Phase 3 — API and Progressive Investigation Surface
Goal
Expose the durable resource through an authenticated API and a navigable UI where plan, activity, candidate rows and evidence reconstruct exactly after refresh.API
Create a standard NestJS feature module with controller-only HTTP and service orchestration:POST /workspaces/:slug/investigationsPOST /workspaces/:slug/investigations/:id/answersPOST /workspaces/:slug/investigations/:id/startPOST /workspaces/:slug/investigations/:id/stopGET /workspaces/:slug/investigationsGET /workspaces/:slug/investigations/:idGET /workspaces/:slug/investigations/:id/events?since=GET /workspaces/:slug/investigations/:id/candidates?cursor=&limit=GET /workspaces/:slug/investigations/:id/export?format=csv|json
WorkspaceGuard; mutations require a human identity and the existing
assistant entitlement. Cross-workspace ids return 404.
Creation formulates at most three questions from a closed catalog:
- geography;
- evidence threshold;
- priority rule.
Progress transport
Use persisted replay plus the existing workspace event stream as a notification bell:- worker writes
investigation_eventsand candidates; EventsServiceannounces that the investigation changed;- client fetches events after its last sequence and revalidates the visible candidate page.
ChatStreamHub; it is
in-memory and belongs to ordinary Chat.
UI
Add an explicit Investigation route and navigation entry. Desktop uses:- left: objective, clarifications, plan, curated activity, stop/resume controls;
- right: progressive
DataTable, counts, filters and evidence drawer.
DataTablefor rows;RecordDrawerinteraction conventions for evidence;- Assistant UI styling/primitives only where they improve the conversation/control pane;
- the existing auth-aware fetch/SWR and workspace event reconnection paths.
label_key dictionary in English and Spanish, for example:
discover.searching->Buscando expansiones recientesdiscover.sources->{n} fuentes encontradasresolve.deduped->{n} empresas únicas después de eliminar duplicadosverify.candidates->Verificando {n} candidatosverify.qualified->{n} empresas cumplen los criterios
Export
- JSON is the canonical row projection.
- CSV includes UTF-8 BOM for Excel, stable columns, escaped commas/quotes/newlines and one row per unique candidate.
- Export uses persisted candidates; it never asks the model to regenerate rows.
Acceptance
- The table exists at
runningwith zero rows and grows without page reload. - Refresh during a run reconstructs plan, activity, selection and rows from the server.
- A deploy/reconnect does not duplicate activity or candidates.
- Stop produces
cancelledand leaves rows/export available. - Evidence drawer resolves only platform-minted evidence ids.
- No UI string exposes tools, providers, raw queries, table names or internal budgets.
- Rail and all non-Investigation routes remain visually unchanged.
