docs/architecture/user-billing-admin.md

User, Billing, And Admin

This slice covers Cognito registration, profile/tank data, tank-level target ranges, Stripe, free Pro grants, admin configuration, admin costs, and support tooling.

Signup, Profile, And Billing

sequenceDiagram
    participant User
    participant UI as Landing / Profile UI
    participant Cognito as Amazon Cognito
    participant SES as Amazon SES no-reply@reefamatic.com
    participant Pre as user-cognito-pre-register
    participant Post as user-cognito-post-register
    participant API as REST API Gateway
    participant Profile as user-get/save-user-profile
    participant Ranges as user-target-ranges
    participant Checkout as user-billing-checkout
    participant Portal as user-billing-portal
    participant Webhook as user-billing-webhook
    participant Stripe as Stripe
    participant UserTable as env-user
    participant TankTable as env-user-tank
    participant Friend as env-friend-access-grant

    User->>UI: Select Free Trial, Basic, or Pro
    UI->>Cognito: Create account
    Cognito->>SES: Send verification code
    Cognito->>Pre: Pre-registration checks
    Cognito->>Post: Post-confirmation
    Post->>Friend: Check email grant
    Post->>UserTable: Create user, tier, trial/friend state
    Post->>TankTable: Create/default tank profile
    User->>UI: Open profile or complete checkout
    UI->>API: POST /user or /user/save
    API->>Profile: Invoke
    Profile->>UserTable: Read/write profile
    Profile->>TankTable: Read/write tank
    UI->>API: POST /user/target-ranges
    API->>Ranges: List/save/reset versioned tank target ranges
    UI->>API: POST /user/billing/checkout
    API->>Checkout: Invoke
    Checkout->>UserTable: Read Stripe customer, pending checkout, and subscription state
    alt Existing open checkout session
        Checkout->>Stripe: Retrieve checkout session
        Checkout-->>UI: Reuse checkout URL
    else Existing active Stripe subscription
        Checkout->>Stripe: Create billing portal session
        Checkout-->>UI: Portal URL
    else New paid subscription
        Checkout->>Stripe: Create checkout session with idempotency key
        Checkout->>UserTable: Store Stripe customer and pending checkout session state
    end
    Stripe->>API: POST /user/billing/webhook
    API->>Webhook: Verify and process event
    Webhook->>UserTable: Store subscription tier/status/price ids and clear pending checkout state
    UI->>API: POST /user/billing/portal
    API->>Portal: Invoke
    Portal->>Stripe: Create billing portal session

Admin Console

flowchart LR
    subgraph UI["Admin UI"]
        ADMIN["Admin page"]
        USERS["Users with nested tanks"]
        COSTS["Usage + Costs"]
        CONFIG["Runtime config"]
        ERRORS["Application errors"]
        FRIENDS["Friend Pro access"]
        FEEDBACK["RaM draft feedback"]
        VERSION["Version + release notes"]
    end

    subgraph API["REST API Gateway"]
        OVERVIEW["POST /user/admin/overview"]
        COSTAPI["POST /user/admin/costs"]
        CFGGET["POST /user/admin/config"]
        CFGSAVE["POST /user/admin/config/save"]
        ERRLIST["POST /user/admin/errors"]
        ERRCLEAR["POST /user/admin/errors/clear"]
        FRIENDAPI["POST /user/billing/friend-access"]
    end

    subgraph Lambdas["Lambdas"]
        L_OVERVIEW["user-admin-overview-get"]
        L_COSTS["user-admin-costs-get"]
        L_CFGGET["user-admin-config-get"]
        L_CFGSAVE["user-admin-config-save"]
        L_ERRLIST["user-admin-errors-list"]
        L_ERRCLEAR["user-admin-errors-clear"]
        L_FRIEND["user-billing-friend-access"]
    end

    subgraph Data["DynamoDB + AWS"]
        USER["env-user"]
        TANK["env-user-tank"]
        TESTH["env-test-history"]
        DOSEH["env-dose-history"]
        PROGH["env-program-history"]
        APPERR["env-app-error"]
        USAGE["env-usage-event"]
        APPCFG["env-app-config"]
        FRIEND["env-friend-access-grant"]
        DRAFTFB["env-program-draft-feedback"]
        WS["env-websocket-connections"]
        CE["AWS Cost Explorer"]
    end

    ADMIN --> USERS
    ADMIN --> COSTS
    ADMIN --> CONFIG
    ADMIN --> ERRORS
    ADMIN --> FRIENDS
    ADMIN --> FEEDBACK
    USERS --> OVERVIEW --> L_OVERVIEW
    FEEDBACK --> OVERVIEW
    COSTS --> COSTAPI --> L_COSTS
    CONFIG --> CFGGET --> L_CFGGET
    CONFIG --> CFGSAVE --> L_CFGSAVE
    ERRORS --> ERRLIST --> L_ERRLIST
    ERRORS --> ERRCLEAR --> L_ERRCLEAR
    FRIENDS --> FRIENDAPI --> L_FRIEND
    L_OVERVIEW --> USER
    L_OVERVIEW --> TANK
    L_OVERVIEW --> TESTH
    L_OVERVIEW --> DOSEH
    L_OVERVIEW --> PROGH
    L_OVERVIEW --> APPERR
    L_OVERVIEW --> USAGE
    L_OVERVIEW --> DRAFTFB
    L_OVERVIEW --> WS
    L_COSTS --> CE
    L_COSTS --> USAGE
    L_CFGGET --> APPCFG
    L_CFGSAVE --> APPCFG
    L_ERRLIST --> APPERR
    L_ERRCLEAR --> APPERR
    L_FRIEND --> FRIEND
    L_FRIEND --> USER

Notes

  • Free Trial accounts get a 7-day app trial, 3 total uploads, and Pro functionality during the trial.
  • Paid subscriptions use recurring Stripe monthly or annual prices.
  • Checkout creation is backend guarded to avoid duplicate subscriptions. The checkout lambda reuses an open pending Checkout Session, redirects existing subscribers to the billing portal, uses Stripe idempotency keys for customer/session creation, and clears pending checkout metadata when webhook subscription state arrives.
  • Promotion code RAM_2026 applies 50% off for the first year.
  • Friend access grants Pro-level access without admin permissions.
  • Canceled or inactive Stripe subscriptions retain user/tank/history data but remove effective app access.
  • Admin costs combine AWS Cost Explorer actuals with RaM per-PDF usage-event attribution.