← vuvasystems.com CV ↗

TECHNICAL DEMONSTRATION · PORTFOLIO PROJECT

A content platform where
AI drafts and people decide.

I built this as my Forward Deployed Engineer portfolio piece: a complete content platform with a headless CMS underneath, an AI assistant for drafting and search on top, and a workflow that refuses to publish anything until a person signs off. This page documents what I built, how it works, and what I’d change for production.

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.
No client was involved in this project and none is claimed. It exists to demonstrate how I engineer AI features into real products: with provenance, review gates and honest labels.

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.

Stack summary

Next.js 15React 19TypeScript strictTailwind CSS Headless CMS (ContentPort)RAG + BM25OpenAI-compatible LLM layer Cloudflare WorkersVitest · 38 tests

Try the platform yourself

No sign-up, no API keys. Ask it a question, run an assist through review, try to publish without approving — the system will stop you, politely.