Shop It Docs
WorkflowsSubscription

Subscription Workflow Overview

Current subscription workflow across catalog setup, entitlement, trials, admin grants, cancellation, and access expiry.

Subscription Workflow Overview

Audience: product, QA, backend, frontend Scope: current subscription lifecycle as implemented in apps/api and packages/db

What Exists Today

The current implementation separates subscription lifecycle from runtime entitlement.

  • subscription records lifecycle and commercial state
  • user_access records whether a user currently has access
  • subscription_history and user_access_history provide audit history
  • user_trial enforces one trial per user per module

This means access checks are based on user_access, not directly on subscription.status.

Catalog Model

The catalog is built in five layers:

  1. subscription_module
  2. subscription_tier
  3. subscription_plan
  4. subscription_plan_price
  5. subscription_plan_feature

The important relationship is:

  • one module has many tiers
  • one tier has one plan
  • one plan has many prices
  • one plan has many features

Trials are configured on the plan via trialDays, not on the module.

Access Grant Sources

A user can receive access from three current paths:

  1. Trial start via POST /subscriptions/trial/:planId
  2. Admin grant via POST /admin/subscriptions/grant
  3. Paid activation via internal SubscriptionService methods

The paid lifecycle still exists in service code, but the current SubscriptionMobileController does not expose purchase or payment-verification endpoints.

Current User-Facing Workflow

Browse

  • public users can list modules via GET /subscriptions/modules
  • authenticated users can list plans via GET /subscriptions/plans

Start Trial

  • user starts a trial against a plan, not a module
  • the service validates:
    • plan exists and is active
    • plan has trialDays > 0
    • the user has not already consumed a trial for that module
    • the user does not already have a live active/trial subscription for that module
  • on success the system creates:
    • a subscription row with status = "trial"
    • a user_trial row
    • a subscription_history row with trial_started
    • a user_access row with grantType = "trial"

The service supports a paid flow through:

  • createPendingPurchase(userId, planId, planPriceId)
  • activateSubscription(pendingSubscriptionId)
  • handlePaymentFailure(pendingSubscriptionId)

That flow is currently service-level. It is not exposed by the current mobile subscription controller. Any payment or order orchestration that activates subscriptions must call into SubscriptionService.

Cancel

Customer cancellation uses SubscriptionService.cancel(subscriptionId, userId).

Behavior:

  • subscription.status becomes cancelled
  • cancelledAt is set immediately
  • cancelsAt is set to the current subscription end date
  • matching user_access.expiresAt is updated to the subscription end date

This is important: cancellation does not immediately revoke access. Access remains until the paid or trial period ends.

Admin Grant / Extend / Revoke

Admins can:

  • grant access directly
  • extend an existing subscription
  • revoke immediately

Admin revoke is different from customer cancel:

  • revoke sets the subscription to cancelled
  • cancelsAt is set to now
  • matching user_access.revokedAt is set immediately

Expiry Workflow

AccessExpirationTask runs every 5 minutes.

It performs two batches:

  1. revoke expired user_access rows
  2. mark expired subscription rows as expired

It also invalidates the access-related cache keys after each expiry action.

Status vs Access

Access is not determined by subscription status alone.

Subscription stateTypical access outcome
pending_paymentno access
trialaccess exists until user_access.expiresAt passes
activeaccess exists until user_access.expiresAt passes
cancelledmay still have access until the retained end date
expiredno access after scheduled revocation/expiry processing

The practical rule is:

  • authorization reads user_access
  • lifecycle reporting reads subscription

Workflow Summary