Technical Architecture

Architecture & Principles

Monorepo structure, shared services, and the design decisions that let seven products share infrastructure without coupling.

Design Principles

Single ownership, shared reads

Each entity is written by one product but can be read by many. Project is owned by Blueprint but read by Relay, Retro, and Proof. This prevents write conflicts and makes the ownership model clear.

Nullable foreign keys as bridges

Cross-product references are always nullable. A Project can exist without a Decision (no Compass). A Document can exist without a Project. Each product works standalone.

{ }

JSONB for evolving schemas

Fields like scores, phase_adjustments, and preferences use JSONB. Each product can extend the shape without migrations. The shared layer stays stable while product-specific data evolves.

Conversation as universal intake

Every product uses the same Conversation entity with a different schema_target. One codebase fills any entity through guided AI interaction.

Retro → EstimationModel feedback loop

PhasePerformance data from completed projects feeds into EstimationModel coefficients. Over time, Blueprint's estimates self-correct using real project data.

Document as universal output

SOWs, proposals, case studies, and decision briefs are all the same entity with a type enum. One doc-gen pipeline, many templates.

Repository Structure

/monorepo root (Turborepo + pnpm)
/shared
/intake-engineConversational schema-filling logic
/llm-clientClaude API wrapper, tool orchestration
/doc-genTemplate rendering to PDF/DOCX
/ui-primitivesShared React components
/authUser/org/billing
/dbPrisma schema, migrations, seed data
/products
/scout(Scout)
/domainScout-specific models & logic
/toolsFunction calling definitions for Claude API
/templatesDocument templates
/appNext.js frontend
/compass(Compass)
/domainCompass-specific models & logic
/toolsFunction calling definitions for Claude API
/templatesDocument templates
/appNext.js frontend
/blueprint(Blueprint)
/domainBlueprint-specific models & logic
/toolsFunction calling definitions for Claude API
/templatesDocument templates
/appNext.js frontend
/bench(Bench)
/domainBench-specific models & logic
/toolsFunction calling definitions for Claude API
/templatesDocument templates
/appNext.js frontend
/relay(Relay)
/domainRelay-specific models & logic
/toolsFunction calling definitions for Claude API
/templatesDocument templates
/appNext.js frontend
/retro(Retro)
/domainRetro-specific models & logic
/toolsFunction calling definitions for Claude API
/templatesDocument templates
/appNext.js frontend
/proof(Proof)
/domainProof-specific models & logic
/toolsFunction calling definitions for Claude API
/templatesDocument templates
/appNext.js frontend

Technology Decisions

Monorepo Tool

Turborepo + pnpmNxLerna

Simpler config than Nx with sufficient caching. pnpm workspace protocol handles internal package linking cleanly. Vercel deploys natively with Turborepo.

Framework

Next.js 14 (App Router)RemixSvelteKit

Best Vercel integration, RSC for data-heavy pages, established patterns for API routes that serve as the backend layer. Each product is its own Next.js app in the monorepo.

Database

Postgres + PrismaSupabasePlanetScale

JSONB support critical for evolving schemas. Prisma gives type-safe queries and migration management. Row-level security by org_id for multi-tenancy. Can layer Supabase on top later for realtime.

AI Integration

Claude API (function calling)OpenAIMulti-provider

Function calling for the conversational intake engine. Tool definitions per product — same orchestration code, different tool sets. Can abstract to multi-provider later if needed.

Auth

ClerkNextAuthAuth0

Fastest to production with org/team support built in. Handles the multi-tenancy pattern (user → org membership) natively. Easy migration to custom auth later if scale demands it.

Document Generation

Custom pipeline (docxtemplater + pdf-lib)PandocWeasyPrint

Full control over template design. docxtemplater for Word/DOCX, pdf-lib for PDF manipulation. Templates live in each product's /templates directory. Shared doc-gen service renders them.

Deployment

Vercel (per-product)AWSRailway

Native Turborepo support means each product deploys independently from the monorepo. Preview deployments per PR. Edge functions for API routes. Zero-config from git push to production.

Styling

Tailwind CSSCSS Modulesstyled-components

Shared design tokens via tailwind.config.js across all products. No runtime CSS-in-JS overhead. Consistent utility classes in the shared UI primitives package.

Shared Service Architecture

Every product follows the same request flow:
1
User InputNatural language or structured form data enters through the product's UI
2
Intake EngineShared conversational module determines which schema fields need filling, generates follow-up questions
3
LLM ClientClaude API call with product-specific tool definitions. Function calling extracts structured data.
4
Domain LogicProduct-specific business rules: estimation calculations, scoring algorithms, matching logic
5
Data LayerPrisma writes to Postgres. Shared entities updated. Cross-product references populated.
6
Doc GenTemplates rendered to PDF/DOCX. Output stored in Document entity. Returned to user.
Steps 2, 3, 5, and 6 are shared code. Only steps 1 and 4 are product-specific. Adding a new product means: new UI (1), new tool definitions (3), new domain logic (4), new templates (6). The infrastructure doesn't change.

Multi-Tenancy Model

org_id is the partition key on every entity. All queries are scoped by org. Prisma middleware enforces this — no query can execute without an org context.

Row-level security in Postgres as a second layer. Even if the application layer has a bug, the database won't return cross-tenant data.

Clerk organizations map 1:1 to the Organization entity. User → Org membership with roles (owner, admin, member) handled by Clerk, mirrored in our User entity.