Build Log · June 21, 2026

Forge: The Handling Engine

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.

  • Forge
  • UX
  • Mobile
  • Handling
  • Twilio
handling engine (lib/forge/handling.ts)
1

handling engine (lib/forge/handling.ts)

Today view replacing Dashboard/Inbox
1

Today view replacing Dashboard/Inbox

call workflow wired (90s delay, cancelOn)
1

call workflow wired (90s delay, cancelOn)

mobile layout spins fixed
4

mobile layout spins fixed

unit test files added
2

unit test files added

Timeline

  1. Start

    Mobile layout spins

    Dashboard overflow, stat cards, horizontal scroll — fixed in sequence

  2. 30m

    Call workflow

    Twilio <Dial> forward, 90s Inngest delay, answeredCallDisposition, forge/lead.handled cancelOn

  3. 1hr

    Auth + Twilio URL fix

    getTenantId fallback removed, Twilio webhook URL built from NEXT_PUBLIC_APP_URL

  4. 1.5hr

    Unit tests

    auth.test.ts + twilioSignature.test.ts, fixed @/ alias resolution in vitest.config.ts

  5. 2hr

    moveDeal triggerEvent decoupling

    Stage names no longer drive Inngest events — triggerEvent column on pipeline_stages

  6. 2.5hr

    Handling engine + Today view

    lib/forge/handling.ts, TodayCard, attention-aware DealCard, Customers page, nav rename

  7. 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