Skip to content

Simple billing engine with automatic subscription rebilling

Notifications You must be signed in to change notification settings

Myuzu/guileful_charger

Repository files navigation

GuilefulCharger

For the sake of time some crucial concepts was omited, such as:

  • there will be one currency
  • no taxation handling
  • Subscribtion will always be in auto-renew state and there are no Plans
  • no user-initiated Subscribtion canceleation
  • Subscription without start/end date
  • no alternative Payment collection methods: only one PaymentMethod, it will be always active without encryption on sensative fields
  • skip on refunds logic

Some other considerations:

  • postgres pessimistic locks
  • exactly-once deliver garantee

Postgres setup (Zero RPO):

  • 1 Primary node
  • 1 Synchronous standby (for immediate failover)
  • 1-2 Asynchronous standbys (for reporting/analytics/non-critical reads)

Core entities

  • Customer

CustomerID: Unique identifier Name: Customer's name Email: Primary contact email BillingAddress: Address for billing purposes PaymentMethodId: associated payment method CreatedAt: Account creation timestamp UpdatedAt: Last update timestamp

  • Subscription

SubscriptionID: Unique identifier CustomerID: Reference to Customer Amount: Base subscription price Status: active/paused/cancelled/past_due BillingCycle: Current billing cycle number NextBillingAt: Date of next billing CreatedAt: Account creation timestamp UpdatedAt: Last update timestamp

  • Invoice

InvoiceID: Unique identifier CustomerID: Reference to Customer SubscriptionID: Reference to Subscription Amount: Total amount Status: Draft/Issued/Paid/Void/Past_Due DueDate: Payment due date IssuedAt: When invoice was issued PaidAt: When invoice was paid BillingPeriod: Start and end dates for billing period CreatedAt: Account creation timestamp

  • Payment

PaymentID: Unique identifier InvoiceID: Reference to Invoice CustomerID: Reference to Customer Amount: Payment amount Status: pending/completed/failed TransactionID: External payment processor transaction ID PaidAt: When payment was processed FailureReason: Description of failure CreatedAt: Account creation timestamp

  • PaymentMethod

PaymentMethodID: Unique identifier CustomerID: Reference to Customer Name: PaymentMethod's name LastUsedAt: When method was last used FailureCount: Number of payment failures CreatedAt: Account creation timestamp UpdatedAt: Last update timestamp

  • AuditLog

LogID: Unique identifier EntityType: Type of entity (Subscription/Payment/Invoice) EntityID: ID of the affected entity Action: Created/Updated/Deleted/Status Change Changes: What was changed CreatedAt: When change occurred

  • RebillingStrategy

MaxRetries: Maximum number of retry attempts RetryIntervals: Array of intervals between retries FailureActions: Actions to take on failure NotificationRules: When to notify customer/admin GracePeriod: Additional time before subscription suspension EscalationRules: When to escalate failed payments

Relationships

Primary Relationships

Customer -> Subscriptions (1:N) Subscription -> Invoices (1:N) Invoice -> Payments (1:N) Customer -> PaymentMethods (1:1)

Secondary Relationships

Payment -> PaymentMethod (N:1) Invoice -> AuditLog (1:N) Subscription -> AuditLog (1:N) Payment -> AuditLog (1:N)

Main Rebilling Logic:

  • First, try to charge the full subscription amount
  • If the bank responds with "insufficient funds," attempt to charge 75%, 50%, and 25% of the amount
  • A maximum of 4 attempts is allowed for each rebill after success payment

About

Simple billing engine with automatic subscription rebilling

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published