prospector/docs/PROSPECTOR.md
Natalie bcbd558e9d
Some checks are pending
CI / verify (push) Waiting to run
refactor!: drop Swift/native macOS app, unify on the PWA
Remove all Swift/legacy artifacts — no native app, no swift-react UI, no
tech debt. The Chrome PWA (web/) on the NestJS backend (src/) + MCP server
is the sole way forward.

Removed:
- @packages/prospector-client, @packages/prospector-ui (Swift packages)
- Sources/ (QuinnProspector, QuinnProspectorCore), Config/, project.yml,
  QuinnProspector.xcodeproj, Resources/
- PLAN.md (stale my/-port plan, superseded)

Rewired:
- .forgejo/workflows/ci.yml → Node CI (npm ci → typecheck/test/build for
  backend + web + MCP) instead of Swift build/test
- .gitignore → drop .build/, *.xcodeproj/

Unified definition:
- docs/PROSPECTOR.md — new single source of truth (architecture, surfaces,
  invariants, dependencies, build/deploy)
- README.md, CLAUDE.md, docs/README.md, src/README.md → PWA-forward,
  point at docs/PROSPECTOR.md, no Swift/legacy references

designs/ kept intact as the authoritative UI/behavior spec.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 11:59:04 -04:00

8.3 KiB

Quinn Prospector — Unified Definition

The single source of truth for what this application is. Read this first; everything else (src/README.md, per-module READMEs, designs/) drills down from here.

One repo, one app. Prospector is a self-contained NestJS backend + React PWA + MCP server, with its own Postgres database. There is no Swift app, no native macOS target, and no platform my/ round-trip in the build. The PWA is the way forward.


1. What it is

Prospector is Quinn's AFK auto-send engine + operator console for inbound prospecting and outbound campaigns. It replaces the old Claude Desktop "coworker/executor" with a focused, installable tool:

  • Backend (src/) — a NestJS service (Node 20) that classifies inbound messages, decides whether to auto-send or hold, drafts replies from canon templates, dispatches through the macsync outbox, and exposes everything under /prospector/*. Owns its Postgres database.
  • Operator PWA (web/) — a Vite + React app served same-origin by the backend. Installs as a standalone Chrome/macOS window (PWA manifest + app-shell service worker). This is the operator's daily workhorse.
  • MCP server (@packages/mcp-prospector/) — a thin adapter over the REST surface so agent coworkers can drive the same flows.

The 8 interactive prototypes in designs/ are the authoritative visual + behavior contract. Open them in a browser; the PWA ports and wires them to real data. Treat them as the spec — they win UI/behavior disputes.


2. Architecture (three pieces, one origin)

                 ┌─────────────────────────────────────────────┐
                 │  Operator (Chrome PWA, installed window)     │
                 │  web/  — React, hash-routed, 8 views         │
                 └───────────────┬─────────────────────────────┘
                                 │  same-origin  /prospector/*
                                 ▼
   agents ──MCP──▶  ┌──────────────────────────────────────────┐
 @packages/         │  Backend  src/  (NestJS, Node 20)         │
 mcp-prospector     │  feature-sliced modules → pure logic      │
                    │  serves web/dist via useStaticAssets      │
                    └───┬───────────────┬──────────────┬────────┘
                        │               │              │
                        ▼               ▼              ▼
                  Postgres        on-demand GPU   HTTP services
                  (own DB)        (LLM classify/  people · mac-sync
                                   draft)          mr-number
  • Same-origin in prod: main.ts serves web/dist (useStaticAssets); the API stays under /prospector. web/src/api.ts targets /prospector in prod and the /api Vite proxy in dev. No SPA-fallback route — the app hash-routes.
  • Auth: a service-token guard protects all /prospector + /internal routes (injected by the fronting proxy in prod; the Vite proxy injects PROSPECTOR_SERVICE_TOKEN in dev). health/ is public.

Layering rule (enforced, see docs/STANDARDS.md)

controller (HTTP only) → service (I/O + orchestration) → pure modules (domain logic, no DB, unit-tested). Cross-module access goes through a feature's index.ts / *Module — never a deep internal import. src/markets/ is the reference module.


3. The operator surfaces (PWA views ↔ backend modules)

Eight nav-rail views, each backed by real /prospector/* endpoints:

View What it does Backend module
Triage (home) Life/Dates/Digital segmented roster + search → detail; toolbar (classify/MR/pastebin refresh) prospects/
Detail thread, Mr. Number panel, draft-from-🌹 + send-via-outbox, teach-loop correction prospects/, corrections/
Queue held-for-review backlog → open / release (auto-drafts on release) audit/
Campaigns tag + market + msg-age filter → audience preview → confirmed launch + history campaigns/
Reports auto-qualify funnel, 7d volume, band/market breakdown, backlog reports/
Markets tour-stop selector + per-market peak hours/days, conversion, locality markets/
Pastebin live 🌹 canon templates (from macsync Notes) pastebin/
Control kill-switch (GO/PAUSE/AWAY) · digest · activity feed · held settings/, audit/

Supporting backend modules: inbound/ (macsync webhook → classify → decide), classify/ + engine/ (pure classifier/gate/scam/state/booking/send-guard), runner/ + scheduler/ (AFK decision + heartbeat), auth/, health/, clients/ (people, mr-number, macsync), entities/ + migrations/.

Two distinct "market" notions — never conflate

  1. Campaign-targeting market — a coarse E.164 calling-code bucket (src/prospects/segment.ts, e.g. US/CA, MX). Used by Campaigns + Reports.
  2. Tour-stop market — a metro Quinn physically works for a date window, with a timezone (src/markets/registry.ts, currently NYC). Drives Markets stats.

4. Invariants (the safety floor)

  • Every send — manual, AFK runner, or campaign — goes through the macsync outbox, keeps the human_owned hard floor, and writes one shared prospect_drafts audit row.
  • Campaigns never blast Life-band contacts unless life is explicitly selected.
  • The kill-switch (settings/) gates all auto-send. AWAY/PAUSE halts the runner.

5. Dependencies

Internal (npm workspaces): @prospector/app (backend, src/) · @prospector/web (PWA) · @prospector/mcp-prospector (MCP).

Backend stack: NestJS 11 (common/core/platform-express, config, schedule, swagger, typeorm), TypeORM + pg (Postgres), class-validator, class-transformer, rxjs, reflect-metadata. Tests: Vitest.

Web stack: React 18 + Vite 5. MCP stack: @modelcontextprotocol/sdk + zod.

External services (HTTP, declared in .infra.yaml): people (signals) · mac-sync (Notes pastebin, outbox, messages, calendar — the only mesh-dependent path) · mr-number (number reputation). Plus shared managed Postgres (lilith-store-pg, own logical DB/role) and an on-demand GPU droplet for LLM classify/draft.


6. Build, run, deploy

# Dev
cd web && npm run dev          # PWA on Vite, proxies /api → backend
npm run start:dev              # backend (watch)

# Verify
npm test                       # backend (Vitest)
npm run typecheck && npm run build
npm run build --workspace web  # → web/dist/

# Local app window
./run                          # launches the local stack
./run tray                     # macOS menu-bar launcher (AppleScript, no Swift)
  • Prod is a single NestJS process serving web/dist same-origin behind the auth-injecting proxy on the DO droplet (.infra.yaml: host lime, port 3210, systemd unit prospector). Override the dist path with PROSPECTOR_WEB_DIST.
  • CI (.forgejo/workflows/ci.yml) runs on ct-forge Linux runners: npm ci → typecheck → test → build backend → build web → build MCP.
  • Mesh dependency is limited to mac-sync (Apple integrations over the WG mesh). Core prospector (stats, classify, drafts, sends, reports, queue) is pure DO + Postgres.

Future goal (not the current host): a platform my/ SSO surface mirroring this PWA for unified quinn.my deploy. Build against web/ here; the my/ port is a later integration, not a dependency.


7. Where to look

  • src/README.md — backend module index (routes, consumers, ground truth).
  • per-module README.md — what/why + file table + HTTP surface.
  • docs/STANDARDS.md — house rules (feature-sliced modules, pure/IO split, reuse, co-located Vitest, 300/500 LOC caps).
  • docs/features/deploy.md, draft-engine.md, mcp.md.
  • docs/MIGRATION_FROM_LP.md — context for the move off lilith-platform.
  • designs/*.html — the visual + behavior spec (open in a browser).