Billing Schema
Purpose
Lumie has two billing models with different data boundaries. Platform billing tracks Lumie charging academies for the SaaS product. Tuition billing tracks an academy charging guardians or students. The ERDs separate those models so schema changes do not accidentally mix platform control-plane records with tenant-owned tuition records.
Source Paths
| Path | Role |
|---|---|
lumie-backend/app/src/main/resources/db/migration/public/V28__billing_platform_tables.sql | Platform billing tables and the initial payment_transactions audit table |
lumie-backend/app/src/main/resources/db/migration/public/V29__tuition_tenant_tables.sql | Tuition billing tables, JSON columns, and tenant RLS |
lumie-backend/app/src/main/resources/db/migration/public/V31__billing_add_missing_columns.sql | Syncs payment_transactions.type comments to the current enum names |
lumie-backend/app/src/main/resources/db/migration/public/V33__billing_keys_add_customer_key.sql | Toss customer key support |
lumie-backend/app/src/main/resources/db/migration/public/V34__seed_plans.sql | Initial plan data |
lumie-backend/app/src/main/resources/db/migration/public/V35__backfill_free_subscriptions.sql | Default subscription backfill |
lumie-backend/app/src/main/resources/db/migration/public/V37__subscription_scheduled_changes.sql | Scheduled subscription changes |
lumie-backend/app/src/main/resources/db/migration/public/V38__create_billing_operation_locks.sql | Billing operation lock table |
lumie-backend/modules/billing/src/main/java/com/lumie/billing/domain/entity/PaymentTransaction.java | Current JPA mapping for audit rows |
lumie-backend/modules/tuition/src/main/java/com/lumie/tuition/domain/entity/TuitionInvoice.java | Current JPA mapping for tuition invoices |
Platform Billing ERD
Platform billing tables are cross-tenant Lumie records. They reference tenants, but they are not tenant RLS tables. Access control belongs to backend authorization and billing workflows.
Tenant Tuition ERD
Tuition tables are tenant-owned academy records. They must keep tenant_id,
tenant-safe indexes, and RLS. Some relations are semantic rather than strict
database FKs when hard coupling would cross module ownership boundaries.
Audit And Idempotency
payment_transactions is append-only audit data. Normal billing code should add
audit rows for requests, responses, and webhooks rather than mutating history.
Verification
cd /path/to/Lumie
rg -n "total_amount|items|idempotency_key|order_id|pg_payload|billing_operation_locks" \
lumie-backend/app/src/main/resources/db/migration/public/V28__billing_platform_tables.sql \
lumie-backend/app/src/main/resources/db/migration/public/V29__tuition_tenant_tables.sql \
lumie-backend/app/src/main/resources/db/migration/public/V38__create_billing_operation_locks.sql
Expected success signal: tuition_invoices exposes items, total_amount,
status, and idempotency_key; payment_transactions exposes pg_payload
and idempotency_key; billing_operation_locks exposes its per-tenant lock
state.
cd /path/to/Lumie
rg -n "SUBSCRIPTION_CHARGE|SUBSCRIPTION_REFUND|ALIMTALK_RECHARGE|BILLING_KEY_ISSUE|BILLING_KEY_REVOKE" \
lumie-backend/app/src/main/resources/db/migration/public/V31__billing_add_missing_columns.sql \
lumie-backend/modules/billing/src/main/java/com/lumie/billing/domain/vo/TransactionType.java
Expected success signal: the search shows the live contract drift explicitly.
V31 mentions TAX_INVOICE_ISSUE, while the checked-in Java enum does not.
Change Checklist
- Decide whether the change is platform billing or tenant tuition.
- Use RLS only for tenant tuition tables, not platform subscription tables.
- Preserve idempotency for external payment calls.
- Add or update audit writes when a new PG interaction is introduced.
- Keep tenant tuition references tenant-safe even when using soft references.