What is an application?
A definition you can carry into every conversation.
An application is a stack of layers, each layer doing one thing well. A user clicks something on a page (top layer). That click hits an API route. The API route reads or writes data through a library function. The library function talks to the database. The database returns rows. The library shapes them. The API returns JSON. The page renders.
Most "features" are vertical slices of that stack. A good feature touches every layer cleanly. A bad feature jumps layers (like writing to the database from the browser, which we forbid).
Most "features" are vertical slices of that stack. A good feature touches every layer cleanly. A bad feature jumps layers (like writing to the database from the browser, which we forbid).
Our 8 layers, top to bottom
This is what we built. Memorize the order.
Layer 1 Pages (what the user sees)
↓
Layer 2 Components (reusable UI pieces)
↓
Layer 3 API Routes (the only path data writes flow through)
↓
Layer 4 Library code (shared TypeScript: handoff, deals, features)
↓
Layer 5 Feature Registry (which features exist + who can use them)
↓
Layer 6 Database (Supabase: outreach_campaigns, deals, spend_log...)
↑ (cron / daemons read from here too)
Layer 7 Daemons & Crons (engine/, launchagents/)
↕
Layer 8 Skills + Agents (the AI toolkit you invoke from Claude Code)
↕
Doppler (every credential, every layer)
1
Pages
What the user sees. Routes that render in the browser. The deals page, meetings page, admin dashboards.
src/app/<page>/page.tsx
Example:
src/app/deals/page.tsx renders the pipeline. src/app/meetings/page.tsx renders the call list. Pages are server components by default. Client components are marked 'use client'.2
Components
Reusable UI pieces shared across pages. Tables, dropdowns, charts, FeedbackBox.
src/components/
Example:
src/components/deals/DealsDashboard.tsx is the inline-editable pipeline table. src/components/meetings/derive.ts has the signal detection logic. Components are pure: they take props and render.3
API Routes
The only path that data writes flow through. Every mutation gets identity check, permission gate, metric recording, then does the work.
src/app/api/<path>/route.ts
Example:
PATCH /api/meetings/[id]/classify validates classification, checks canUseKey, writes to meeting_notes, records a feature_metrics event. The browser never writes to Supabase directly.4
Library code
Shared TypeScript that pages and routes import. Business logic lives here. Each lib file owns one domain.
src/lib/
handoff.ts owns Meetings to Deals promotion logic.
deals.ts owns deal stages and transitions.
circuit-breaker.ts owns budget gating.
tickets.ts owns incident detection.
classifications.ts owns the canonical taxonomy.
Read these before you write anything that touches their domains.
5
Feature Registry
Which features exist, who can use them, what status they're in. A feature without a registry entry doesn't exist in our system.
src/lib/features/
defs/meetings.ts lists Charlie's features.
defs/deals.ts lists Bear's features.
permissions.ts defines canUse() and gateReason().
metrics.ts defines recordMetric().
Every API route imports from here.
6
Database
Supabase. One project:
dwrnfpjcvydhmhnvyzov. The source of truth for everything mutable.supabase/migrations/
Key tables:
meeting_notes, deals, outreach_campaigns, campaign_targets, spend_log, feature_metrics, agent_tickets, actor_tiers, setup_status.
Schema changes go through migrations. Never edit production schema by hand.
7
Daemons + Crons
Background work. Things that run without a user clicking. Webhooks. Scheduled syncs. The Mac mini runs these.
engine/, launchagents/, scripts/
Salesfinity webhook fires when a call ends.
Fireflies sync runs nightly.
Auto-promote runs hourly.
The stuck detector runs on every API hit.
These never block the UI but they keep the system alive while you sleep.
8
Skills + Agents
The AI toolkit you invoke from Claude Code. 68 skills in the repo. Some build code. Some research. Some validate.
skills/
/architect tells you where things go.
/auto-fix debugs broken code.
/audit-quality reviews your work.
/maxswarm spins up 11 agents for hard questions.
Skills are how you punch above your weight. Use them.
How a feature spans the layers
A walkthrough using Charlie's Daily Triage as the example.
| Layer | What lives there for Daily Triage |
|---|---|
| 1. Page | src/app/meetings/triage/page.tsx renders the queue and stats. |
| 2. Components | Reuses ClassificationSelect from existing meetings page. New: TriageStatsCard. |
| 3. API Routes | Calls existing PATCH /api/meetings/[id]/classify. No new routes needed for v1. |
| 4. Library code | Imports detectRevenueSignal from derive.ts, classifications from classifications.ts. |
| 5. Feature Registry | Adds meetings.daily-triage to defs/meetings.ts at tier: 'intern'. |
| 6. Database | Reads meeting_notes. Writes only via the existing classify route. No new tables. |
| 7. Daemons | None. The page is request-driven. Future: a digest cron that emails Mark Charlie's daily classifications. |
| 8. Skills | Charlie invokes /cold-call-workflow when classifying ambiguous meetings. /audit-quality before demoing to Mark. |
The point: a feature that lives only in Layer 1 is decoration. A feature that lives only in Layer 6 is invisible. Good features span 4 to 6 layers cleanly.
What "features inside the application" means
Not buttons. Not pages. Loops.
Every feature you build is a loop. Something triggers it. It does work. Something downstream consumes the output. The trigger lives in one layer. The work spans others. The downstream consumer lives somewhere else.
Examples of how a single feature touches the stack:
- Classify a meeting: trigger (Layer 1 click) → API route (Layer 3) → permission check (Layer 5) → DB write (Layer 6) → metric recorded (Layer 5/6) → handoff evaluation (Layer 4) → if score 50+, deal created (Layer 6) → Bear's pipeline updates (Layer 1).
- Reject a warm lead: trigger (Layer 1) → API route (Layer 3) → DB writes to
meeting_notes+deal_activity_log(Layer 6) → Charlie sees the rejection on the meeting detail (Layer 1) → Charlie's classification approach adjusts (Layer 4 over time).
If your feature touches one layer and stops, you built decoration. Build loops.