빌링 스키마
목적
Lumie에는 데이터 경계가 다른 두 가지 과금 모델이 있습니다. 플랫폼 과금은 Lumie가 학원에 SaaS 제품 비용을 청구하는 흐름을 추적합니다. 수강료 과금은 학원이 보호자 또는 학생에게 청구하는 흐름을 추적합니다. 이 ERD는 스키마 변경이 플랫폼 제어 평면 레코드와 테넌트 소유 수강료 레코드를 실수로 섞지 않도록 두 모델을 분리해 보여줍니다.
소스 경로
| 경로 | 역할 |
|---|---|
lumie-backend/app/src/main/resources/db/migration/public/V28__billing_platform_tables.sql | 플랫폼 과금 테이블과 초기 payment_transactions 감사 테이블 |
lumie-backend/app/src/main/resources/db/migration/public/V29__tuition_tenant_tables.sql | 수강료 과금 테이블, JSON 컬럼, 테넌트 RLS |
lumie-backend/app/src/main/resources/db/migration/public/V31__billing_add_missing_columns.sql | payment_transactions.type 주석을 현재 enum 이름과 동기화 |
lumie-backend/app/src/main/resources/db/migration/public/V33__billing_keys_add_customer_key.sql | Toss customer key 지원 |
lumie-backend/app/src/main/resources/db/migration/public/V34__seed_plans.sql | 초기 플랜 데이터 |
lumie-backend/app/src/main/resources/db/migration/public/V35__backfill_free_subscriptions.sql | 기본 subscription backfill |
lumie-backend/app/src/main/resources/db/migration/public/V37__subscription_scheduled_changes.sql | 예약된 subscription 변경 |
lumie-backend/app/src/main/resources/db/migration/public/V38__create_billing_operation_locks.sql | billing 작업 lock 테이블 |
lumie-backend/modules/billing/src/main/java/com/lumie/billing/domain/entity/PaymentTransaction.java | audit 행의 현재 JPA 매핑 |
lumie-backend/modules/tuition/src/main/java/com/lumie/tuition/domain/entity/TuitionInvoice.java | tuition invoice의 현재 JPA 매핑 |
플랫폼 빌링 ERD
platform billing 테이블은 cross-테넌트 Lumie 레코드입니다. tenant를 참조하지만 테넌트 RLS 테이블은 아닙니다. 접근 제어는 백엔드 권한 부여와 billing 워크플로가 담당합니다.
테넌트 수강료 ERD
tuition 테이블은 테넌트 소유 학원 레코드입니다. tenant_id, 테넌트-safe 인덱스, RLS를 유지해야 합니다. 일부 관계는 hard 결합이 모듈 소유권 경계를 넘을 때 엄격한 DB FK가 아니라 의미적 관계로 남습니다.
감사 및 멱등성
payment_transactions는 append-only audit 데이터입니다. 일반 billing 코드는 이력을 수정하는 대신 요청, 응답, webhook에 대한 audit 행을 추가해야 합니다.
검증
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
예상 성공 신호: tuition_invoices에 items, total_amount, status, idempotency_key가 있고, payment_transactions에 pg_payload와 idempotency_key가 있으며, billing_operation_locks가 tenant별 lock 상태를 노출합니다.
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
예상 성공 신호: 검색 결과가 현재의 라이브 계약 드리프트를 명시적으로 보여줍니다. V31은 TAX_INVOICE_ISSUE를 언급하지만, 체크인된 Java enum에는 없습니다.
변경 체크리스트
- 변경이 platform billing인지 테넌트 tuition인지 결정합니다.
- platform subscription 테이블이 아니라 테넌트 tuition 테이블에만 RLS를 사용합니다.
- 외부 결제 호출의 idempotency를 유지합니다.
- 새로운 PG 상호작용을 도입하면 audit write를 추가하거나 갱신합니다.
- soft reference를 쓰더라도 테넌트 tuition 참조는 테넌트-safe하게 유지합니다.