GMI · TECHNOLOGY OBSERVATORY // ALL SYSTEMS NOMINAL
ENGINEERED BY LEOPARD DATA

Billing & Subscription Architecture

A Stripe-backed, storage-usage billing engine built around a durable job queue, a safe two-pass preview-then-charge workflow, and idempotency guards that make double-billing structurally impossible.

TWO-PASS QUEUE FLOW
rendering diagram…
flowchart TB
    A([Admin enqueues run]):::app
    Q[(BillingRun queue<br/>Status Queued)]:::data
    P[Console poll-queue<br/>ClaimNextQueuedRunAsync<br/>atomic claim - Running]:::svc
    PV[Preview pass<br/>read-only - no charges]:::svc
    CSV[(CSV export)]:::data
    CH[Charge pass<br/>idempotency guard<br/>one charge per account]:::svc
    ST[Stripe<br/>tokenized cards<br/>last4 plus brand]:::ext
    INV[(Invoices plus DB commit)]:::data
    BRA[(BillingRunAccount<br/>Success - Failed<br/>Skipped - NoCharges)]:::data
    FPR[(FailedPaymentReconciliation<br/>Stripe ok - DB write failed<br/>manual resolution)]:::sec
    DONE([Status Complete]):::app
    A --> Q
    Q -->|poll| P
    P --> PV
    PV --> CSV
    PV --> CH
    CH --> ST
    ST -->|charge ok| INV
    INV --> BRA
    ST -->|charged but DB write fails| FPR
    BRA --> DONE
classDef app fill:#1f2630,stroke:#C0894E,color:#F3EFE8;
classDef svc fill:#241c14,stroke:#E2B583,color:#F3EFE8;
classDef data fill:#22201a,stroke:#C0894E,color:#EBD3AE;
classDef ext fill:#1b1f27,stroke:#5A616B,color:#C4C0B8;
classDef sec fill:#1d2733,stroke:#5cc8e0,color:#eafaff;
An admin enqueues a billing run; the console claims it atomically, runs a read-only preview pass, then a charge pass that commits to the database and Stripe, recording per-account outcomes and reconciling any partial failures.

Stripe & Storage-Based Pricing

The billing engine charges customers through Stripe (Stripe.net v46.2.0) based on how much storage each file consumes over time.

charge = days_stored × file_size_GB × daily_rate  (per file)
  • Per-file storage usage pricing
  • Honors free-tier and coupon-covered ($0) charges
  • Accounts for soft-deleted files
Card Data Never Stored

Cards are tokenized by Stripe. Grade My Investments persists only the last4 digits and card brand for display, never raw card numbers. Billing applies to paid-tier (card-on-file) accounts only — free-tier usage records a $0 charge carrying internal cost for analytics and is never invoiced.

Two-Pass Billing

Every billing run is split into two distinct passes so totals can be inspected before a single dollar moves.

Pass 1 — Preview
  • Read-only, no charges
  • CSV export of computed charges
  • Auditable before committing
Pass 2 — Charge
  • Commits charges to the database
  • Calls Stripe to bill customers
  • Records per-account outcomes

Durable Queue

The BillingRun table doubles as a durable job queue, decoupling the admin who triggers a run from the console worker that executes it.

  1. Admin enqueues a billing run
  2. Console polls the queue for work
  3. ClaimNextQueuedRunAsync atomically claims the next run
  4. Status advances Queued Running Complete

Idempotency & Safety

  • No double-billing a period. HasSuccessfulBillingRunForPeriodAsync(year, month) blocks repeat runs for the same period.
  • One charge per job per account. Each account is charged at most once within a run.
  • One-time coupon use. Coupons are consumed a single time.

Failed Payment Reconciliation

The hardest case is a partial success: Stripe charges the customer but the database write that records it fails. The FailedPaymentReconciliation table captures exactly this scenario.

  • Stripe success + DB write failure is captured, not lost
  • Preserved for manual resolution
  • Prevents silent revenue or audit gaps

Per-Account Auditing

BillingRunAccount rows record the outcome of each account within a run, with an invoice id or error message for drill-down.

Success Failed Skipped NoCharges

CLI Commands

Command Pass Purpose
billing-report Preview Read-only preview with CSV export, no charges
charge Charge Run the monthly charge pass
charge-account Charge Retry a single account
poll-queue Primary Poll the BillingRun queue and process claimed runs

Implemented across Gmi.BillingEngine.Console and the BillingService in Gmi.Services.