Operations & ops
The least-visible product domain and arguably the most operationally critical. Six controllers covering billing, expert compensation, contractual paperwork, and internal support tickets.
What it covers
- Client invoicing — invoices to corporate clients for completed boards. Generated from board-status transitions; sent via the email layer; tracked through paid/overdue lifecycle.
- Expert payouts — historically the most-changed area. Currently routes payments through Stripe Connect. Previously (and dormantly) supported Gnosis Safe multi-sig.
- Legal / NDA tracking — per-board NDA acceptance records. The flow is dormant but the data model still expects rows.
- Support tickets — an in-Treehouse ticket queue that overlaps with but is separate from the email-reply parsing in Treehouse → Prospects.
- Account-rotation health — dashboards for the SMTP-account rotation used in outreach, including bounce rates and suspension status per account.
Representative routes
| Method | Path | Handler | Notes |
|---|---|---|---|
| GET | /admin/ops/invoices | InvoiceController.list | Filter by client, status, fiscal quarter. |
| POST | /admin/ops/invoices/:id/send | InvoiceController.send | Queues invoice email; marks sent. |
| POST | /admin/ops/invoices/:id/mark-paid | InvoiceController.markPaid | Status transition + ledger entry. |
| GET | /admin/ops/payouts | PayoutController.list | Pending and historical expert payouts. |
| POST | /admin/ops/payouts/:id/run | PayoutController.run | Triggers Stripe Connect transfer. |
| GET | /admin/ops/legal/ndas | NdaController.list | Dormant; no recent entries. |
| GET | /admin/ops/tickets | TicketController.list | Internal support queue. |
| POST | /admin/ops/tickets/:id/reply | TicketController.reply | Sends email reply; logs internal note. |
| GET | /admin/ops/email-health | EmailHealthController.dashboard | SMTP account rotation health. |
Headline flow: board close → invoice → expert payout
Step 1: Treehouse staff closes a board (BoardController.close).
Step 2: A close hook fires InvoiceController.draftFromBoard:
- Reads board.client_id, board.contracted_amount.
- Creates an invoice row in 'draft' status.
- Allocates expert compensation per participation rules
into per-expert payout rows in 'pending' status.
Step 3: Staff reviews draft at /admin/ops/invoices/:id, makes line-item
adjustments if needed, then POST .../send.
Step 4: dispenserd lane `send_email` queues the invoice email
(PDF attachment generated on the fly).
Step 5: Client pays → finance marks invoice paid via
POST /admin/ops/invoices/:id/mark-paid.
Step 6: Marking paid auto-flips associated expert payout rows from
'pending' to 'ready'.
Step 7: Weekly cron sweeps 'ready' payouts and runs
PayoutController.run on each — Stripe Connect transfer, status
transitions to 'sent'.
Step 8: Expert receives funds; receipt email goes out.