ForgeKitFORGEKIT

Build Log

Forge: The Handling Engine

June 21, 2026

Forge grew a brainstem — a handling engine that tells you exactly what to do next, Today view replacing Dashboard, mobile-first cards, attention-aware pipeline, and call workflow wiring.

ForgeUXMobileHandlingTwilio
1
handling engine (lib/forge/handling.ts)
1
Today view replacing Dashboard/Inbox
1
call workflow wired (90s delay, cancelOn)
4
mobile layout spins fixed
2
unit test files added

Timeline

Start
Mobile layout spins
Dashboard overflow, stat cards, horizontal scroll — fixed in sequence
30m
Call workflow
Twilio <Dial> forward, 90s Inngest delay, answeredCallDisposition, forge/lead.handled cancelOn
1hr
Auth + Twilio URL fix
getTenantId fallback removed, Twilio webhook URL built from NEXT_PUBLIC_APP_URL
1.5hr
Unit tests
auth.test.ts + twilioSignature.test.ts, fixed @/ alias resolution in vitest.config.ts
2hr
moveDeal triggerEvent decoupling
Stage names no longer drive Inngest events — triggerEvent column on pipeline_stages
2.5hr
Handling engine + Today view
lib/forge/handling.ts, TodayCard, attention-aware DealCard, Customers page, nav rename
Done
Forge v2 committed
All changes in forge/ subrepo

What shipped

lib/forge/handling.ts — getHandlingState(), getPrimaryActions(), extractMemoryText(), TONE_COLORS — pure functions, no DB writes

TodayCard component — vertical mobile layout, handling state badge always visible, contextual primary actions, Done/Snooze secondary

Today page — replaces Dashboard/Inbox/Home everywhere (nav, page title, dynamic date header)

Pipeline page — fetches most important active event per deal, passes handling + primaryActions into DealCard

DealCard — attention panel with handling label + primary action buttons when active event exists

Customers page (was Contacts) — active deals ordered by createdAt desc, excludes Paid/Complete, memory snippets via extractMemoryText()

ContactsList — client component with live search + memory snippet (violet, italic)

Call workflow — Twilio <Dial> forward to owner_phone, outcome callback to /api/webhooks/twilio/call-status

missedCallSms Inngest function — 90s delay, cancelOn forge/lead.handled so Gino calling back prevents awkward missed-call text

answeredCallDisposition — texts Gino after answered call asking what happened (new estimate / scheduled / not a lead)

leadStatus column on deals — new_lead → missed_call_queued → missed_call_sent → contacted / not_a_lead / awaiting_reply

forge/lead.handled fires on: stage move, markContacted, markNotALead, customer SMS reply

Needs Contact section on dashboard — unhandled missed calls with Got it / Not a lead one-tap buttons

getTenantId(): removed hardcoded fallback — missing org now redirects to sign-in

Twilio webhook: URL built from NEXT_PUBLIC_APP_URL (req.url is relative on Vercel)

vitest.config.ts: resolve.tsconfigPaths fixes @/ alias resolution

tests/unit/auth.test.ts — covers no-org-fallback case

tests/unit/twilioSignature.test.ts — covers URL construction logic

moveDeal: triggerEvent column on pipeline_stages — stage display names no longer drive Inngest events

migration 0005_thin_leader.sql — ALTER TABLE pipeline_stages ADD COLUMN trigger_event

Dashboard: compact Needs Contact list — one row per lead, no dead space

Multiple mobile layout fixes: overflow, stat card wrap, min-w-0 on flex children, height constraints removed

Deleted orphaned EventActions.tsx and LeadActions.tsx

PrimaryActionButton shared component in components/forge/ used by TodayCard and DealCard

Forge grew a brainstem. It now knows what to do — not just what happened.

The handling engine — lib/forge/handling.ts