Skip to main content

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

  1. Keep charging on delivery, not on sale outcome, for V1.
  2. Treat assignment status sent as the billable delivery event.
  3. Ship two products:
    • exclusive: one installer assignment
    • shared: up to three installer assignments
  4. Start monthly invoicing in arrears with a delivery ledger and credit note support.
  5. Add intake-triggered auto-dispatch behind policy guards and fallback queue behavior.
  6. 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:

  1. Lead intake persistence and idempotency:
    • apps/admin/convex/leads.ts
    • submitPublicLeadIntake deduplicates by clientSubmissionKey and stores normalized lead payloads.
  2. Manual and policy-like assignment logic:
    • apps/admin/convex/routing.ts
    • Eligibility checks for installer status, region ownership, and capacity are already enforced.
  3. Path-aware assignment caps are already modeled:
    • recommended_installer routes to 1
    • compare_quotes routes up to 3
  4. Notification and audit trails exist:
    • apps/admin/convex/lib/notifications.ts
    • apps/admin/convex/schema.ts
    • emailNotificationAudits records send/fail/skip outcomes.
  5. 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:

  1. Intake-triggered auto-dispatch is live via system-safe enqueue from public lead intake.
    • apps/admin/convex/leads.ts
    • apps/admin/convex/routing.ts
  2. Billing ledger entities are implemented in schema and active workflows.
    • apps/admin/convex/schema.ts
  3. Delivery-based pricing snapshots are persisted through delivery event records.
    • apps/admin/convex/billing.ts
  4. Installer finance workflows are implemented for preview, draft generation, issue, payments, and adjustments.
    • apps/admin/convex/billing.ts

Remaining Gaps (Operational Hardening)

  1. Period-close guardrails should continue to be hardened for edge-case protection.
  2. Auto-dispatch exception triage and retry/escalation tooling should continue to improve.
  3. 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:

  1. Deep outcome attribution tied to installer-reported close data.
  2. Complex referral/recovery automation in follow-up workflows.
  3. Advanced dynamic pricing engines.
  4. 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

  1. Exclusive lead (recommended_installer):
    • one assignment only
    • premium unit price
  2. 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:

  1. It is observable in system state.
  2. It is auditable with existing assignment timeline and email audit data.
  3. 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:

  1. Successful delivery defaults to capStatus = counted.
  2. Operators may release cap usage for objective operational reasons without mutating invoice history.
  3. General credits and invoice adjustments remain finance actions, not quota actions.
  4. Lead-linked credits for objective invalid-lead faults may also auto-release cycle-cap usage.
  5. 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.

For the current stage, use a hybrid model:

  1. Keep the app as source of truth for billable delivery events.
  2. Create invoices manually in Stripe from monthly export totals.
  3. Write Stripe references back into app records for reconciliation.

Why this is the right near-term tradeoff:

  1. Faster execution with less engineering risk.
  2. Human review before invoice issuance reduces early billing mistakes.
  3. 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:

  1. stripeCustomerId on installer finance profile.
  2. stripeInvoiceId on invoice records.
  3. optional stripeInvoiceUrl for quick operator access.
  4. optional stripePaymentIntentId or external payment reference on payments.

Required Data Model Additions

Add these tables in apps/admin/convex/schema.ts:

  1. installerPricingPlans
    • installerId
    • effectiveFrom
    • effectiveTo (optional)
    • exclusivePriceCents
    • sharedPriceCents
    • currency
  2. deliveryEvents
    • one row per billable assignment delivery
    • assignmentId, leadId, installerId, deliveredAt
    • productType (exclusive | shared)
    • unitPriceCents snapshot
    • eventStatus (billable | credited | void)
    • invoiceId (optional link once invoiced)
    • stripeInvoiceId (optional)
  3. invoices
    • installerId
    • periodStart, periodEnd
    • status (draft | issued | paid | partially_paid | void)
    • subtotalCents, creditsCents, totalCents, balanceCents
    • issuedAt, dueAt, paidAt
    • stripeInvoiceId (optional)
    • stripeInvoiceUrl (optional)
  4. invoiceLineItems
    • invoiceId
    • deliveryEventId
    • description
    • quantity
    • unitPriceCents
    • lineTotalCents
  5. invoiceAdjustments
    • invoiceId
    • type (credit | debit)
    • reasonCode
    • amountCents
    • notes
  6. payments
    • invoiceId
    • amountCents
    • receivedAt
    • reference
    • method
    • externalPaymentRef (optional)

If needed, you can phase this further:

  • now: installerPricingPlans, deliveryEvents, lightweight invoices
  • later: invoiceLineItems, invoiceAdjustments, payments full automation depth

Required Backend Changes

  1. Add a system-safe auto-dispatch entrypoint:
    • internalMutation that can run auto-routing without an interactive admin actor.
    • Keep policy checks identical to existing routing rules.
  2. 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.
  3. Emit delivery event when assignment becomes sent:
    • enforce idempotency so a status flip does not double-charge.
  4. 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
  5. Add finance-safe invariants:
    • no invoice edits after issued (only adjustments)
    • immutable unit price on delivery event
    • deterministic period boundaries.

Required Admin Product Changes

  1. Installer finance settings surface:
    • set exclusive/shared prices
    • pricing effective dates
  2. Billing operations pages:
    • delivery events queue
    • invoice drafts with Stripe export-ready totals
    • issued invoices with Stripe references and reconciliation status
  3. 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)

  1. Finalize billable event rules, cap release policy, and credit policy.
  2. Add delivery event ledger and monthly per-installer export.
  3. Create Stripe invoices manually and capture Stripe invoice IDs back in app.
  4. Reconcile paid status weekly.

Phase A: Instrument Delivery Billing (No Invoice Yet)

  1. Add pricing + delivery event tables.
  2. Emit delivery events from assignment status transitions.
  3. Add read-only internal reporting for expected monthly billables.

Phase B: Invoice Generation (App-Assisted, Stripe-Issued)

  1. Generate monthly draft invoices from uninvoiced billable events.
  2. Add approval/issue action and ledger freeze in app.
  3. Support CSV export and Stripe handoff steps.

Phase C: Finance Operations (Deeper Automation)

  1. Record payments and balances.
  2. Issue credits via adjustment entries.
  3. Add overdue follow-up queue.

Phase D: Auto-Dispatch By Default

  1. Intake-triggered auto-dispatch for eligible leads.
  2. Guardrails for capacity/region/policy failures.
  3. Ops exception queue for leads requiring manual intervention.

KPI And Guardrails

Track these from day one of billing:

  1. lead-to-dispatch latency
  2. delivery success rate (pending to sent)
  3. billable deliveries by installer and product type
  4. cap releases and reason distribution
  5. credit rate and reason distribution
  6. invoice collection time (DSO proxy)

Guardrails:

  1. Every billable event must tie to exactly one assignment.
  2. No invoice line item without a delivery event.
  3. Cap release reasons must be categorized and auditable.
  4. Credit reasons must be categorized and auditable.
  5. Auto-dispatch failures must create a visible operator queue item.

Open Decisions To Lock Before Build

  1. Invoice cadence default:
    • recommended: monthly in arrears.
  2. Payment terms:
    • recommended: net 7 for small installer network.
  3. Credit SLA:
    • recommended: decide within 5 business days.
  4. Tax handling:
    • confirm GST treatment in invoice totals.
  5. Stripe workflow ownership:
    • who creates invoices, who approves, who reconciles, and the weekly cadence.
  1. Implement billing schema + delivery event write path.
  2. Add monthly installer billing export and Stripe reference capture fields/UI.
  3. Add internal auto-dispatch mutation and intake trigger.
  4. Build invoice generation mutation + admin draft list page.
  5. Add issue invoice + payment reconciliation actions.
  6. 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)

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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

  1. 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
  2. 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.
  3. 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.
  4. 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.
  5. 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 in apps/admin/src/features/installers/components/installers-list-page.tsx and apps/admin/src/features/regions/components/regions-list-page.tsx

Larger lift

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

  1. Ship quick wins first (search/filter/age/my-queue/export/presets).
  2. Then add medium-lift operational controls (bulk installer ops + dedupe + owner handoff).
  3. 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)

  1. Review dispatch exceptions in /analytics > Dispatch exceptions.
  2. Resolve expected skips and escalate unexpected failures.
  3. Capture receivables snapshot manually after reconciliation cut-off if required.
  4. Review overdue receivables in /analytics > Receivables and follow up top installers.

Weekly (ops + finance owner)

  1. Review WoW receivables trend deltas (outstanding, overdue, overdue 31+).
  2. Review open dispatch exception count trend and unresolved oldest item age.
  3. Confirm payment postings and adjustment reason-code hygiene.

Period close (monthly)

  1. Validate billing period boundaries and installer scope.
  2. Preview invoice period totals and verify unusual outliers.
  3. Generate draft invoices.
  4. Review draft ledger details and adjustment requirements.
  5. Mark issued with Stripe references and due dates.
  6. Capture post-issue receivables snapshot.

Role Hardening Baseline (Commercial Ops)

Use explicit capability separation for commercialization-sensitive actions.

  1. read_ops: read analytics and operational data.
  2. write_routing: assignment and routing lifecycle changes.
  3. manage_billing_ops: invoice generation, issue, adjustment, payment, receivables snapshots.
  4. manage_admin_access: capability and admin-user management.

Default launch policy:

  1. super_admin: all capabilities.
  2. admin: all operational capabilities including manage_billing_ops.
  3. editor: read + non-financial operational maintenance only (no billing ops).

Hardening checks before launch:

  1. Confirm only trusted operator accounts have manage_billing_ops.
  2. Confirm billing UI actions are disabled for accounts without manage_billing_ops.
  3. Confirm all billing mutations enforce manage_billing_ops server-side.