Blueprint
Architecture
Eight layers, one contract-driven system. Each layer only knows the interface of the layer beneath it — which is why the demo runs without a single external dependency or credential.
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────────┐
│ HEADLESS CMS │ ──▶ │ CONTENT SERVICE │ ──▶ │ API LAYER │
│ Contentful/seed │ │ (ContentPort) │ │ 10 typed endpoints │
└─────────────────┘ └──────────────────┘ └──────────┬──────────┘
│
▼
┌─────────────────────┐ ┌──────────────────┐ ┌─────────────────────┐
│ EVALUATION/ │ ◀── │ AI ORCHESTRATION │ ──▶ │ NEXT.JS APPLICATION │
│ GOVERNANCE │ │ LLMProvider + CB │ │ static pages + RSC │
└─────────┬───────────┘ └────────┬─────────┘ └─────────────────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌──────────────────┐
│ OBSERVABILITY │ │ RETRIEVAL/VECTOR │
│ health·usage·audit │ │ BM25 → ANN-ready │
└─────────────────────┘ └──────────────────┘Live configuration right now: provider demo, active demo-simulated, circuit breaker closed, demo mode true. Verify independently at /api/health.
Headless CMS
Contentful (production) · Local seed adapter (demo)Structured content lives outside the application. Editors author against typed models (article, resource, FAQ, case study, author) with SEO and accessibility metadata as first-class fields. The application never queries a vendor SDK directly.
Implementation detail
Both adapters implement the same ContentPort interface: listArticles, getArticleBySlug, listResources, listFaqs, listCaseStudies, getCaseStudyBySlug, listAuthors, all(). Swapping backends is environment configuration — CONTENTFUL_SPACE_ID / CONTENTFUL_ACCESS_TOKEN — not a code change.
Content Service
TypeScript services over ContentPortA single service layer mediates every content read: sorting, category grouping, related-article resolution, reading time and search-index document construction. UI components never touch the CMS adapter directly.
Implementation detail
This is what keeps the demo honest: pages are server-rendered from the same service the API routes use, so there is one source of truth for content behaviour in both paths.
API Layer
10 route handlers · typed envelopes/api/content/[slug], /api/search, /api/rag, /api/ai/generate, /api/ai/evaluate, /api/recommendations, /api/workflow, /api/audit, /api/usage, /api/health. Every response uses a consistent envelope ({ok:true,data} | {error:{code,message}}) with validated inputs and correct status codes.
Implementation detail
Validation is dependency-free type-guarding at the boundary; business rules live in services below. The workflow endpoint is the only write surface and enforces the human-in-the-loop state machine.
Next.js Application
Next 15 · React 19 · static exportServer components pre-render every public page to static HTML at build; interactive islands (search, discovery console, assistant, recommendations) hydrate client-side and call the typed APIs. No web fonts, no trackers, minimal client JS.
Implementation detail
Static export means the public site is immutable hashed assets plus HTML — served from the edge with millisecond first paints. Dynamic behaviour is isolated to small client components with loading, error and empty states designed deliberately.
AI Orchestration
LLMProvider abstraction · circuit breakerAll AI calls flow through runCompletion(): task-labelled prompt contracts, telemetry capture per call, and a circuit breaker that fails closed to the clearly-labelled demo provider when a live provider errors repeatedly. Provider keys never leave the server.
Implementation detail
The OpenAI-compatible adapter speaks the standard chat-completions protocol, so DeepSeek, OpenAI or any compatible gateway is pure configuration (AI_PROVIDER, AI_BASE_URL, AI_MODEL, AI_API_KEY). The DemoProvider performs deterministic heuristic computation on the same call path.
Retrieval / Vector Layer
BM25 ranker (demo) · vector-ready interfaceRAG quality starts at retrieval: structure-aware passage extraction, freshness-aware ranking, and relevance thresholds that trigger honest refusals. The demo ships an in-process BM25 implementation with term-frequency indexing and title boosting.
Implementation detail
Production upgrade path: replace the index with managed embeddings + ANN search behind the same retrievePassages() contract, add hybrid reranking. Because RAG treats retrieval as replaceable, no orchestration code changes.
Evaluation & Governance
7-dimension harness · workflow state machine · audit logEvery AI draft passes evaluation (grounding, relevance, completeness, tone, safety, accessibility, source coverage) before human review. The workflow engine enforces legal transitions: publish requires prior approval by a human actor, rejections require reasons, and every event lands in an append-only audit log.
Implementation detail
Prompt-injection defence sits here too: retrieved text is delimited untrusted data with neutralised instruction patterns, system prompts declare the trust boundary, and outputs are schema-validated before display.
Observability
/api/health · usage store · audit streamThe health endpoint reports component checks with latency; the usage store aggregates tokens, cost estimates and latency per operation/provider; the audit log reconstructs any editorial decision. Dashboards read from these directly.
Implementation detail
Demo-mode telemetry is seeded and labelled simulated everywhere it appears — the dashboards demonstrate the operating practice without claiming production metrics.
Stack summary
- Framework
- Next.js 15 (App Router), React 19
- Language
- TypeScript (strict mode)
- Styling
- Tailwind CSS + design-token layer
- CMS
- ContentPort: local adapter now, Contentful adapter on credentials
- AI
- OpenAI-compatible provider protocol (DeepSeek-ready) + deterministic demo provider
- Retrieval
- In-process BM25, vector-upgrade path documented
- Delivery
- Static export on Cloudflare edge worker
- Quality
- Vitest suites: search, RAG guardrails, workflow, validation
- Operations
- Health endpoint, usage telemetry, append-only audit log