Automations, test suite, brand identity system, splash page, and settings. Phase 0 + Phase 1 complete.
| Phase | What it covers | Status |
|---|---|---|
| Phase 0 — Core CRM | Pipeline, contacts, auth, DB, demo data | ✓ Done |
| Phase 1 — Messaging | Twilio, Inngest sequences, Automation Hub | ✓ Done (1 gap) |
| Phase 1 gap | Inbound reply → note on deal + stop sequence | ⚠ Next session |
| Prod env vars | TWILIO + INNGEST keys needed in Vercel for live SMS | ⚠ Next session |
| Phase 2 — Files + AI | Photo upload (Vercel Blob), AI captions, dashboard stats | → Up next |
| Phase 3 — Knowledge | Document Q&A, pgvector RAG, second vertical | Not started |
| Phase 4 — Platform | Multi-tenant, Stripe, self-service onboarding | Not started |
The triggers array moved from a separate second argument into the first options object. TypeScript caught it at build time.
// v3 — broken in v4 createFunction({ id, name }, [{ event: 'forge/x' }], handler) // v4 — correct createFunction({ id, name, triggers: [{ event: 'forge/x' }] }, handler)
Rewrote all 3 sequence functions with the correct signature.
Vitest hoists vi.mock() calls at compile time, but only when they appear at the top level of a test file. Wrapping them in a helper function (mockUnauthenticated()) meant they ran at call time, after the real mock had already been set, overriding it.
Moved all vi.mock calls to the top level of each test file directly.
Multiple test files seeding the same org concurrently caused duplicate primary key violations on pipeline_stages.
Added fileParallelism: false to vitest.config.ts. Sequential file execution eliminates the conflict.
dotenvx run -f .env.test won't set a variable that already exists in the environment. The system had DATABASE_URL pointing at prod.
Added --overload flag to all test scripts. Forces .env.test values regardless of existing env.
When the test org was deleted by slug (not by ID), pipeline_stages rows with fixed UUIDs remained. Re-inserting those UUIDs on the next run caused PK conflicts.
Seed helper now explicitly deletes by inArray(pipelineStages.id, FIXED_STAGE_IDS) before deleting the org.
Next.js 16 picks up all .ts files in the project via its tsconfig glob. Vitest types don't match the Next.js compiler config — caused build failures.
Added vitest.config.ts, playwright.config.ts, and tests/** to tsconfig.json exclude array.
The FORGEKIT splash PNG has a large wordmark in the lower half that competed with the page headline. The initial overlay (opacity-60 + from-black/40) wasn't strong enough.
Dropped image to opacity-30 and added a solid bg-[#0D1117]/70 overlay layer on top.
The 1920×1080 desktop splash crops badly on portrait/mobile screens — text cut off on both sides.
Used the forgekit-splash-mobile-1170x2532.png from the identity pack. Responsive swap via md:hidden / hidden md:block.
The event-driven model is exactly right. Stage change fires an event, Inngest function handles sequencing and retries. step.sleep() for multi-day delays is clean and durable. Zero cron configuration needed.
Settings save, automation toggle, step template edit — all use server actions. No API route boilerplate. Form submit → action → revalidatePath → done. Clean and fast to write.
Using the actual Neon database (not mocks) caught real constraint violations and orphan FK issues that mocks would have hidden. Sequential execution is acceptable given the correctness gains.
Having SVGs, PNGs, feature cards, favicons, and brand tokens all organized with claude-implementation-notes.md made the splash page fast to build and consistent throughout.
All slides rendered with position:absolute, active at opacity:1, others at opacity:0. CSS transition-opacity handles the fade. SSR-compatible, works with Next.js Image, no external dependency.
Correctly separating the business owner's personal cell (where Forge sends alerts) from the Twilio outbound number (what customers receive texts from) is the right data model — two different directions of communication.
triggers is inside the first object argument, not a separate array. Always check Inngest docs before writing createFunction.
Never wrap vi.mock in a helper function — it won't hoist. Put it at the top of each test file directly.
Without --overload, dotenvx won't override an already-set DATABASE_URL. Always use --overload in test scripts.
Any test suite hitting a shared database needs fileParallelism: false. Parallel seed operations cause PK conflicts.
Add vitest.config.ts, playwright.config.ts, and tests/** to tsconfig.json exclude. Next.js 16 will otherwise type-check them and fail the build.
step.sleep('label', '72h') creates a durable checkpoint. No process held, retries managed by Inngest. Raw cron would require scanning the full message log on every tick.