Signal-to-Content Intelligence Platform
A production SaaS that turns market signals into brand-checked content drafts. A 62-rule guardrail engine reviews every draft before a human sees it.
- Role
- Architect & sole engineer
- Timeline
- 2026 to present
- Status
- In production
- Context
- Built for FullFunnel, a Boston-based GTM agency serving 50+ B2B clients
// stage.problem
Content teams drown in noise and ship generic AI slop
The agency’s clients hit two failures at once. Content calendars were built from last quarter’s keyword research, so by publish day the conversation had moved. And when teams used AI to close the speed gap, they got fluent, generic text: off-brand, unverifiable, and often wrong in the details.
The brief I set myself: make the research continuous instead of manual, and constrain AI drafting hard enough that the output survives a brand editor.
// stage.system
Signals in, governed drafts out
Ingestion runs on scheduled Inngest jobs: per-client listening configs pull competitor updates, industry news, and community signals through scraping and search APIs, normalize them, and embed them into pgvector. Clustering groups related signals into topics. A ranking pass scores each topic against the client’s ICP, Search Console data, and past content performance, surfacing the gap between what the market is asking and what the client ranks for. The result is a weekly opportunity queue.
Generation runs through two gates. A router picks among 8 models via OpenRouter based on task type and cost ceiling, with undated model aliases so provider deprecations don’t break production. Every draft then passes the guardrail engine (62 codified rules against AI-tell patterns, vague claims, and structural slop) and a brand-voice comparison against embeddings of the client’s own published writing. Drafts that fail either gate are regenerated with the failure reasons injected into the prompt. Drafts that pass reach a human review queue with full provenance: which signals, which model, what cost.
The whole system is multi-tenant: Clerk auth, per-tenant scoping enforced in middleware, 45+ tables. It runs across the agency’s entire client portfolio.
// stage.product.view
A review queue instead of a blank page
// stage.key.decisions
Why it’s built this way
Decision 01
Durable queues over cron scripts
- Chose
- Inngest for every pipeline step
- Over
- Vercel cron + fire-and-forget API routes
Signal ingestion is long-running, failure-prone work against third-party APIs. Inngest gave step-level retries, concurrency limits per tenant, and replayable runs. A failed scrape retries itself; a failed cron script silently loses a week of signals.
Decision 02
One vector store instead of two databases
- Chose
- pgvector (halfvec) inside the main Postgres
- Over
- Dedicated vector DB (Pinecone/Qdrant)
Signals need joins against tenants, topics, and drafts constantly. Keeping vectors in Postgres meant one source of truth, transactional writes, and no sync layer. halfvec cut the index footprint roughly in half; accuracy loss was unmeasurable for this workload.
Decision 03
Codified rules over tone prompts
- Chose
- A codified 62-rule guardrail engine
- Over
- "Write in a human tone" prompt instructions
Prompt-level tone instructions decay as models change and prompts grow. Explicit rules, each testable with its own failure message, made quality enforceable and debuggable. When a draft fails, the log names the rule.
Decision 04
Model routing as a first-class system
- Chose
- Multi-model router with per-call cost tracking
- Over
- One flagship model for everything
Clustering summaries don’t need the same model as final drafts. Routing by task cut generation costs materially, and cost-per-piece became a reportable metric instead of a monthly surprise.
// stage.production.notes
What broke, and what it taught the system
Silent fallbacks are worse than loud failures
A scraping provider started returning degraded results instead of errors. The pipeline kept running while signal quality collapsed. Fix: validation on ingest with explicit quality thresholds, and alerts when a source’s yield drops below baseline. Every external dependency now fails loudly.
Model deprecations happen on someone else’s schedule
A dated model identifier got deprecated mid-operation. The router now uses undated aliases resolved at call time, with fallback chains per task type. A provider retiring a model no longer takes the pipeline down.
Multi-tenancy is a middleware problem, not a query problem
Tenant scoping enforced once, in middleware, rather than trusting every query to remember a WHERE clause. An early auth-bypass bug found in testing turned this from a preference into a rule.
OUTCOMES
What the numbers say
The platform runs the agency’s content operation across its client portfolio: weekly ranked topics per client, drafts that arrive pre-checked against the brand’s own voice, and a review queue instead of a blank page. Content research went from a recurring manual task to a background process.
Every draft carries provenance: source signals, model, cost, guardrail results. Editors can check any claim against its source. That audit trail is why they trust the queue.
WHAT I’D DO DIFFERENTLY
The honest retro
- I over-invested in scraping breadth early. Half the sources produced signals nobody acted on; the ranking layer mattered more than source count. Today I’d ship with 5 high-yield sources and expand by demand.
- Guardrail rules should have been versioned from day one. Editing rules in place made "why did this draft pass last month?" harder to answer than it should be.
“Your ability to quickly understand what we’re trying to do, interpret the concept, and then play tennis with me to get it from theory to a product — that is your most meaningful contribution. We came up with a story. You helped me make it real.”
// stage.common.questions
What is a content intelligence platform?
A system that continuously ingests market signals (competitor moves, industry news, community discussions), clusters them into topics, ranks them against a client’s ICP and search data, and drafts content under brand guardrails. This one runs as a multi-tenant SaaS across an agency’s client portfolio.
How does the guardrail engine prevent AI-sounding content?
62 codified rules check every draft for AI-tell patterns, vague claims, and structural slop, alongside a brand-voice comparison against embeddings of the client’s own published writing. Drafts that fail either gate are regenerated with the failure reasons injected into the prompt.
Why route across 8 LLM models instead of using one?
Different pipeline steps need different quality-to-cost ratios: clustering summaries tolerate cheaper models, final drafts do not. Routing by task type with per-call cost tracking made cost-per-piece a reportable metric instead of a monthly surprise.