Case Study
Napoleon
A full SaaS for AI-powered marketing automation. Lead scoring, content generation, approval pipelines, social publishing, and job queue failure handling — all production-grade.
What It Is
Napoleon is a marketing automation SaaS that takes a business from zero to a fully queued, AI-generated, human-approved social media campaign — with a background job pipeline handling every step. It's built for agencies and solo operators who want automation without losing control over voice and quality.
The system includes lead ingestion, AI lead scoring (Gemini-capped at 10 per batch), voice draft generation, a human approval queue, and social publishing. Every stage has failure handling, retry logic, and dead-letter tracking.
The Engineering
BullMQ Background Job Queue
Every content action runs as an asynchronous job: ORCHESTRATE, GENERATE_SOCIAL, SEND_APPROVED_EMAIL, REWRITE_APPROVAL_CONTENT, REWRITE_SOCIAL_POST, SEND_EXPIRED_APPROVAL. Failed jobs enter a dead-letter queue and surface to the admin activity feed with a failure_reason field.
AI Voice Draft Engine
GPT-4o generates platform-specific draft content per post. A 17-rule voice enforcer checks each draft before it reaches the approval queue — banning 15+ banned phrases, checking opener patterns, and verifying tone signals match the client brand.
Connection-Before-Payment Gate
Social platform cards are always visible, but the product won't activate without at least one verified social connection. A 4-state banner guides the user from discovery to connected to ready to active. The /api/dashboard/social/readiness endpoint powers this in real-time.
Race Condition Fix on Lead Lock
Two workers were occasionally both passing the global lead lock check before either committed, resulting in duplicate outreach emails. Fixed with SELECT ... FOR UPDATE database transaction — row-level locking with no race window.
Hard Problems Solved
Every CTA was 404 at launch
The live site launched with all CTA buttons returning 404. Vercel was routing requests to its own 404 handler instead of the Railway backend. Fix: added vercel.json with explicit rewrite rules. Zero infrastructure changes — one config file fixed the entire product.
6 types of silent job failure
Jobs were disappearing with no trace. No error, no notification, no dead-letter entry. Fixed with a full sprint (N4-N9): dead-letter handlers for all six job types, failure surfacing to the activity feed, and frontend empty states per failure mode.
Gunicorn 2-worker startup race
Railway deploys were randomly crashing on startup. Two Gunicorn workers were both attempting to run DB migrations simultaneously, causing a collision. Fix: startup lock — only the first worker runs migrations, others wait.
Current State
Live at napoleon.polarisdgtl.com. 74/74 tests passing. All 6 dead-letter paths covered. Social setup gate active. Voice draft generating real content.