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>
54 lines
2.2 KiB
Markdown
54 lines
2.2 KiB
Markdown
# @novelpad/outreach-review
|
|
|
|
Human review queue for (org, grant) matches produced by the scoring pipeline in `packages/outreach-core`. A reviewer sees each pending match — organization, hero grant, total score, easy-win flag — and approves or rejects it. Approved matches are picked up downstream and synced into Apollo sequences.
|
|
|
|
## Auth
|
|
|
|
**There is no authentication in this app, by design.** It is a tiny internal tool intended to run behind:
|
|
|
|
- Google IAP (Identity-Aware Proxy) in any hosted environment, or
|
|
- `localhost` only, for local development
|
|
|
|
Do **not** add `better-auth` (or any other auth library) to this workspace. If this app ever needs to leave an IAP-fronted network, that's a deliberate follow-up decision, not something to bolt on ad hoc here.
|
|
|
|
## Development
|
|
|
|
```
|
|
yarn dev # react-router dev
|
|
yarn build # react-router build
|
|
yarn start # serve the production build
|
|
yarn typecheck # react-router typegen && tsc --noEmit
|
|
```
|
|
|
|
Requires `DATABASE_URL` pointing at the outreach Postgres instance (see `packages/outreach-core`). Optional: `PG_POOL_MAX`, `PG_CONNECTION_TIMEOUT_MS`.
|
|
|
|
## Data contract
|
|
|
|
This app is a thin consumer of `@novelpad/outreach-core`. It assumes the following exports (server-side query/action functions live under the `./server` subpath, matching the `packages/core` convention in novelpad-desktop):
|
|
|
|
```ts
|
|
// @novelpad/outreach-core
|
|
export const schema: /* drizzle schema */;
|
|
export type NpOutreachDatabase = /* PgDatabase<..., typeof schema> */;
|
|
export interface PendingReviewMatch {
|
|
id: string;
|
|
orgName: string;
|
|
heroGrantTitle: string;
|
|
totalScore: number;
|
|
isEasyWin: boolean;
|
|
}
|
|
export type MatchReviewDecision = 'approved' | 'rejected';
|
|
|
|
// @novelpad/outreach-core/server
|
|
export function serverListPendingReviewMatches(
|
|
db: NpOutreachDatabase,
|
|
): Promise<PendingReviewMatch[]>;
|
|
export function serverSetMatchReview(
|
|
db: NpOutreachDatabase,
|
|
matchId: string,
|
|
decision: MatchReviewDecision,
|
|
): Promise<void>;
|
|
```
|
|
|
|
If `packages/outreach-core`'s matches domain (`src/matches/queries`, `src/matches/actions`) lands with different names or a different `PendingReviewMatch` shape, update `app/db.server.ts` and `app/routes/_index.tsx` to match rather than reshaping data client-side.
|