ForgeKit scaffolded, architecture locked, Forge built from scratch, deployed to app.forgekits.build in one session. 10 hours. Zero to live.
Clerk's clerkMiddleware expects the file Next.js 16 renamed to proxy.ts, and requires a named export. Multiple attempts with wrapped exports, no-op proxies, and trying to downgrade to Next.js 15 all failed — downgrade broke shadcn v4 which requires React 19 / Next.js 16.
500 errors on all authenticated routes in production.
proxy.ts with named export export { clerkMiddleware as proxy }. Rule: always check Next.js version before wiring Clerk middleware.
Windows PowerShell injected a U+FEFF byte-order mark when piping secrets via vercel env add. Keys arrived as pk_live_... instead of pk_live_.... Clerk and Neon both rejected them silently with cryptic errors.
Clerk: "isPublishableKey() failed". Neon: "connection string invalid".
Wrong keys, wrong Clerk instance, wrong env var names.
# What Windows CLI sent (invisible BOM prefix) pk_live_xxxx # What it should have been pk_live_xxxx
Delete ALL env vars from Vercel dashboard. Re-enter by typing manually — never paste via CLI. Deleted and recreated the Vercel project to bust any cached state. 8+ deploys over ~3 hours before root cause found.
The same chunk hash __0obi7ve._.js appeared across multiple deploys even after --force and project recreation. Looked like a stale build cache.
Same chunk hash surviving project deletion and forced redeploys.
Not a real problem. Chunk hash is deterministic from source content, not a build cache artifact. Same code = same hash. Stopped chasing it.
Restricting sign-ups to an approved email list requires the Clerk allowlist, which is gated behind the Pro plan. Free tier has no native way to limit who can register.
Couldn't restrict who could sign up on the free Clerk plan.
Switched to Account Portal hosted sign-in (Clerk-hosted at accounts.forgekits.build). Gives a clean auth flow without exposing the sign-up form publicly. Free tier workaround.
dotenvx wasn't overriding the system DATABASE_URL, so the seed script was pointing at the wrong database.
Seed data written to wrong Neon database.
Added --overload flag to the seed script. Forces dotenvx to override any already-set system variables.
Clerk's auth() returned a valid userId but no orgId on the first session before the user had joined an org. The app assumed orgId was always present, causing a white screen when it was null.
Blank page immediately after sign-in for new users.
Used userId directly as the tenant identifier instead of requiring org membership. Org scoping can be layered in later when multi-tenant is needed.
Framing Forge as a capability platform (contacts, messaging, workflows, AI) rather than a product made it immediately extensible. Adding a second vertical = a new config file, not new code. The architecture absorbed every new requirement without structural changes.
Schema-first development with drizzle-kit push caught type errors before runtime. Neon's serverless connection handled cold starts cleanly with no connection pooling setup required. The schema became the single source of truth from the first commit.
Having Gino the electrician as a concrete user (not a persona) shaped every decision — "Jobs" not "Pipeline", bottom nav not sidebar, mobile-first layout. The app felt real from day one because it was built for a real person in a real trade.
Once the BOM issue was identified, Vercel function logs became the primary debugging surface. Every subsequent fix had observable evidence before the next deploy. The lesson: build a /api/debug route first, before fighting 500s in prod.
Building v1 in one continuous session meant no context-switching cost, no "where were we" overhead, and a working app at the end. Momentum compounds — each piece made the next piece faster. Zero to live in one night.
PowerShell injects a U+FEFF BOM when piping secrets via vercel env add. Always use the Vercel dashboard. Type, don't paste.
Named export required: export { clerkMiddleware as proxy }. v15 and v16 have different middleware conventions — check the version before wiring any auth middleware.
Expose env var names (never values) at runtime before assuming wrong keys. Evidence first, then fix. Without it, you're guessing.
Without --overload, dotenvx silently skips variables that already exist in the environment. Always use --overload in seed and test scripts.
Account Portal (hosted at accounts.forgekits.build) gives a clean, controlled auth flow without exposing a public sign-up page. The right default until multi-tenant self-serve is ready.
Next.js 15 breaks shadcn v4 (requires React 19 / Next.js 16). Before downgrading any major dependency, map the full version dependency chain to find the actual lowest compatible floor.
| Phase | What it covers | Status |
|---|---|---|
| Phase 0 — Core CRM | Pipeline, contacts, auth, DB, demo data | ✓ Done |
| Phase 1 — Messaging | Automations, sequences, Automation Hub | ✓ Done (in this session) |
| Phase 2 — Files + AI | Photo upload (Vercel Blob), AI captions, dashboard stats | → Up next |
| Domain + Infra | forgekits.build live, Clerk production, Vercel deployed | ✓ Done |
| Phase 3 — Knowledge | Document Q&A, pgvector RAG, second vertical | Not started |
| Phase 4 — Platform | Multi-tenant, Stripe, self-service onboarding | Not started |
"Service revenue now, product revenue later, magic always."ForgeKit operating principle · Est. 2026-06-16