Workspaces: config (copied), outreach-core (schema + actions/queries + hard gates), outreach-ai (Gemini client + embeddings copies, profiler and mission-fit-judge agent stubs), outreach-worker (DBOS executor with nightly ingest + hourly expiry workflows), outreach-review (RR7 review queue v0). Initial drizzle migration incl. pgvector extension. Stack contract: Yarn 4.5.0 + Turbo, Node 22.16, Drizzle 0.44.6 + pgvector, DBOS 4.17.6, @google/genai on Vertex, gemini-embedding-001 @1536, React Router v7. Files copied from novelpad-desktop carry provenance headers @ 62c56b87. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
55 lines
3.3 KiB
Markdown
55 lines
3.3 KiB
Markdown
# @novelpad/outreach-core
|
|
|
|
Domain/data package for the HelmDocs grant-match outreach engine: the Drizzle
|
|
schema for grants, orgs, org profiles, contacts, matches, and pipeline
|
|
events, plus the actions/queries that read and write them.
|
|
|
|
Modeled on `packages/core` in [novelpad-desktop](https://gitea.stephenmann.io/NovelPad/novelpad-desktop),
|
|
following the same [action/query pattern](https://gitea.stephenmann.io/NovelPad/novelpad-desktop/src/branch/master/docs/features/database-action-query-pattern.md):
|
|
every read lives in a domain's `queries/`, every write in its `actions/`,
|
|
both barrel-exported, and route handlers/workflows/hooks never touch
|
|
`db.select()`/`db.insert()` directly.
|
|
|
|
## Domains
|
|
|
|
- `grants/` — open grant opportunities (Grants.gov, NH state, 990-PF, PND RSS, Candid). Ingestion upserts on `sourceUrl`; an hourly sweep expires anything past its close date.
|
|
- `orgs/` — NH nonprofits, plus `org_profiles` (LLM/agent-researched enrichment: mission, programs, known funders, budget band, citation sources).
|
|
- `matches/` — a scored `(org, grant)` pair. `hard-gates.ts` is the deterministic, DB-free pass/fail predicate (entity eligibility, geography, ≥21-day runway, ≥$10k ceiling, application-form support) that runs *before* the weighted LLM subscoring pass — see its module doc for why it's kept pure.
|
|
- `pipeline/` — outreach lifecycle events (`enrolled` → `sent` → `opened`/`replied`/... → `demo_booked` → `converted`), synced from Apollo and recorded internally.
|
|
|
|
## Deliberate deviations from `@novelpad/core`
|
|
|
|
This package is **server-only** — there is no client app, so several things
|
|
`@novelpad/core` does for its PGlite/OPFS client don't apply here:
|
|
|
|
- **No PGlite, no client schema, no sync.** There's exactly one database
|
|
handle type (`NpOutreachDatabase`/`NpOutreachTransaction` in `src/db/db.ts`),
|
|
not the client/server pair (`NpClientDatabase` vs `NpDatabase`) `@novelpad/core`
|
|
needs to support both a local and a remote copy of the same data.
|
|
- **No `novelpad_core_dev` export condition.** `@novelpad/core`'s `package.json`
|
|
uses a custom `novelpad_core_dev` condition so dev builds resolve straight
|
|
to `src/*.ts` without a build step. This package's `exports` map only has
|
|
plain `types`/`default` conditions — run `yarn build` (or `yarn dev` for a
|
|
watch build) before consuming it from a sibling workspace in dev.
|
|
- **No `build:migration-files` bundling step.** `@novelpad/core`'s
|
|
`create:migration` also runs a script that bundles generated SQL into a
|
|
TS module the client can import for its OPFS-based local migrator. There
|
|
is no local migrator here, so `bin/create-migration` only runs
|
|
`drizzle-kit generate` against the single server config.
|
|
- **Root `index.ts` is intentionally small.** It exports only the schema,
|
|
DB types, and the pure `hard-gates` predicate — not domain client barrels,
|
|
since every domain here is server-only. Everything else lives behind
|
|
`index.server.ts` / the `./server` export condition.
|
|
|
|
## Scripts
|
|
|
|
```
|
|
yarn build # tsc
|
|
yarn dev # tsc --watch
|
|
yarn typecheck # tsc --noEmit
|
|
yarn test # vitest run
|
|
yarn create:migration <name> # drizzle-kit generate against drizzle.config.ts
|
|
yarn migrate # drizzle-kit migrate
|
|
yarn studio # drizzle-kit studio
|
|
```
|