What I was trying to solve
Three problems show up in nearly every content operation I looked at. Editors can’t find things, so they rewrite work that already exists. AI drafting tools arrived faster than the governance around them, so nobody can say who approved a paragraph or where it came from. And a CEO and a developer need different versions of the same document, which most systems solve by making someone maintain two copies.
The interesting question wasn’t whether to add AI. It was whether one platform could do all three jobs well enough that editors wouldn’t quietly route around it.
The approach
I designed it contract-first. Every boundary in the system is a typed interface: the app
talks to the CMS through one ContentPort interface, the AI layer talks to language models
through one provider interface, and every API returns the same response envelope. That is why
the whole thing runs locally with no keys or database at all — swap the seed adapter for
Contentful or the demo model for DeepSeek and nothing above those interfaces changes.
How the platform works
The AI workflow
Editors get nine assistant operations: outlines, summaries, rewrites, audience adaptations, SEO descriptions, tag suggestions, FAQ generation, unsupported-claim screening and an accessibility pre-check. Anything the assistant produces carries an AI GENERATED DRAFT label that follows it through every state change.
The draft then moves through evaluation, human review, approval and publication as explicit steps. Each step writes an audit event. Illegal jumps are rejected by the server, publishing requires a prior human approval, and the automation account itself is barred from publishing. There’s a test suite that proves each of those rules.
RAG, with sources attached
Search questions hit a BM25 index over the structured corpus. Retrieved passages get wrapped in delimiters, stripped of instruction-style phrasing, and passed to the model as quoted data next to a system prompt that says: answer only from these sources. Responses cite specific passages, and the API validates those citations against what retrieval actually returned, so the model can’t invent a source. When coverage is thin the endpoint refuses rather than guessing — ask it about vacation policy and you’ll see the refusal, not a confident hallucination.
Evaluation
Drafts can be scored on seven dimensions: grounding, relevance, completeness, tone, safety, accessibility and source coverage. Scores are advisory by design; a person still approves. Machines catch the mechanical failure classes so reviewers spend attention on judgement calls.
- FRONT END
- Next.js 15 App Router, React 19, TypeScript strict mode, Tailwind CSS.
- CONTENT
- Typed content models behind a CMS port interface; local seed corpus now, Contentful adapter when credentials exist.
- AI LAYER
- OpenAI-compatible provider protocol (DeepSeek-ready), circuit breaker, deterministic demo model.
- RETRIEVAL
- BM25 ranking over structured records with passage extraction; vector search slots into the same interface later.
- DELIVERY
- Static export served from Cloudflare Workers with the API running at the edge.
- TESTING
- 38 tests covering retrieval relevance, RAG guardrails, workflow rules and API contracts.
Governance you can inspect
Most governance failures happen when the rule lives in a policy document but not in the tool. Here the rule lives in code: the transition table rejects illegal moves, rejections require a reason, provenance labels persist on every AI artefact, and the audit log reconstructs who did what to which revision. A dashboard surfaces all of it rather than hiding it in documentation.
Accessibility and performance were treated as engineering requirements too: semantic landmarks, keyboard-complete flows, visible focus states, reduced-motion support, pre-rendered pages and no third-party scripts anywhere in the public site.
What’s real versus simulated
Being straight about this matters more than looking bigger than I am.
- Real implementation: the CMS abstraction, search indexing and ranking, RAG pipeline with citation checking and refusals, the workflow engine and audit log, the evaluation harness, every API, the dashboards reading from them, and the test suite.
- Simulated, labelled everywhere it appears: model output in demo mode (a deterministic heuristic engine stands in for an LLM) and usage telemetry such as token counts and cost figures.
What I’d change for production
- Persistence. Workflow state and audit events live in memory here. Production gets Postgres (or D1 on this same Cloudflare setup) with append-only audit storage.
- Retrieval. BM25 over 25 documents is fine; over 50,000 it isn’t. Managed vector search goes behind the same interface, with hybrid ranking before reaching for rerankers.
- Auth. The dashboard has no login because it demonstrates mechanics. Production needs identity, roles and per-editor approval rights first.
- Rate limiting. Any live-provider deployment needs per-key and per-IP limits with budget ceilings before launch; in demo mode cost is zero by construction.
- Evaluation. The heuristic scorer shows the shape of the harness. Production would use a model-judged rubric plus a fixed question bank run in CI after every corpus or prompt change.