Operations Commercial Readiness Audit
This document audits current repo reality against the immediate business objective:
- auto-send leads safely
- charge installers on delivery (not sales outcome)
- run exclusive vs shared lead products with clear pricing logic
- keep operations lightweight for a small installer network
Use this as the implementation and policy source for commercialization work in the current phase.
Execution spec sheet:
Decision Summary
- Keep charging on delivery, not on sale outcome, for V1.
- Treat assignment status
sentas the billable delivery event. - Ship two products:
- exclusive: one installer assignment
- shared: up to three installer assignments
- Start monthly invoicing in arrears with a delivery ledger and credit note support.
- Add intake-triggered auto-dispatch behind policy guards and fallback queue behavior.
- Start with manual Stripe invoice creation, using app-generated delivery exports as the source of truth.
Current Reality (Good)
The backend already has strong routing foundations:
- Lead intake persistence and idempotency:
apps/admin/convex/leads.tssubmitPublicLeadIntakededuplicates byclientSubmissionKeyand stores normalized lead payloads.
- Manual and policy-like assignment logic:
apps/admin/convex/routing.ts- Eligibility checks for installer status, region ownership, and capacity are already enforced.
- Path-aware assignment caps are already modeled:
recommended_installerroutes to 1compare_quotesroutes up to 3
- Notification and audit trails exist:
apps/admin/convex/lib/notifications.tsapps/admin/convex/schema.tsemailNotificationAuditsrecords send/fail/skip outcomes.
- Activity logging is in place for operational traceability:
apps/admin/convex/activityLog.ts
These are strong prerequisites for commercialization.
Commercial Core Status (Implemented)
The previously identified commercialization gaps are now implemented in the app:
- Intake-triggered auto-dispatch is live via system-safe enqueue from public lead intake.
apps/admin/convex/leads.tsapps/admin/convex/routing.ts
- Billing ledger entities are implemented in schema and active workflows.
apps/admin/convex/schema.ts
- Delivery-based pricing snapshots are persisted through delivery event records.
apps/admin/convex/billing.ts
- Installer finance workflows are implemented for preview, draft generation, issue, payments, and adjustments.
apps/admin/convex/billing.ts
Remaining Gaps (Operational Hardening)
- Period-close guardrails should continue to be hardened for edge-case protection.
- Auto-dispatch exception triage and retry/escalation tooling should continue to improve.
- Receivables alert thresholds and recurring review cadence should be enforced operationally.
Redundant Or Defer-For-Now Work
Given current business stage, defer these until dispatch and billing are stable:
- Deep outcome attribution tied to installer-reported close data.
- Complex referral/recovery automation in follow-up workflows.
- Advanced dynamic pricing engines.
- Real-time payment gateway integration.
These are useful later, but they are not required to make delivery billing operational now.
Target Commercial Operating Model
Lead Products
- Exclusive lead (
recommended_installer):- one assignment only
- premium unit price
- Shared lead (
compare_quotes):- up to three assignments
- lower per-installer unit price
Billable Event
Bill when assignment status transitions to sent.
Why this event:
- It is observable in system state.
- It is auditable with existing assignment timeline and email audit data.
- It avoids dependence on installer honesty about won/lost outcomes.
Cap Usage Policy
Count cycle-cap usage from the same delivery event by default, but keep it separately mutable.
Rules:
- Successful delivery defaults to
capStatus = counted. - Operators may release cap usage for objective operational reasons without mutating invoice history.
- General credits and invoice adjustments remain finance actions, not quota actions.
- Lead-linked credits for objective invalid-lead faults may also auto-release cycle-cap usage.
- Every cap release must store an explicit reason.
Credit Policy
Allow credits only for strict, objective failure cases (for example duplicate dispatch defects, unsupported postcode mismatch, unreachable payload due to system fault).
Do not credit for sales outcome.
Stripe Handling (Recommended Now)
For the current stage, use a hybrid model:
- Keep the app as source of truth for billable delivery events.
- Create invoices manually in Stripe from monthly export totals.
- Write Stripe references back into app records for reconciliation.
Why this is the right near-term tradeoff:
- Faster execution with less engineering risk.
- Human review before invoice issuance reduces early billing mistakes.
- Stripe still handles payment links, reminders, and receipts.
Important guardrail:
- Stripe is the payment and invoicing system of record for collection, but not the source of truth for delivery eligibility.
Minimal Stripe Data To Store In App
Store these references once invoices are issued:
stripeCustomerIdon installer finance profile.stripeInvoiceIdon invoice records.- optional
stripeInvoiceUrlfor quick operator access. - optional
stripePaymentIntentIdor external payment reference on payments.
Required Data Model Additions
Add these tables in apps/admin/convex/schema.ts:
installerPricingPlansinstallerIdeffectiveFromeffectiveTo(optional)exclusivePriceCentssharedPriceCentscurrency
deliveryEvents- one row per billable assignment delivery
assignmentId,leadId,installerId,deliveredAtproductType(exclusive|shared)unitPriceCentssnapshoteventStatus(billable|credited|void)invoiceId(optional link once invoiced)stripeInvoiceId(optional)
invoicesinstallerIdperiodStart,periodEndstatus(draft|issued|paid|partially_paid|void)subtotalCents,creditsCents,totalCents,balanceCentsissuedAt,dueAt,paidAtstripeInvoiceId(optional)stripeInvoiceUrl(optional)
invoiceLineItemsinvoiceIddeliveryEventIddescriptionquantityunitPriceCentslineTotalCents
invoiceAdjustmentsinvoiceIdtype(credit|debit)reasonCodeamountCentsnotes
paymentsinvoiceIdamountCentsreceivedAtreferencemethodexternalPaymentRef(optional)
If needed, you can phase this further:
- now:
installerPricingPlans,deliveryEvents, lightweightinvoices - later:
invoiceLineItems,invoiceAdjustments,paymentsfull automation depth
Required Backend Changes
- Add a system-safe auto-dispatch entrypoint:
internalMutationthat can run auto-routing without an interactive admin actor.- Keep policy checks identical to existing routing rules.
- Wire post-intake dispatch trigger:
- after lead creation, enqueue auto-dispatch (sync or scheduled) when policy says eligible.
- on failure, write queue/failure record and notify ops.
- Emit delivery event when assignment becomes
sent:- enforce idempotency so a status flip does not double-charge.
- Add billing module:
- period close preview
- Stripe-ready invoice export payload
- invoice issue tracking (manual Stripe id capture)
- then later: issue/void/payment/credit full in-app operations
- Add finance-safe invariants:
- no invoice edits after issued (only adjustments)
- immutable unit price on delivery event
- deterministic period boundaries.
Required Admin Product Changes
- Installer finance settings surface:
- set exclusive/shared prices
- pricing effective dates
- Billing operations pages:
- delivery events queue
- invoice drafts with Stripe export-ready totals
- issued invoices with Stripe references and reconciliation status
- Lead and assignment detail enhancements:
- show billable status for each assignment
- show linked invoice id when billed
Rollout Plan
Phase 0: Manual Stripe Workflow (Immediate)
- Finalize billable event rules, cap release policy, and credit policy.
- Add delivery event ledger and monthly per-installer export.
- Create Stripe invoices manually and capture Stripe invoice IDs back in app.
- Reconcile paid status weekly.
Phase A: Instrument Delivery Billing (No Invoice Yet)
- Add pricing + delivery event tables.
- Emit delivery events from assignment status transitions.
- Add read-only internal reporting for expected monthly billables.
Phase B: Invoice Generation (App-Assisted, Stripe-Issued)
- Generate monthly draft invoices from uninvoiced billable events.
- Add approval/issue action and ledger freeze in app.
- Support CSV export and Stripe handoff steps.
Phase C: Finance Operations (Deeper Automation)
- Record payments and balances.
- Issue credits via adjustment entries.
- Add overdue follow-up queue.
Phase D: Auto-Dispatch By Default
- Intake-triggered auto-dispatch for eligible leads.
- Guardrails for capacity/region/policy failures.
- Ops exception queue for leads requiring manual intervention.
KPI And Guardrails
Track these from day one of billing:
- lead-to-dispatch latency
- delivery success rate (
pendingtosent) - billable deliveries by installer and product type
- cap releases and reason distribution
- credit rate and reason distribution
- invoice collection time (DSO proxy)
Guardrails:
- Every billable event must tie to exactly one assignment.
- No invoice line item without a delivery event.
- Cap release reasons must be categorized and auditable.
- Credit reasons must be categorized and auditable.
- Auto-dispatch failures must create a visible operator queue item.
Open Decisions To Lock Before Build
- Invoice cadence default:
- recommended: monthly in arrears.
- Payment terms:
- recommended: net 7 for small installer network.
- Credit SLA:
- recommended: decide within 5 business days.
- Tax handling:
- confirm GST treatment in invoice totals.
- Stripe workflow ownership:
- who creates invoices, who approves, who reconciles, and the weekly cadence.
Recommended Next Tasks (Execution Order)
- Implement billing schema + delivery event write path.
- Add monthly installer billing export and Stripe reference capture fields/UI.
- Add internal auto-dispatch mutation and intake trigger.
- Build invoice generation mutation + admin draft list page.
- Add issue invoice + payment reconciliation actions.
- Add KPI dashboard cards for delivery and receivables.
Management Nice-To-Haves Addendum
This section captures management workflow quality-of-life improvements discovered in a second repo audit. These items intentionally avoid overlap with the core commercialization work above.
Quick wins (small)
- Add leads list search and operational filters (status, path, suburb/postcode, date window).
- Why: managers can find and triage records quickly without opening detail views.
- Evidence:
apps/admin/src/features/leads/components/leads-list-page.tsx,apps/admin/convex/leads.ts
- Add "time in stage" and "age" columns on leads list.
- Why: makes SLA breaches and stale pipeline obvious at a glance.
- Evidence:
apps/admin/convex/schema.ts,apps/admin/src/features/leads/components/leads-list-page.tsx
- Add follow-up owner filter and "my queue" toggle.
- Why: helps each operator work their own queue first while preserving team view.
- Evidence:
apps/admin/convex/followUps.ts,apps/admin/src/features/follow-ups/components/follow-ups-list-page.tsx
- Add quick export actions (CSV) for leads, follow-ups, and activity feed.
- Why: simplifies client reporting and ad hoc audit pulls without manual copying.
- Evidence:
apps/admin/convex/http.ts,apps/admin/src/features/activity/components/activity-feed-page.tsx
- Add saved filter presets per user for recurring views.
- Why: removes repetitive daily filter setup for managers and coordinators.
- Evidence:
apps/admin/src/features/activity/components/activity-feed-page.tsx,apps/admin/src/features/leads/components/leads-list-page.tsx
Medium lift
- Add bulk installer operations (status change, capacity cap update, service note append).
- Why: regional or seasonal partner changes can be applied in one operation.
- Evidence: single-record update path only in
apps/admin/convex/installers.ts
- Add duplicate-lead candidate detection and merge workflow.
- Why: prevents duplicate routing and confusion when repeat submissions happen outside submission-key dedupe.
- Evidence: intake idempotency exists in
apps/admin/convex/leads.ts, but no similarity/merge workflow in admin features.
- Add manager digest email (daily/weekly) for key metrics and exceptions.
- Why: gives owners passive visibility without opening admin daily.
- Evidence: notification plumbing exists in
apps/admin/convex/lib/notifications.ts, but no scheduled digest workflow.
- Add lead ownership handoff (assign internal owner on leads, not just follow-ups).
- Why: clarifies accountability before and during routing phases.
- Evidence: follow-ups store owner fields in
apps/admin/convex/schema.ts, leads do not.
- Add region and installer operational scorecards in list/detail views.
- Why: faster partner management decisions without jumping into analytics tabs.
- Evidence: analytics data exists via
apps/admin/convex/system.ts, list pages are mostly static summaries inapps/admin/src/features/installers/components/installers-list-page.tsxandapps/admin/src/features/regions/components/regions-list-page.tsx
Larger lift
- Add policy automation for escalation actions (rule-driven nudge/critical/snooze).
- Why: reduces manual escalation queue handling as volume grows.
- Evidence: escalation actions are currently operator-triggered in
apps/admin/convex/followUps.ts
- Add security hardening for admin auth (MFA/step-up for sensitive actions).
- Why: reduces operational and client risk once finance and billing actions are live.
- Evidence: baseline auth provider config in
apps/admin/convex/auth.config.ts
Suggested sequencing after commercial core
- Ship quick wins first (search/filter/age/my-queue/export/presets).
- Then add medium-lift operational controls (bulk installer ops + dedupe + owner handoff).
- Then roll in scale controls (escalation automation + stronger auth controls).
V1 Billing And Dispatch Runbook
This is the minimum operating cadence for launch.
Daily (ops lead)
- Review dispatch exceptions in
/analytics> Dispatch exceptions. - Resolve expected skips and escalate unexpected failures.
- Capture receivables snapshot manually after reconciliation cut-off if required.
- Review overdue receivables in
/analytics> Receivables and follow up top installers.
Weekly (ops + finance owner)
- Review WoW receivables trend deltas (outstanding, overdue, overdue 31+).
- Review open dispatch exception count trend and unresolved oldest item age.
- Confirm payment postings and adjustment reason-code hygiene.
Period close (monthly)
- Validate billing period boundaries and installer scope.
- Preview invoice period totals and verify unusual outliers.
- Generate draft invoices.
- Review draft ledger details and adjustment requirements.
- Mark issued with Stripe references and due dates.
- Capture post-issue receivables snapshot.
Role Hardening Baseline (Commercial Ops)
Use explicit capability separation for commercialization-sensitive actions.
read_ops: read analytics and operational data.write_routing: assignment and routing lifecycle changes.manage_billing_ops: invoice generation, issue, adjustment, payment, receivables snapshots.manage_admin_access: capability and admin-user management.
Default launch policy:
super_admin: all capabilities.admin: all operational capabilities includingmanage_billing_ops.editor: read + non-financial operational maintenance only (no billing ops).
Hardening checks before launch:
- Confirm only trusted operator accounts have
manage_billing_ops. - Confirm billing UI actions are disabled for accounts without
manage_billing_ops. - Confirm all billing mutations enforce
manage_billing_opsserver-side.