@company-manager/docs

Subscription Lifecycle

State machine and sequence diagrams for subscription management

Subscription Lifecycle

This page details the complete subscription lifecycle from initial signup through renewal, pause, and cancellation.

Subscription State Machine

stateDiagram-v2
    [*] --> PENDING: Create Subscription

    PENDING --> TRIALING: Start Trial
    PENDING --> ACTIVE: Payment Success (no trial)
    PENDING --> CANCELLED: Payment Failed / User Cancels

    TRIALING --> ACTIVE: Trial Ends + Payment Success
    TRIALING --> CANCELLED: Trial Ends + Payment Failed
    TRIALING --> CANCELLED: User Cancels During Trial

    ACTIVE --> PAUSED: User Pauses
    ACTIVE --> PAST_DUE: Payment Failed
    ACTIVE --> CANCELLED: User Cancels
    ACTIVE --> EXPIRED: End Date Reached

    PAUSED --> ACTIVE: Resume
    PAUSED --> CANCELLED: Cancel While Paused

    PAST_DUE --> ACTIVE: Payment Retry Success
    PAST_DUE --> CANCELLED: Max Retries Exceeded

    EXPIRED --> ACTIVE: Renew
    EXPIRED --> CANCELLED: No Renewal

    CANCELLED --> [*]
    EXPIRED --> [*]

    note right of TRIALING
        Free trial period
        No payment yet
    end note

    note right of PAST_DUE
        Payment failed
        Retry in progress
    end note

    note right of PAUSED
        Temporary hold
        Can resume
    end note

Status Descriptions

StatusDescriptionActions Available
PENDINGCreated, awaiting initial paymentPay, Cancel
TRIALINGIn free trial periodUse service, Cancel
ACTIVEPaid and activeUse service, Pause, Cancel, Upgrade
PAUSEDTemporarily suspendedResume, Cancel
PAST_DUEPayment failed, retryingUpdate payment, Cancel
CANCELLEDTerminated by user or systemResubscribe
EXPIREDEnd date reachedRenew, Resubscribe

Subscription Signup Sequence

sequenceDiagram
    participant User
    participant UI as Frontend
    participant API as TRPC Router
    participant Service as Subscription Service
    participant Stripe as Stripe API
    participant DB as Database
    participant Email as Email Service

    User->>UI: Select subscription plan
    UI->>API: createSubscription(planId, paymentMethodId)
    API->>Service: initiateSubscription(ctx, input)

    Service->>DB: Get plan details
    DB-->>Service: Plan data

    Service->>DB: Get or create contact
    DB-->>Service: Contact

    alt Plan has trial
        Service->>Stripe: Create subscription (trial)
        Stripe-->>Service: Subscription (trialing)
        Service->>DB: Create subscription (TRIALING)
    else No trial
        Service->>Stripe: Create subscription
        Stripe-->>Service: Subscription (active)
        Service->>DB: Create subscription (ACTIVE)
    end

    DB-->>Service: Subscription created

    Service->>Email: sendWelcomeEmail(subscription)
    Email-->>Service: Queued

    Service-->>API: Subscription result
    API-->>UI: Success
    UI-->>User: Welcome screen

Trial to Active Transition

sequenceDiagram
    participant Stripe as Stripe
    participant Webhook as Webhook Handler
    participant Service as Subscription Service
    participant DB as Database
    participant Email as Email Service
    participant User

    Note over Stripe: Trial period ends

    Stripe->>Stripe: Attempt first charge
    Stripe->>Webhook: customer.subscription.updated

    Webhook->>Service: handleSubscriptionUpdate(event)
    Service->>DB: Find subscription by stripeId
    DB-->>Service: Subscription

    alt Payment successful
        Service->>DB: Update status (ACTIVE)
        Service->>DB: Set nextBillingDate
        Service->>Email: sendTrialEndedSuccess(subscription)
        Email->>User: "Your subscription is now active"
    else Payment failed
        Service->>DB: Update status (PAST_DUE)
        Service->>Email: sendPaymentFailed(subscription)
        Email->>User: "Payment failed - please update"
    end

    Service-->>Webhook: Handled

Pause Subscription Flow

flowchart TD
    REQUEST[User Requests Pause] --> VALIDATE{Validate Request}

    VALIDATE -->|Invalid| REJECT[Reject - Show Reason]
    VALIDATE -->|Valid| CHECK_LIMITS{Within Pause Limits?}

    CHECK_LIMITS -->|No| REJECT_LIMIT[Reject - Max Pauses Reached]
    CHECK_LIMITS -->|Yes| SELECT_DATES[Select Pause Period]

    SELECT_DATES --> CONFIRM[Confirm Pause]
    CONFIRM --> STRIPE[Update Stripe Subscription]
    STRIPE --> DB[Create Pause Record]
    DB --> ADJUST[Adjust Next Billing Date]
    ADJUST --> NOTIFY[Send Confirmation Email]

    NOTIFY --> PAUSED[Subscription Paused]

    style PAUSED fill:#fff3e0

Pause Sequence

sequenceDiagram
    participant User
    participant API as TRPC Router
    participant Service as Subscription Service
    participant Stripe as Stripe API
    participant DB as Database

    User->>API: pauseSubscription(subscriptionId, dates)
    API->>Service: pauseSubscription(id, pauseStart, pauseEnd)

    Service->>DB: Get subscription
    DB-->>Service: Subscription

    Service->>Service: Validate pause request
    Note over Service: Check: status, limits, dates

    Service->>Stripe: Update subscription (pause collection)
    Stripe-->>Service: Updated

    Service->>DB: Create SubscriptionPause record
    Service->>DB: Update subscription status (PAUSED)
    Service->>DB: Calculate new billing date

    DB-->>Service: Updated

    Service-->>API: Pause confirmed
    API-->>User: Success

Resume Subscription Flow

sequenceDiagram
    participant User
    participant API as TRPC Router
    participant Service as Subscription Service
    participant Stripe as Stripe API
    participant DB as Database
    participant Email as Email Service

    User->>API: resumeSubscription(subscriptionId)
    API->>Service: resumeSubscription(id)

    Service->>DB: Get subscription + pause record
    DB-->>Service: Data

    Service->>Service: Calculate billing adjustment
    Note over Service: Extend end date by pause duration

    Service->>Stripe: Resume collection
    Stripe-->>Service: Updated

    Service->>DB: Update pause record (ended)
    Service->>DB: Update subscription (ACTIVE)
    Service->>DB: Update billing dates

    Service->>Email: sendResumeConfirmation(subscription)

    Service-->>API: Resume confirmed
    API-->>User: Success

Upgrade/Downgrade Flow

flowchart TD
    REQUEST[Change Plan Request] --> COMPARE{Compare Plans}

    COMPARE -->|Upgrade| PRORATE_UP[Calculate Prorated Charge]
    COMPARE -->|Downgrade| PRORATE_DOWN[Calculate Credit]
    COMPARE -->|Same Tier| REJECT[No Change Needed]

    PRORATE_UP --> CHARGE[Charge Difference]
    CHARGE --> UPDATE[Update Plan]

    PRORATE_DOWN --> CREDIT[Apply Credit]
    CREDIT --> UPDATE

    UPDATE --> STRIPE[Update Stripe]
    STRIPE --> DB[Update Database]
    DB --> EMAIL[Send Confirmation]

    EMAIL --> COMPLETE[Plan Changed]

    style COMPLETE fill:#e8f5e9

Plan Change Sequence

sequenceDiagram
    participant User
    participant API as TRPC Router
    participant Service as Subscription Service
    participant Stripe as Stripe API
    participant DB as Database

    User->>API: changePlan(subscriptionId, newPlanId)
    API->>Service: changePlan(id, newPlanId)

    Service->>DB: Get current subscription
    Service->>DB: Get new plan
    DB-->>Service: Both records

    Service->>Service: Calculate proration

    alt Upgrade (higher price)
        Service->>Stripe: Update subscription (prorate)
        Note over Stripe: Creates prorated invoice
        Stripe-->>Service: Invoice + updated subscription
        Service->>Stripe: Pay invoice immediately
    else Downgrade (lower price)
        Service->>Stripe: Update subscription (credit)
        Note over Stripe: Applies credit to account
        Stripe-->>Service: Updated subscription
    end

    Service->>DB: Update subscription (new plan)
    Service->>DB: Log plan change

    Service-->>API: Plan changed
    API-->>User: New plan active

Subscription Timeline

gantt
    title Subscription Lifecycle Example
    dateFormat YYYY-MM-DD
    axisFormat %b %d

    section Trial
    Trial Period           :active, trial, 2024-01-01, 14d

    section Active
    First Billing Cycle    :active, cycle1, after trial, 30d
    Second Billing Cycle   :cycle2, after cycle1, 30d
    Third Billing Cycle    :cycle3, after cycle2, 30d

    section Pause
    Paused Period          :crit, pause, after cycle3, 14d

    section Resume
    Fourth Billing Cycle   :cycle4, after pause, 30d

Grace Period Handling

stateDiagram-v2
    ACTIVE --> PAYMENT_FAILED: Invoice fails
    PAYMENT_FAILED --> GRACE_PERIOD: Enter grace period

    state GRACE_PERIOD {
        [*] --> DAY_1: Start
        DAY_1 --> DAY_3: Retry 1 fails
        DAY_3 --> DAY_7: Retry 2 fails
        DAY_7 --> DAY_14: Retry 3 fails
        DAY_14 --> END: Final retry
    }

    GRACE_PERIOD --> ACTIVE: Payment succeeds
    GRACE_PERIOD --> CANCELLED: All retries fail