Adeel Nayyer
← All work

AI / Platform · client work, details anonymised

AI-Native CMS

An AI-first backend for a hospitality marketing platform that generates a business's website content by default and lets owners refine it, with every edit feeding back into how the next site is generated.

Role
Architect and sole backend engineer
When
2026
Source
Client code, not public
Stack
  • Python
  • FastAPI
  • PostgreSQL + pgvector
  • SQLAlchemy 2.0
  • OpenAI / Anthropic
  • SentenceTransformers
  • Terraform
  • AWS ECS
  • Recipe-driven site generation that emits content in the existing frontend's contract, so the live renderer needed no changes
  • A closed feedback loop: owner edits are compiled into snapshots that tune prompts and evolve generation recipes, guarded by minimum-data and cooldown rules
  • Import pipeline for 567 legacy business records
AI-Native CMS: AI owns the defaults, owner edits become feedbackCLIENTSCORE APIDATAExisting site frontendOwner editsStory translationschema → storiesGeneration pipelinestream, validate, scoreFeedback compilerscheduledRecipe selectorPostgres + pgvectorschemas, feedbackLocal embedding modelpicks recipeversioned schematagged storiesrenderfeedback eventsevolve recipesvectors
AI-Native CMS: AI owns the defaults, owner edits become feedback

Problem

A hospitality and restaurant marketing platform ran small-business websites from a conventional CMS. Every site started as a blank set of fields that staff or owners filled in by hand, and nothing learned from the edits people made afterwards. The goal was a backend where AI writes the first version of every page and humans correct it, with those corrections improving the next generation. The existing customer-facing frontend had to stay as it was.

My role

I wrote the architecture and strategy documents and was the only committer on the backend across 287 commits between January and March 2026. That covered the data model, the generation pipeline, the feedback system, the legacy import and the AWS infrastructure as code. Delivery ran through a scripted, agent-assisted sprint cycle kept in the repository.

Architecture

A FastAPI service with async SQLAlchemy sits on PostgreSQL with the pgvector extension. One database holds identity, business profiles, menus, FAQs, versioned page schemas, feedback events and embeddings. A recipe selector picks a page recipe by business type and page. It takes database overrides and in-memory defaults, and any fallback is logged.

The generation service calls the LLM through a provider-neutral interface and parses the streamed JSON response as it arrives. Each section is validated and gets a confidence score with reason codes. A translation layer then turns the stored page schema into the tagged story records the existing frontend already renders. Scheduled jobs compile raw feedback into snapshots, improve low-scoring content daily and propose recipe changes. Terraform provisions the AWS side: VPC, load balancer, ECS, Aurora, Valkey, S3, Secrets Manager, monitoring, and GitHub OIDC for deploys.

Key decisions

  • Page schema as a first-class, versioned object. Generated pages aren’t written straight to content. They’re stored with recipe name, confidence and version, which gives rollback and a training record. This is in the architecture decision log.
  • Translate to the existing frontend’s format. StoryTranslationService maps sections to the existing tag format, so the AI backend could run alongside the legacy system with no frontend release.
  • pgvector before a dedicated vector database. Vectors live next to the data they describe. The decision log keeps Weaviate or Pinecone open as a later option behind a stable interface.
  • Self-hosted embeddings by default. The embedding layer supports OpenAI and SentenceTransformers behind one interface. The default moved to a local all-mpnet-base-v2 model, which costs nothing per call, keeps data private and has no rate limits.
  • Swappable LLM provider. get_llm_service returns an OpenAI or Anthropic implementation of one base class, picked by configuration.
  • Guarded recipe evolution. A recipe only changes automatically after a minimum number of generations across several businesses, and at most once per recipe per 24 hours. Every change is a new version that can be rolled back.

Outcomes

The backend generates complete pages from recipes, tracks confidence and acceptance per page, and turns owner edits into structured feedback that changes later generations. There are 93 test modules, and the schema is managed through 45 Alembic migrations. Import scripts bring 567 legacy business records into the new model, and search runs as dense-vector cosine similarity over pgvector.