Fastify 5 · Drizzle ORM · PostgreSQL 16 · TypeScript 5.8 · Vanilla HTML/JS + Three.js/Lottie/GSAP
any types, strict TS — but 1,538-line orchestratorany, noUncheckedIndexedAccess — missing noUnusedLocalsImpact: Every mailer method (sendOwnerNewSubmission, sendUserReceipt, sendAdminMagicLink, sendOwnerInternalPlan, sendOwnerOutboundFromTemplate) wraps its Resend API call in a try/catch that logs to console.error and silently swallows the error. If Resend is down, rate-limited, or the recipient bounces, the lead submission is permanently lost — the owner never gets notified, the visitor never gets a receipt, and no retry or dead-letter mechanism exists. The session is marked "submitted" in the DB regardless.
✅ Fix: (1) Add a retry wrapper with exponential backoff (3 attempts). (2) On final failure, insert a row into a email_failures table or webhook_log with the payload for replay. (3) Surface failed emails in the admin dashboard. (4) Replace console.error with structured logger (app.log.error).
Impact: No GitHub Actions, no CI config of any kind. Tests, type checking, linting, and builds are entirely manual. Any developer can push broken code to main with nothing stopping them. Deployments require manual SSH + npm run build. There's no automated dependency scanning (Dependabot/Snyk) or security auditing.
✅ Fix: Create .github/workflows/ci.yml with: (1) npm ci → (2) npx tsc --noEmit → (3) npm test → (4) npm run build. Add Dependabot config for weekly security updates. Add a deployment workflow using the existing Dockerfile.
Impact: The start() function in server/index.ts calls runMigrations(), but no migration files exist in the repository. The Dockerfile copies dist/server/db/migrations, implying they should exist. On a fresh deploy, runMigrations() either no-ops or fails silently (the catch block logs and continues in "degraded mode"), meaning the schema might not match the Drizzle table definitions. This could cause runtime errors on any DB query.
✅ Fix: Run npx drizzle-kit generate to create migration files from the existing schema. Commit them. Verify runMigrations() applies them correctly on a fresh database. Add a migration step to the Dockerfile CMD or an entrypoint script.
The IntakeOrchestrator class handles session creation, resume, answer validation, question composition, brief generation, asset generation, email dispatch, lead scoring, event tracking, admin settings, and URL audits — all in one file. This is the single largest decomposition risk in the codebase. Extract: BriefService, AssetService, EmailDispatchService, SessionStateService.
Seven homepage preview variants (v2–v7) are served alongside the real index.html. They're accessible via direct URL, indexed by search engines, and confuse the static file server's routing. They also duplicate CSS/JS, inflating the deploy artifact.
console.* Calls in Server CodeFastify has a structured Pino logger (app.log), but 19 console.error/warn calls bypass it. These won't appear in production log aggregators, can't be filtered by log level, and have no request context. Replace all with request.log.error() or app.log.error().
package.json has no license field and no LICENSE file exists. This means the code is technically "all rights reserved" by default, which prevents any legitimate reuse or contribution. Add an MIT or Apache-2.0 license.
The /api/health endpoint returns { ok: true, timestamp } without checking if the database is reachable, if S3/MinIO is accessible, or if the LLM provider is configured. A load balancer will route traffic to a server with a broken DB connection. Add DB ping, storage check, and optionally LLM provider check.
| Sev | Finding | File |
|---|---|---|
| P2 | Missing noUnusedLocals / noUnusedParameters in tsconfig — dead variables and unused params compile silently | tsconfig.json |
| P2 | No API versioning — all routes under /api/ with no /v1/ prefix, breaking changes have no migration path | server/routes/ |
| P2 | 10 mascot PNG files at 400–507KB each (~4.3MB total) — unoptimized, should be WebP/AVIF at 1/10 the size | public/assets/img/mascots/ |
| P2 | mascot.mp4 is 1.7MB — no streaming, no poster image, loads eagerly on page paint | public/assets/mascot.mp4 |
| P2 | No rate limiting on admin routes — only session routes have getSessionRateLimitConfig. Admin login endpoint is brute-forceable. | server/routes/admin.ts |
| P2 | Three.js loaded globally at 654KB — only used on homepage, should be lazy-loaded or code-split | public/assets/vendor/three/three.min.js |
| P2 | No CONTRIBUTING.md or CHANGELOG.md — onboarding for new contributors is ad-hoc | / |
| P2 | tslib> in | package.json |
| P2 | Garbled em-dash character (¢) in mailer.ts line 216 — encoding issue in error message string | server/services/mailer.ts:216 |
| Sev | Finding |
|---|---|
| P3 | docker-compose uses hardcoded postgres:postgres credentials — fine for local dev, should note in README — docker-compose.yml |
| P3 | No .nvmrc or engines field in package.json for Node version pinning (Dockerfile uses Node 20) — package.json |
| P3 | MinIO credentials minioadmin:minioadmin in docker-compose — acceptable for local dev only — docker-compose.yml |
| P3 | CORS allows Origin: null (file:// pages) — intentional for local testing but should be disabled in production — server/index.ts:83 |
public/index-preview-v*.html"license": "MIT" to package.json and create LICENSE file — package.jsonnoUnusedLocals: true and noUnusedParameters: true to tsconfig — tsconfig.jsonserver/services/mailer.tsengines: { "node": ">=20" } to package.json — package.jsontslib from dependencies to devDependencies — package.jsonnpx drizzle-kit generate to create and commit migration files — server/db/migrations/cwebp -q 80) — saves ~3.8MB — public/assets/img/mascots/02-architecture.md| Sev | Finding | File |
|---|---|---|
| P0 | Mailer silent-failure pattern — all email sending is fire-and-forget with no retry or dead-letter | server/services/mailer.ts |
| P1 | IntakeOrchestrator is a 1,538-line god object — handles sessions, briefs, assets, emails, scoring, events, URL audits | server/agent/orchestrator.ts |
| P2 | No async job infrastructure — long-running operations (LLM calls, URL audits, email sending) block the request thread | server/ |
| P2 | No API versioning — breaking changes have no migration path | server/routes/ |
| P3 | NoOpMailer pattern is good — clean fallback when RESEND_API_KEY is missing | server/services/mailer.ts |
| P3 | Dependency injection in buildServer() is well-structured — orchestrator receives all deps via constructor | server/index.ts |
Strengths: Clean layered architecture (routes → orchestrator → services → db). Fastify plugin registration is well-organized. Env validation via Zod is exemplary. Schema design with proper foreign keys, cascade deletes, and enum types. Weaknesses: No background job system, no event bus, orchestrator needs decomposition.
03-code-review.md| Sev | Finding | File |
|---|---|---|
| P1 | 19 console.* calls bypass Fastify's structured Pino logger — no request context, no log level filtering | server/services/mailer.ts |
| P2 | z.any() used in session route schemas (seedAnswers, value) — loses type safety at the API boundary | server/routes/sessions.ts |
| P2 | Validation retry capped at 1 — user gets only one retry on invalid input before being stuck | server/agent/orchestrator.ts:244 |
| P3 | HTML escaping in mailer is manual (escapeHtml) — correct but could use a library for edge cases | server/services/mailer.ts |
| P3 | Timing-safe comparison for resume tokens — excellent security practice | server/agent/orchestrator.ts:204 |
Zero any types in server code is exceptional. Zod validation on all API inputs. JWT cookie auth with proper httpOnly/secure/sameSite flags. The codebase shows strong engineering discipline — the issues are architectural (god object), not careless.
04-design-quality.md| Sev | Finding | File |
|---|---|---|
| P1 | 7 preview HTML files (v2–v7) shipped in production — duplicate content, SEO confusion | public/index-preview-v*.html |
| P2 | 10 mascot PNGs at 400KB+ each — should be WebP (10x smaller) | public/assets/img/mascots/ |
| P3 | Full design token system with light/dark mode — Linear/Vercel/Stripe-inspired, 8px grid, proper radii | public/assets/css/tokens.css |
| P3 | Three.js + Lottie + GSAP for motion design — premium interactive feel | public/assets/vendor/ |
The design system is genuinely premium: full CSS custom property token set, dark/light toggle with localStorage persistence, 8px spacing grid, Bebas Neue + DM Sans typography, teal accent with orange CTA. The motion layer (GSAP ScrollTrigger, Lottie animations, Three.js hero) adds Flash-era energy. Main issue is asset optimization, not design quality.
08a-data-integrity.md| Sev | Finding | File |
|---|---|---|
| P3 | Zero mock/fake/dummy/placeholder data in production code — all data flows from DB or user input | server/ |
| P3 | Budget presets ("Under $5k", "$5k-$15k", etc.) are legitimate UI options, not fake data | public/assets/js/intake-bundle.js |
| P3 | Seed data exists in catalog.seed.ts but is clearly marked as seed/bootstrap data, not fake | server/db/seeds/ |
Excellent data hygiene. No hardcoded display values, no mock data in production paths, all content is DB-driven via the catalog system. The Zod-validated env schema prevents misconfiguration. Database schema uses proper foreign keys with cascade deletes and enum types.
04b-production-readiness.md| Sev | Finding | File |
|---|---|---|
| P0 | No CI/CD pipeline — no automated tests, type checking, or deployment | .github/ |
| P0 | Database migrations not committed — fresh deploys may have schema drift | server/db/migrations/ |
| P1 | Health check is shallow — no DB or storage dependency verification | server/routes/health.ts |
| P2 | No metrics/monitoring — no Prometheus, no OpenTelemetry, no APM | server/ |
| P2 | No structured logging — 19 console.* calls bypass Pino logger | server/services/ |
| P3 | Graceful shutdown implemented — SIGTERM/SIGINT handlers call app.close() | server/index.ts |
| P3 | Multi-stage Dockerfile is well-structured — separate build and runtime layers | Dockerfile |
The Dockerfile and docker-compose are production-quality. The graceful shutdown handler is correct. But the absence of CI/CD, committed migrations, monitoring, and deep health checks means this codebase is not yet safe for unattended production deployment.
06-test-health.md| Sev | Finding | File |
|---|---|---|
| P2 | No coverage thresholds configured — Vitest runs but no minimum coverage gate | package.json |
| P2 | No integration/e2e tests — only unit tests for orchestrator, recommender, ROI, rules, schemas, scoring, server, URL audit | tests/ |
| P2 | No load/stress tests — no k6, Artillery, or JMeter configs | / |
| P3 | 8 test files with 49 test cases and 120 assertions — good unit-level coverage for core logic | tests/ |
| P3 | Server tests use supertest — proper HTTP-level testing of route handlers | tests/server.test.ts |
Test files: orchestrator.test.ts (519 lines, 9 tests, 36 expects), server.test.ts (291 lines, 14 tests, 29 expects), recommender.test.ts (145 lines, 7 tests), url-audit.test.ts (112 lines, 3 tests, 18 expects), roi.test.ts (91 lines, 6 tests), schemas.test.ts (60 lines, 3 tests), scoring.test.ts (66 lines, 3 tests), rules.test.ts (44 lines, 4 tests). The tests are well-written but limited to unit level — no e2e, no coverage gate.
07-documentation.md| Sev | Finding | File |
|---|---|---|
| P2 | No CONTRIBUTING.md — no onboarding guide for contributors | / |
| P2 | No CHANGELOG.md — no release history or version tracking | / |
| P2 | No ADRs (Architecture Decision Records) — decisions are implicit in code | / |
| P3 | README.md present — basic project setup instructions | README.md |
| P3 | .env.example is thorough — documents all env vars with comments explaining each | .env.example |
| P3 | docs/brand-voice.md — brand voice/style guide for content | docs/brand-voice.md |
5 markdown files total: README.md, docs/brand-voice.md, public/assets/img/mascots/README.md, public/assets/lottie/README.md, public/assets/vendor/README.md. The .env.example is genuinely well-documented with inline comments for every variable. Missing: ADRs, runbooks, CONTRIBUTING, CHANGELOG, API reference.
05-dependencies.md| Sev | Finding |
|---|---|
| P1 | No license field in package.json — legal status unclear |
| P2 | tslib in dependencies instead of devDependencies — runtime bloat |
| P2 | No Dependabot or Renovate config — no automated security update PRs |
| P3 | 18 dependencies, 7 devDependencies — lean and focused, no bloat |
| P3 | All deps are well-maintained, popular packages (Fastify 5, Drizzle 0.44, Zod 3.25, Resend 4.5) |
| P3 | package-lock.json present — reproducible installs |
Key deps: @anthropic-ai/sdk ^0.51, @aws-sdk/client-s3 ^3.821, fastify ^5.3.3, drizzle-orm ^0.44.2, openai ^4.103, resend ^4.5.1, zod ^3.25.28. Dev: typescript ^5.8.3, vitest ^3.1.2, supertest ^7.1.1, tsx ^4.19.4, drizzle-kit ^0.31.1. The dependency tree is healthy and minimal.
08-typescript-audit.md| Sev | Finding |
|---|---|
| P2 | Missing noUnusedLocals and noUnusedParameters — dead code compiles silently |
| P3 | 0 : any types in server code — exceptional type discipline |
| P3 | 0 as any casts — no type escape hatches |
| P3 | strict: true and noUncheckedIndexedAccess: true enabled — strictest possible config |
| P3 | ES2022 target with NodeNext module resolution — modern, correct for Node 20 |
The TypeScript configuration is near-perfect. strict: true, noUncheckedIndexedAccess: true, forceConsistentCasingInFileNames, skipLibCheck. Zero any types across 8,591 lines of server TS. The only gap is noUnusedLocals/noUnusedParameters.
09-api-surface.md| Sev | Finding |
|---|---|
| P2 | No API versioning — no /v1/ prefix, breaking changes have no migration path |
| P2 | No OpenAPI/Swagger spec — 65 routes undocumented |
| P2 | z.any() used for seedAnswers and answer value — loses type safety at API boundary |
| P3 | 65 server routes across 7 route files — well-organized by domain (sessions, admin, catalog, events, voice-demos, uploads, health) |
| P3 | 26 frontend fetch calls — all use credentials: 'same-origin' or 'include' for cookie auth |
| P3 | All route inputs validated with Zod schemas — no unvalidated request bodies |
Route breakdown: sessions (10 routes), admin (20 routes), catalog (15 routes), voice-demos (7 routes), events (2 routes), uploads (3 routes), health (1 route). Plus 9 static page routes. Frontend-backend API contract is consistent — all fetch calls have corresponding server routes.
09-mobile-responsiveness.md| Sev | Finding |
|---|---|
| P2 | Responsive breakpoints only in preview HTML files and 3 CSS files — main base.css and components.css lack media queries |
| P2 | No hamburger menu / mobile nav toggle in main site chrome — nav-links just hidden at 980px with no replacement |
| P3 | 60 responsive declarations across the codebase — @media (max-width: 980px) breakpoint is consistent |
| P3 | prefers-reduced-motion media query implemented — accessibility-conscious |
The responsive approach is basic: grids collapse to 1fr, nav links are display:none. No mobile menu replacement means navigation is inaccessible on mobile. The prefers-reduced-motion support is a nice touch.
10-bundle-analysis.md| Sev | Finding |
|---|---|
| P2 | Three.js 654KB loaded globally — only used on homepage hero, should be lazy-loaded |
| P2 | Lottie 164KB + GSAP 113KB (71KB + 42KB ScrollTrigger) = 931KB vendor JS total — no bundler, all eagerly loaded via <script> tags |
| P2 | mascot.mp4 at 1.7MB — no poster image, no streaming, loads on page paint |
| P2 | 10 mascot PNGs totaling ~4.3MB — should be WebP (~430KB total at 80% quality) |
| P3 | No module bundler (Webpack/Vite/esbuild) — vanilla <script> tags, no tree-shaking, no minification of app JS |
Total vendor JS: 931KB (Three.js 654KB + Lottie 164KB + GSAP 71KB + ScrollTrigger 42KB). Total large assets: ~6.9MB (vendor JS + mascot.mp4 + PNGs). First page load could exceed 7MB without optimization. Converting PNGs to WebP and lazy-loading Three.js would save ~4.5MB.
10b-design-strategy.mdIndustry: AI/Marketing Consultancy · Benchmarks: Top agencies (IDEO, R/GA, Accenture Song) · This phase evaluates the site as a design strategy consultant — not just "are your CSS tokens consistent" but "would a new visitor be impressed enough to sign up?"
| Dimension | Current State | Industry Standard | Gap |
|---|---|---|---|
| Visual System | Full token system, dark/light mode, teal+orange accents | Consistent brand language, motion design | Minimal gap |
| Hero Experience | Three.js + Lottie + GSAP hero with mascot | Cinematic hero, 3D elements, parallax | Meets standard |
| Content Strategy | Services catalog, case studies, voice demos | Thought leadership, case study depth | Partial gap |
| Conversion Funnel | Intake widget, discovery flow, free audit | Multi-step funnel, A/B tested CTAs | Significant gap |
| Personalization | AI recommender matches services to needs | Dynamic content, user segmentation | Partial gap |
| Analytics | First-party event tracking (12 event types) | GA4 + PostHog + conversion tracking | Meets standard |
| Performance | ~7MB first load, no lazy-loading | <2MB first load, LCP < 2.5s | Critical gap |
| Bottleneck | Impact | Priority | Recommended Approach |
|---|---|---|---|
| 7MB+ page weight kills mobile conversion | 40-60% bounce on mobile | P0 | Convert PNGs to WebP, lazy-load Three.js, add mascot poster image |
| No mobile navigation — nav links hidden at 980px | Mobile users can't navigate past homepage | P1 | Add hamburger menu with slide-out nav panel |
| No A/B testing on CTAs or intake flow | Can't optimize conversion rate | P2 | Integrate GrowthBook or PostHog experiments on intake CTA |
| No social proof above the fold | Trust deficit for first-time visitors | P2 | Add client logos, testimonial carousel, or metrics strip to hero |
| 7 preview HTML files dilute SEO | Duplicate content penalty risk | P1 | Delete preview files, add canonical meta tags |
three.jslottie + web-audiogsapgsap ScrollTrigger20-gate-architecture.md| 9-10 Criteria | Met? | Evidence |
|---|---|---|
| Async job infrastructure (BullMQ/Agenda/Bree) | ❌ No | No queue system — LLM calls, URL audits, emails all block request thread |
| Feature flag system | ⚠️ Partial | provider.isEnabled() exists for LLM provider only, not general-purpose |
| API versioning | ❌ No | All routes under /api/ with no version prefix |
| Event-driven architecture | ❌ No | No EventEmitter, no event bus — direct method calls only |
| Multi-tenancy support | ❌ No | No tenant/org/workspace isolation — single-owner design |
| OpenTelemetry / distributed tracing | ❌ No | Only transitively in package-lock (from dep tree), not used |
21-gate-correctness.md| 9-10 Criteria | Met? | Evidence |
|---|---|---|
| Property-based testing (fast-check) | ❌ No | No fast-check or property-based testing in any test file |
| Contract testing (Pact) | ⚠️ Partial | Test comments mention "contract" but no Pact/schematic contract tests |
| Idempotency keys on mutations | ❌ No | No idempotency key header handling on POST routes |
| Retry with exponential backoff | ⚠️ Partial | Validation retry (1 attempt) exists, but no retry on LLM/email/audit calls |
| Chaos engineering | ❌ No | No chaos monkey, no fault injection, no circuit breaker |
| Formal verification / invariants | ❌ No | No formal specs, no invariant checking, no TLA+/Alloy |
22-gate-design.md| 9-10 Criteria | Met? | Evidence |
|---|---|---|
| Storybook / component documentation | ❌ No | No .storybook directory, no *.stories.* files |
| Motion design system | ✅ Yes | GSAP ScrollTrigger, Lottie animations, CSS keyframe animations, prefers-reduced-motion |
| Dark mode with auto-detection | ✅ Yes | Full dark/light toggle with localStorage, data-theme attribute, token overrides |
| Internationalization (i18n) | ❌ No | No i18next, no react-intl, English-only |
| PWA / offline support | ❌ No | No service worker, no manifest.json, no workbox |
| A/B testing infrastructure | ❌ No | No experiment framework, no feature flag service |
23-gate-security.md| 9-10 Criteria | Met? | Evidence |
|---|---|---|
| Multi-factor authentication (MFA) | ❌ No | Magic link auth only — no TOTP, no WebAuthn, no 2FA |
| Audit logging / trail | ❌ No | No audit log table, no admin action tracking (events table is for analytics, not security audit) |
| Secrets rotation | ❌ No | No vault integration, no key rotation mechanism |
| CI dependency scanning | ❌ No | No Snyk, no Dependabot, no npm audit in CI (no CI exists) |
| security.txt / responsible disclosure | ❌ No | No .well-known/security.txt, no bug bounty policy |
| CSP / Helmet headers | ✅ Yes | Fastify Helmet with dynamic CSP derivation from env vars, strict origin CORS |
| JWT cookie auth (httpOnly, secure, sameSite) | ✅ Yes | Proper cookie options, timing-safe token comparison, 12h session / 7d admin expiry |
24-gate-testing.md| 9-10 Criteria | Met? | Evidence |
|---|---|---|
| Mutation testing (Stryker) | ❌ No | No Stryker config, no mutation testing |
| Load/stress tests (k6/Artillery/JMeter) | ❌ No | No load testing configs |
| Coverage thresholds enforced | ❌ No | No coverage config in vitest or package.json |
| E2E tests (Playwright/Cypress) | ❌ No | No e2e test framework |
| 8 test files, 49 test cases, 120 assertions | ⚠️ Partial | Good unit test coverage for core logic, but no higher-level testing |
| supertest for HTTP route testing | ✅ Yes | server.test.ts uses supertest for 14 route-level tests |
25-gate-ops.md| 9-10 Criteria | Met? | Evidence |
|---|---|---|
| Circuit breakers (opossum/polly) | ❌ No | No circuit breaker pattern anywhere |
| Metrics (Prometheus/OpenTelemetry) | ❌ No | No metrics endpoint, no prom-client, no custom metrics |
| SLO/SLI definitions | ❌ No | No SLO/SLI docs, no error budget tracking |
| Auto-scaling / multi-region | ❌ No | No k8s, no Helm, no auto-scaling config |
| Graceful shutdown | ✅ Yes | SIGTERM/SIGINT handlers call app.close() with DB cleanup |
| Multi-stage Dockerfile | ✅ Yes | 4-stage build (deps → build → prod-deps → runtime), Node 20 Alpine |
| docker-compose for local dev | ✅ Yes | PostgreSQL 16 + MinIO with persistent volumes |
26-gate-docs.md| 9-10 Criteria | Met? | Evidence |
|---|---|---|
| ADR (Architecture Decision Records) | ❌ No | No adr/ or decisions/ directory |
| Runbooks / incident playbooks | ❌ No | No runbook, playbook, or oncall docs |
| CONTRIBUTING guide | ❌ No | No CONTRIBUTING.md |
| Automated API docs in CI | ❌ No | No OpenAPI/Swagger/Redoc, no .github/ workflows |
| Interactive tutorials / getting started | ❌ No | No tutorial or walkthrough docs |
| README with setup instructions | ✅ Yes | README.md present with basic setup |
| Thorough .env.example | ✅ Yes | Every env var documented with inline comments |
| Brand voice guide | ✅ Yes | docs/brand-voice.md for content consistency |
27-gate-conversion.md| 9-10 Criteria | Met? | Evidence |
|---|---|---|
| A/B testing on CTAs and intake flow | ❌ No | No experiment framework (GrowthBook, Optimizely, PostHog experiments) |
| NPS / satisfaction surveys | ❌ No | No NPS widget, no feedback form, no satisfaction rating |
| Personalization engine | ⚠️ Partial | AI service recommender matches services to answers, but no dynamic content or user segmentation |
| Accessibility certification (WCAG AA/AAA) | ❌ No | No axe-core testing, no a11y audit, no WCAG certification |
| First-party analytics | ✅ Yes | analytics.js with 12 event types, GA4/PostHog/Plausible integration, consent banner |
| Case studies with metrics | ✅ Yes | DB-driven case studies with metrics array, featured flag, gallery URLs |
| Multi-step intake funnel | ✅ Yes | 5 flows (brand, website, freeAudit, discovery, urlAudit) with branching question logic |
| Voice demo showcase | ✅ Yes | Voice demo system with phone numbers, recordings, event tracking, QR codes |
28-certification.md| Dimension | 9-10 Gate | Criteria Met |
|---|---|---|
| Architecture | FAIL | 0/6 — missing async jobs, API versioning, event bus, multi-tenancy, tracing |
| Correctness | FAIL | 0/6 — no property-based testing, no idempotency, no chaos engineering |
| Design/UX | FAIL | 2/6 — has motion design and dark mode, missing Storybook, i18n, PWA, A/B testing |
| Security | FAIL | 2/7 — has CSP/Helmet and JWT cookie auth, missing MFA, audit logging, secrets rotation |
| Testing | FAIL | 1/6 — has supertest HTTP tests, missing mutation, load, coverage, e2e |
| Ops | FAIL | 3/7 — has graceful shutdown, Dockerfile, docker-compose, missing circuit breakers, metrics, SLO |
| Docs | FAIL | 3/8 — has README, .env.example, brand-voice guide, missing ADRs, runbooks, CONTRIBUTING |
| Conversion | FAIL | 4/8 — has analytics, case studies, intake funnel, voice demos, missing A/B testing, NPS, a11y |
The Consultant has a strong foundation — zero any types, strict TypeScript, Zod-validated inputs, clean architecture, premium design tokens, and a well-structured DB schema. However, it does not meet 9-10 certification standards in any dimension. The codebase is at a 6-7/10 "solid startup" level. To reach 9-10, it needs: CI/CD with coverage gates, background job infrastructure, API versioning, MFA + audit logging, Prometheus metrics, Storybook, A/B testing, and comprehensive documentation (ADRs, runbooks, CONTRIBUTING). The 3 P0 issues (mailer silent failures, no CI/CD, missing migrations) must be fixed first.
11-strategic-roadmap.mdWeek 1: Fix P0s + Quick Wins
drizzle-kit generate, commit migrations, verify fresh DB deployconsole.* with Pino logger, add deep health check (DB + storage ping)display:none nav hackWeek 2: Architecture + Testing
/api/v1/ prefix), add OpenAPI spec generationnpm audit to CI, add Snyk scanning| Quarter | Theme | Goals |
|---|---|---|
| Q1 2026 | Production Hardening | Fix all P0/P1, CI/CD, monitoring, migrations, deep health checks |
| Q2 2026 | Testing & Quality | 80% coverage, e2e with Playwright, load tests with k6, mutation testing |
| Q3 2026 | Scale & Performance | Background jobs (BullMQ), lazy-load Three.js, CDN for assets, Prometheus metrics |
| Q4 2026 | 9-10 Certification Push | MFA, audit logging, Storybook, A/B testing, i18n, PWA, ADRs |
12-backlog.md| Epic | Stories | Story Points |
|---|---|---|
| 🔴 P0 Critical Fixes | 3 | 21 |
| 🟠 P1 High-Impact | 5 | 29 |
| 🟡 P2 Medium | 9 | 27 |
| 🔵 P3 Low | 4 | 12 |
| Total | 21 | 89 |
| Story | Pri | SP | Effort | File |
|---|---|---|---|---|
| Mailer retry + dead-letter + structured logging | P0 | 8 | 1 day | server/services/mailer.ts |
| CI/CD pipeline with GitHub Actions | P0 | 5 | 4 hours | .github/workflows/ |
| Generate and commit DB migrations | P0 | 8 | 2 hours | server/db/migrations/ |
| Story | Pri | SP | Effort | File |
|---|---|---|---|---|
| Decompose IntakeOrchestrator into 4 services | P1 | 13 | 2 days | server/agent/orchestrator.ts |
| Delete 7 preview HTML files | P1 | 1 | 2 min | public/index-preview-v*.html |
| Replace 19 console.* with Pino logger | P1 | 3 | 2 hours | server/services/ |
| Add LICENSE file and package.json field | P1 | 1 | 2 min | package.json |
| Deep health check (DB + storage + LLM ping) | P1 | 5 | 3 hours | server/routes/health.ts |
| Story | Pri | SP | Effort | File |
|---|---|---|---|---|
| Add noUnusedLocals/noUnusedParameters to tsconfig | P2 | 2 | 3 min | tsconfig.json |
| Add API versioning (/api/v1/ prefix) | P2 | 5 | 4 hours | server/routes/ |
| Convert mascot PNGs to WebP | P2 | 2 | 8 min | public/assets/img/mascots/ |
| Lazy-load Three.js on homepage only | P2 | 3 | 2 hours | public/index.html |
| Add rate limiting to admin routes | P2 | 3 | 1 hour | server/routes/admin.ts |
| Add CONTRIBUTING.md and CHANGELOG.md | P2 | 2 | 1 hour | / |
| Move tslib to devDependencies | P2 | 1 | 1 min | package.json |
| Fix encoding issue in mailer.ts line 216 | P2 | 1 | 1 min | server/services/mailer.ts |
| Add mascot.mp4 poster image + lazy loading | P2 | 3 | 30 min | public/assets/mascot.mp4 |
Add a hamburger menu with a slide-out panel. Currently nav-links is just display:none at 980px — mobile users have no way to navigate.
Add client logos, a metrics strip ("50+ leads converted", "$2M+ revenue influenced"), or a testimonial carousel above the fold.
Make the Three.js mascot react to cursor position or scroll — currently it just rotates passively. Interactive 3D differentiates from every other consultancy.
Replace static case study cards with 3D flip animations revealing metrics on hover. Matches the premium design token aesthetic.
Add BullMQ or Bree for async processing of LLM calls, URL audits, and email sending. Currently all block the request thread.
Integrate GrowthBook or PostHog experiments on the intake CTA. The analytics infrastructure already exists — just need experiment assignment.
Add a service worker and manifest.json for installable PWA support. The vanilla HTML/JS architecture makes this straightforward.
Add TOTP-based 2FA for admin accounts. Magic links are good but not sufficient for an admin panel with lead data access.