PRD
PRD
Last updated 5/3/2026
DataZoom — Progressive Product Requirements Document
PRD Metadata
| Field | Value |
|---|---|
| Product Name | DataZoom |
| Repository | midwestco/datazoom |
| PRD Version | v1.0 Growth |
| Status | Production |
| Document Owner | Product Strategy |
| Last Updated | 2026 |
| Primary Stack | Next.js 15, React 19, TypeScript, Supabase (PostgreSQL + pgvector), Python 3.10+, Clerk |
| AI Runtime | Modal (Qwen2.5:32B), sentence-transformers (all-MiniLM-L6-v2, 384-dim), Ollama (local fallback) |
| Deployment Targets | Fly.io (orchestrator), RunPod (GPU workers), Cloudflare (edge), Docker Compose (self-hosted) |
| Auth Provider | Clerk (multi-tenant, organization-scoped) |
| Analytics | Mixpanel |
| Error Tracking | Sentry |
v0.1 Spark — Problem & Outcomes
Problem Statement
Legal and business documents are dense, voluminous, and structurally inconsistent. During due diligence, fundraising, M&A review, or regulatory compliance, professionals must read hundreds of pages of contracts, equity agreements, IP assignments, and financial disclosures to extract specific facts, identify risks, and map relationships between parties. This process is slow (days to weeks), expensive (senior attorney time), and error-prone (key clauses missed under time pressure).
Existing document management tools (Google Drive, Dropbox, SharePoint) provide storage and search but offer no semantic understanding. Generic AI chatbots (ChatGPT, Claude) can summarize single documents but cannot reason across a corpus of 50–200 interrelated files, maintain source citations, manage organizational data isolation, or reconstruct equity ownership chains from fragmented transaction records.
DataZoom solves this by combining vector-based semantic search over chunked document corpora with a retrieval-augmented generation (RAG) pipeline and a structured data extraction layer. Users upload documents, and DataZoom extracts entities, dates, parties, and terms; embeds content into a pgvector-backed similarity index; and exposes a conversational interface where every answer cites the exact source chunk. Specialized modules for cap table reconstruction, due diligence checklist automation, timeline visualization, and strategic advisory extend the core RAG layer into domain-specific workflows.
Desired Outcomes
| Outcome ID | Outcome | Measurement |
|---|---|---|
| OUT-001 | Reduce time-to-answer for document queries from hours to seconds | P95 query latency < 8 seconds end-to-end |
| OUT-002 | Enable non-legal users to extract actionable facts from legal documents | Session depth > 5 questions per conversation |
| OUT-003 | Reconstruct equity ownership history from uploaded agreements automatically | Cap table extraction accuracy ≥ 90% against human-verified fixtures |
| OUT-004 | Provide auditable, cited answers with source tracebacks | 100% of AI responses include chunk-level citations |
| OUT-005 | Support multi-organization data isolation with zero cross-tenant leakage | RLS policy coverage 100%; zero cross-org data incidents |
| OUT-006 | Enable on-premises deployment for air-gapped or regulated environments | Local Ollama mode functional with no external API calls |
Constraints
- BR-001 Data Residency: All document processing must be executable locally (Ollama path) to satisfy customers with data residency requirements.
- BR-002 Citation Integrity: Every RAG response must surface source document and chunk-level references. No uncited assertions permitted.
- BR-003 Org Isolation: PostgreSQL Row-Level Security (RLS) enforces organization-based data isolation. Clerk organization ID is the primary tenant discriminator.
- BR-004 Vector Dimension Lock: Embeddings are fixed at 384 dimensions (all-MiniLM-L6-v2). Schema changes to
document_chunks.embedding VECTOR(384)require a full re-embedding migration. - BR-005 Cap Table Review Gate: AI-extracted cap table transactions require human approval via the review queue (
/api/cap-table/review) before they are committed to the ledger. Automatic approval is prohibited. - BR-006 LLM Routing: The model router (
product/lib/__tests__/model-router.test.ts) determines whether queries are dispatched to Modal (Qwen2.5:32B cloud) or local Ollama. Routing logic must be deterministic and testable.
v0.2 Market Definition — ICP & Segments
Ideal Customer Profile
The primary buyer is a deal-side professional at a firm that regularly conducts document-intensive review cycles — either as a buyer (acquiring company, investor) or as a subject (startup raising capital, company undergoing legal audit). They have access to 10–500 documents per deal, a legal or finance team that currently reviews them manually, and a mandate to move faster without adding headcount.
Segments Table
| Segment ID | Segment Name | Description | Document Types | Key Pain | Size Signal |
|---|---|---|---|---|---|
| SEG-001 | Early-Stage Startup (Fundraising) | Founders preparing data rooms for seed/Series A investors; need to organize equity agreements, IP assignments, and financials for due diligence | Equity agreements, IP assignments, SAFEs, cap table documents | Disorganized history, founders can't answer investor questions fast | High volume; 500K+ startups raise annually in the US |
| SEG-002 | Private Equity / VC Due Diligence | Deal teams reviewing target company data rooms; need to extract risk flags, key terms, and party relationships across 50–200 documents under time pressure | NDAs, SPA, financial statements, employment agreements, IP schedules | Manual review bottleneck; missed clauses create deal risk | ~4,000 PE firms globally; $1T+ deal flow annually |
| SEG-003 | Corporate M&A / Legal Teams | In-house M&A counsel and corporate development teams conducting buy-side diligence; need clause comparison, timeline reconstruction, and structured findings | Acquisition agreements, reps & warranties, employment contracts, regulatory filings | Expensive outside counsel; slow synthesis across large corpora | Mid-to-large enterprise; ~$3.5T M&A deal value annually |
| SEG-004 | Law Firms (Deal Support) | Associates and paralegals supporting transactional matters; use DataZoom to accelerate document review, generate first-draft memos, and answer client questions | Any transactional document type | Billable hour pressure; clients demand faster turnaround | ~450,000 lawyers in US transactional practice |
| SEG-005 | Healthcare / Regulated Industries | Compliance officers reviewing contracts, licensing agreements, and regulatory documents in air-gapped or data-residency-constrained environments | Healthcare agreements, licensing, regulatory filings | Cannot use cloud AI; need on-premise processing via Ollama path | Specialized; high willingness-to-pay |
"Not For"
- Consumer users seeking personal document help (lease review, personal tax prep). DataZoom's multi-tenant architecture, Clerk org management, and professional workflow depth are excessive and confusing for single-user consumer needs.
- Pure litigation / discovery workflows requiring Bates-numbering, privilege logging, or EDRM chain-of-custody. DataZoom processes transactional documents, not litigation production sets.
- Real-time collaboration document editors (Google Docs competitors). While a
collaboration-wsWebSocket service exists (product/collaboration-ws/Dockerfile), the core product is a read/query/analyze system, not a collaborative authoring tool. - Generic knowledge base / wiki search use cases where documents are not legal or business agreements. The domain-specific extractors (cap table, timeline, due diligence checklist) provide no value outside transactional document contexts.
v0.3 Commercial Model — Pricing & Positioning
Positioning Statement
DataZoom is the AI-native deal room for teams that need to understand their documents, not just store them. Where traditional virtual data rooms (Intralinks, Ansarada, Firmex) provide secure file hosting with basic search, DataZoom provides semantic understanding: ask any question about your deal in plain English and receive a cited answer in seconds. Where generic AI tools require copy-pasting documents and cannot reason across a corpus, DataZoom maintains a persistent, org-isolated vector index that grows with every upload.
Monetization Model
| Tier | Target Segment | Pricing Model | Key Limits | Notes |
|---|---|---|---|---|
| Starter | SEG-001 (Founders) | Per-seat SaaS, monthly | 500 documents, 1 org, Modal cloud LLM only | Self-serve onboarding; data room for a single raise |
| Professional | SEG-002, SEG-004 | Per-seat SaaS, annual | 5,000 documents, unlimited orgs/folders, full advisor module | Cap table module, due diligence checklists, timeline visualization |
| Enterprise | SEG-003, SEG-005 | Custom contract, annual | Unlimited documents, self-hosted Ollama path, SSO, audit logs | Air-gapped deployment via Docker Compose (docker-compose.yml); dedicated GPU workers via RunPod |
| API / Embedded | Technology partners, law firm platforms | Usage-based (per query/embedding) | Rate-limited; requires Clerk org provisioning | Exposes /api/advisor, /api/analysis, /api/cap-table programmatically |
Billing Infrastructure
The repository includes a dedicated billing and wallet subsystem (docs/billing_wallet/BILLING_WALLET_IMPLEMENTATION_MASTER.md, docs/billing_wallet/WALLET_ACTION_PLAN.md). This suggests a credit/wallet model for AI query consumption layered atop the subscription tiers — specifically, Modal cloud LLM calls are metered and deducted from a wallet balance, as evidenced by the 06_wallet_deduction.md action plan in the Modal migration optimization series.
Moat Thesis
- Corpus Statefulness: DataZoom's pgvector index persists and grows across sessions. Each uploaded document increases the semantic retrieval surface. A competitor starting fresh from a document dump cannot match the indexed, relationship-mapped state built over months of use.
- Domain-Specific Extractors: Cap table reconstruction (
/api/cap-table/extract,/api/cap-table/auto-populate), due diligence checklist generation (/api/business-types/[typeKey]/checklist), and party-level analysis (/api/analysis/party) are not achievable with a generic LLM wrapper. Each extractor encodes domain logic validated against real document fixtures (product/lib/cap-table/__tests__/fixture-corpus.ts). - Hybrid Deployment: The ability to run the full stack locally (Ollama + Supabase self-hosted) addresses a blocker that eliminates cloud-only competitors from regulated market segments.
- Citation Enforcement: The
citation-system.test.tstest file andBR-002constraint indicate citation integrity is a hard architectural requirement. Hallucination-prone competitors cannot meet the evidentiary standard required in legal and financial contexts.
v0.4 User Journeys
UJ-001 — Document Upload and Indexing
Actor: Legal analyst at a PE firm
Entry point: product/app/(app)/documents/page.tsx → Documents view
Steps:
- User navigates to the Documents section and selects a folder or creates a new one (
product/app/(app)/documents/folder/[id]/page.tsx). - User uploads one or more PDFs or documents via the upload interface (PR #101: Upload fixes indicates active work on this flow).
- The document is stored in Supabase Storage; metadata is written to the
documentstable (filename,document_type,parties,key_terms,page_count). - The async ingest worker (
docker/Dockerfile.worker, BullMQ queue via Redis/Upstash) processes the document: extracts full text, generates an LLM summary via Modal or Ollama, and splits the text into chunks. - sentence-transformers (all-MiniLM-L6-v2) generates 384-dimensional embeddings for each chunk; chunks are written to
document_chunkswith their embedding vectors. - The
ivfflatcosine index ondocument_chunks.embeddingis updated, making the document immediately queryable. - User sees the document appear in the Documents list with extracted
document_type,effective_date, andpartiesmetadata rendered inproduct/app/(app)/[type]/[id]/views/document-view.tsx.
Success metric: Document available for semantic query within 60 seconds of upload for documents ≤ 50 pages.
UJ-002 — Natural Language Document Query (RAG Chat)
Actor: Founder preparing for investor Q&A
Entry point: product/app/(app)/context/page.tsx → Context / Chat interface
Steps:
- User opens the Context page and selects or creates a conversation thread via
product/app/(app)/context/components/thread-selector.tsx. - User types a natural language question (e.g., "Who are the parties to the IP assignment signed in February 2025, and what rights were transferred?").
- The query is embedded using the same all-MiniLM-L6-v2 model; a vector cosine similarity search against
document_chunksretrieves the top-k most relevant chunks. - Retrieved chunks are assembled into a prompt context and dispatched to the model router, which selects Modal (Qwen2.5:32B) or local Ollama based on routing rules (
product/lib/__tests__/model-router.test.ts). - The LLM generates a response grounded in the retrieved chunks; the citation system (
product/lib/__tests__/citation-system.test.ts) attaches source references to each factual claim. - The response is streamed to
product/app/(app)/context/components/conversation-panel.tsxwith inline citations linking back to the source document and chunk. - Suggested follow-up questions are surfaced via
product/app/(app)/context/components/suggested-followups.tsx. - The user can save a decision or finding to the decision log (
product/app/(app)/context/components/decision-log.tsx,product/app/(app)/context/components/save-decision-form.tsx). - AI interaction is tracked via
/api/ai/track-interactionand sent to Mixpanel.
Success metric: P95 response latency < 8 seconds; citation present on 100% of factual responses.
UJ-003 — Cap Table Extraction and Review
Actor: M&A associate reconstructing target company equity history
Entry point: product/app/(app)/cap-table/page.tsx
Steps:
- Associate navigates to Cap Table and triggers extraction against already-uploaded equity documents via
/api/cap-table/extract. - The extraction pipeline (Modal endpoint, triggered via
/api/cap-table/auto-populate) parses equity agreements, SAFEs, and stock purchase agreements to identify transactions: issuances, transfers, conversions, option grants. - Extracted transaction candidates are written to a review queue; associate sees them in the review interface surfaced via
/api/cap-table/review. - Associate reviews each candidate transaction: approves via
/api/cap-table/review/[id]/approveor rejects via/api/cap-table/review/[id]/reject. Bulk review is also supported. - Approved transactions are committed to the cap table ledger. The calculation engine (
product/lib/cap-table/__tests__/calc.test.ts) computes ownership percentages and dilution. - Associate queries the cap table as of any historical date via
/api/cap-table/as-ofto reconstruct point-in-time ownership. - Current state is available via
/api/cap-table/current. Transactions can be voided via/api/cap-table/transactions/[id]/void. - Cap table health checks run via
/api/cap-table/healthto surface reconciliation mismatches. - The associate views the rendered cap table in
product/app/(app)/cap-table/page.tsxwith ownership percentages, transaction history, and parties.
Success metric: Extraction accuracy ≥ 90% against human-verified corpus (product/lib/cap-table/__tests__/fixture-corpus.test.ts).
UJ-004 — Due Diligence Checklist Generation
Actor: VC analyst conducting Series B diligence
Entry point: product/app/(app)/analysis/page.tsx → Analysis module
Steps:
- Analyst selects a business type profile (e.g., SaaS, healthcare, fintech) via
/api/business-typesand retrieves the associated checklist via/api/business-types/[typeKey]/checklist. - DataZoom generates a due diligence checklist tailored to the business type, drawing from the document catalog (
docs/action_plans/business_type_fix/REFERENCE_DOCUMENT_CATALOG.md). - The system matches checklist items against the documents already uploaded to the org, surfacing coverage gaps (documents present vs. documents expected).
- The DD match panel (
product/app/(app)/[type]/[id]/views/dd-match-panel.tsx) shows which checklist items are satisfied by which documents. - Analyst requests regeneration of specific analysis sections via
/api/analysis/regenerateor party-level analysis via/api/analysis/party. - Strategic options are generated by the Advisor module (
/api/advisor/strategic-options), synthesizing findings across the corpus into a structured memo. - A risk memo is produced via
/api/advisor/risk-memo, compiled from findings logged during review. - The analyst exports activity data via
/api/activity/exportfor client reporting.
Success metric: Checklist coverage computation completes within 10 seconds for corpora up to 200 documents.
UJ-005 — Timeline Visualization
Actor: Legal counsel reconstructing chronology for a dispute or deal closing
Entry point: product/app/(app)/analysis/overview/page.tsx or analysis strategy view
Steps:
- Counsel uploads all relevant agreements; the ingest pipeline extracts
timeline_eventsrecords from each document, populatingevent_date,event_type(e.g.,equity_change,agreement_signed,ip_assignment),description,parties_involved, andimpactlevel. - The Timeline view renders events chronologically, filterable by
event_typeandimpactseverity. - Counsel clicks an event to navigate to the source document chunk, viewing the exact text that triggered the event extraction.
- Cross-document event correlations (e.g., an IP assignment and a subsequent equity grant to the same party) are surfaced.
- The full timeline is exportable via the activity export API (
/api/activity/export).
Success metric: Timeline events extracted for ≥ 95% of documents containing dates and described events.
UJ-006 — Admin Pipeline Monitoring
Actor: Platform administrator or DevOps engineer
Entry point: product/app/(app)/admin/pipeline/page.tsx
Steps:
- Admin navigates to the Pipeline admin page to monitor the document processing queue.
- Pipeline health is checked via
/api/admin/pipeline/health; cloud worker status (RunPod fleet, pod warmup state:provisioning → warming → ready) is retrieved from/api/admin/pipeline/cloud. - Admin views routing statistics (Modal vs. Ollama dispatch ratios, queue depths) via
/api/admin/routing-stats. - Failed jobs are retried via
/api/admin/pipeline/retry. - Observability metrics (embedding throughput, LLM call latency, queue backlog) are visible in the pipeline view.
v0.5 Red Team Review — Risk Register
| Risk ID | Category | Risk Description | Likelihood | Impact | Mitigation |
|---|---|---|---|---|---|
| RISK-001 | AI Quality | RAG retrieval returns irrelevant chunks, producing hallucinated or misleading answers about legal terms | Medium | Critical | rag-retrieval-enhanced.test.ts and rag-retrieval.test.ts cover retrieval quality; citation enforcement (BR-002) ensures every claim is traceable; users can inspect source chunks |
| RISK-002 | Data Security | Cross-tenant data leakage via mis-scoped database query (missing RLS filter) | Low | Critical | PostgreSQL RLS enforced at database level; Clerk org ID is the tenant discriminator; company-settings/linkage-mismatches API monitors for linkage anomalies; penetration testing required pre-enterprise launch |
| RISK-003 | Cap Table Accuracy | AI misreads ambiguous equity clause, commits incorrect ownership data to ledger | Medium | High | Human review gate (BR-005) mandated before any transaction is committed; fixture-corpus tests (fixture-corpus.test.ts) validate extraction against real documents; void capability (/api/cap-table/transactions/[id]/void) provides rollback |
| RISK-004 | LLM Vendor Dependency | Modal (Qwen2.5:32B) outage or pricing change disrupts cloud AI path | Medium | High | Ollama local fallback fully implemented; model router (model-router.test.ts) supports switching; multi-GPU worker support via RunPod provides secondary cloud path |
| RISK-005 | Embedding Model Lock-in | Switching from all-MiniLM-L6-v2 (384-dim) to a higher-quality model requires re-embedding entire corpus | Low | Medium | Vector dimension is schema-locked (BR-004); migration path documented in docs/archive/completed_action_plans/document_refinement_v1/05_rag_retrieval_layer_COMPLETE.md; re-embedding tooling exists |
| RISK-006 | Upload Pipeline Reliability | Document upload failures leave corpus incomplete without user awareness (PR #101: Upload fixes is open) | High | High | BullMQ retry logic with Redis/Upstash; fix: critical TLS + race condition fixes from full pipeline audit (commit 6c89d22) addresses known failures; upload status surface via activity tracking |
| RISK-007 | RunPod/Fly.io Infrastructure | GPU pod warmup latency (provisioning → warming → ready) creates multi-minute cold starts for first queries in a session | Medium | Medium | Pod warmup status tracking implemented (commit 580b80b); warmup status surfaced in admin pipeline UI; pre-warming strategy for predictable usage patterns |
| RISK-008 | Regulatory / Legal Liability | Users act on AI-generated legal analysis (risk memos, clause comparisons) without professional review, creating liability | Medium | High | Risk memos (/api/advisor/risk-memo) and advisor outputs must include explicit "not legal advice" disclosures; product positioned as analyst tool, not legal counsel replacement |
| RISK-009 | BullMQ / Redis TLS | Upstash TLS configuration failures break the async ingest queue (commit b718932: fix BullMQ workers use redis.asyncio with ssl_cert_reqs=None) | Low | High | Fix committed; fix: BullMQ workers use redis.asyncio with ssl_cert_reqs=None for Upstash TLS addresses root cause; health check endpoint /api/admin/pipeline/health monitors queue liveness |
| RISK-010 | Feature Scope Creep | E-signature module (docs/action_plans/e_sign/), collaboration WebSocket (product/collaboration-ws/Dockerfile), and billing wallet expanding scope beyond core RAG value prop | Medium | Medium | Feature gates (product/lib/cap-table/__tests__/feature-gate.test.ts pattern) applied to non-core modules; staged rollout per docs/cap-table/action_plans/12_rollout_feature_flag_and_rollback.md |
| RISK-011 | Knip Dead Code | Unused exports and dead code accumulate in a 500-file codebase, increasing bundle size and maintenance burden | Low | Low | .github/workflows/knip.yml runs automated dead code detection in CI; pre-commit hooks enforced via .husky/pre-commit |
v0.6 Architecture
TECH-001 — Frontend Application
Path: product/ (Next.js 15 App Router)
Runtime: React 19, TypeScript, Tailwind CSS, shadcn/ui (Radix UI primitives, e.g., @radix-ui/react-context-menu)
Theming: next-themes (dark/light mode)
Routing: App Router with dynamic segments product/app/(app)/[type]/[id]/page.tsx for polymorphic entity rendering (documents, companies, findings, options)
State Management: React Context providers scoped per feature (product/app/(app)/analysis/analysis-provider.tsx, product/app/(app)/documents/documents-provider.tsx, product/app/(app)/activity/activity-provider.tsx)
Deployment: Vercel (.vercelignore present) with Cloudflare edge (PR #111: Cloudflare deployment)
TECH-002 — Backend API Layer
Path: product/app/api/ (50 Next.js API Route handlers)
Auth: Clerk (/api/clerk/proxy/route.ts); organization-scoped via withOrgAuth middleware
Database Client: @supabase/supabase-js ^2.95.3 (SUPABASE_URL, SUPABASE_SERVICE_KEY from .env.services)
Key API Groups:
- Activity:
activity/,activity/unified/(calendar, day, feed, refresh) - Admin:
admin/pipeline/(cloud, health, retry),admin/routing-stats/ - Advisor:
advisor/(batch, process-queue, risk-memo, strategic-options) - Cap Table:
cap-table/(as-of, auto-populate, current, extract, health, review, transactions) - Analysis:
analysis/(party, regenerate) - Business Types:
business-types/,business-type-profiles/ - Clauses:
clauses/compare/ - Collaboration:
collaboration/token/ - Company Settings:
company-settings/,company-settings/linkage-mismatches/
TECH-003 — Database Layer
Engine: PostgreSQL via Supabase
Extension: pgvector for 384-dimensional vector storage and cosine similarity search
Key Tables:
| Table | Purpose |
|---|---|
documents | Document metadata: filename, document_type, parties TEXT[], key_terms TEXT[], effective_date, full_text, summary |
document_chunks | Chunked text with embedding VECTOR(384), metadata JSONB, FK to documents |
timeline_events | Extracted events: event_date, event_type, parties_involved TEXT[], impact |
conversations | Chat session metadata, org-scoped |
messages | Individual chat turns linked to conversations |
cap_table_transactions | Equity transactions with approval state |
due_diligence_checklists | Checklist items linked to business type profiles |
knowledge_graph | Entity and relationship records extracted from documents |
activity_log | Audit trail for all user actions (uploads, deletes, analyses) |
Indexes:
ivfflatondocument_chunks.embeddingwithvector_cosine_ops(lists=100) for ANN searchGINondocuments.partiesfor array containment queries- B-tree on
documents.document_type,documents.effective_date - B-tree on
timeline_events.event_date,timeline_events.event_type - B-tree on
document_chunks.document_id
RLS: Row-Level Security policies enforce org-level isolation using Clerk organization ID as the discriminant.
TECH-004 — AI / ML Pipeline
Embedding Service: sentence-transformers all-MiniLM-L6-v2 (384-dim); runs in the GPU Docker image (docker/Dockerfile.gpu)
LLM (Cloud): Modal deployment of Qwen2.5:32B; dispatched from Next.js API routes via the model router
LLM (Local): Ollama (ollama/ollama:latest), exposed on port 11434; OLLAMA_NUM_PARALLEL=4, OLLAMA_MAX_LOADED_MODELS=3
LLM Proxy: llm service in docker-compose.yml, image ghcr.io/midwestco/datazoom-base:latest, port 8001, proxies to http://ollama:11434
Model Router: Deterministic routing logic tested in product/lib/__tests__/model-router.test.ts; selects Modal vs. Ollama based on query type, org configuration, and availability
Ingest Worker: Python 3.10+ worker (docker/Dockerfile.worker, ghcr.io/midwestco/datazoom-worker:latest); processes BullMQ jobs from Redis/Upstash; performs text extraction, chunking, embedding generation, and database writes
Cloud Worker: docker/cloud-worker/Dockerfile; deployed to Fly.io (docker/cloud-worker/fly.toml); handles cloud-path document processing
TECH-005 — Queue Infrastructure
Queue: BullMQ backed by Redis (Upstash in production, with TLS via ssl_cert_reqs=None fix in commit b718932)
Job Types: Document ingest, re-embedding, batch advisor processing (/api/advisor/batch, /api/advisor/process-queue), cap table extraction
Retry: Failed jobs retried via /api/admin/pipeline/retry; pipeline health monitored via /api/admin/pipeline/health
TECH-006 — Infrastructure and Deployment
Container Registry: ghcr.io/midwestco/ (GitHub Container Registry)
CI/CD: .github/workflows/build-images.yml builds and pushes datazoom-base, datazoom-worker, datazoom-gpu images
Orchestrator: Fly.io (fly/orchestrator/Dockerfile); manages RunPod GPU fleet for cloud inference
GPU Workers: RunPod (pod warmup states: provisioning → warming → ready); status exposed via /api/admin/pipeline/cloud
Collaboration Service: Standalone WebSocket server (product/collaboration-ws/Dockerfile) for real-time co-editing
Networking: WireGuard VPN option for private network connectivity (docker/wireguard/wg0.conf.example)
Docker Compose Profiles:
full: All services including Ollama, LLM proxy, workergpu: Embed + reranker + Ollamaworker: Ingest worker onlyinfra: Monitoring (future)
API-001 — RAG Query API
Route: Inferred from context module; query dispatched through /api/advisor or context page
Method: POST
Input: { query: string, conversationId: string, orgId: string }
Processing: Embed query → cosine similarity search on document_chunks → retrieve top-k chunks → assemble prompt → dispatch to model router → stream response with citations
Output: { answer: string, citations: [{ documentId, chunkId, chunkContent, filename }] }
API-002 — Cap Table Extract API
Route: /api/cap-table/extract
Method: POST
Input: { documentIds: string[] }
Processing: Dispatch extraction job to Modal endpoint; parse equity transaction details from document full text; write candidates to review queue
Output: { jobId: string, candidateCount: number }
Test Coverage: product/lib/__tests__/cap-table-extract-trigger.test.ts
API-003 — Activity Unified Feed API
Route: /api/activity/unified/feed
Method: GET
Input: { orgId, from, to } (query params)
Output: Paginated activity events from activity_log materialized view; supports calendar view (/api/activity/unified/calendar) and day drill-down (/api/activity/unified/day)
DBT-001 — Activity Materialized Views
Location: docs/activity_page/action_plans/02_create_materialized_views_COMPLETE.md
Purpose: Pre-aggregate activity log records by day and event type to power the Activity calendar and metrics APIs (/api/activity/metrics) without full-table scans on activity_log
Refresh: Triggered via /api/activity/unified/refresh (incremental refresh on new activity inserts)
DBT-002 — Cap Table Snapshot Read Model
Location: docs/cap-table/action_plans/14_snapshot_read_model_optimization.md
Purpose: Maintain point-in-time cap table snapshots to