Admin Subscription Workflow
Current admin catalog and subscription operations, including routes, permissions, grants, extensions, and revocations.
Admin Subscription Workflow
Audience: backend, admin frontend, QA Scope: current admin routes and behaviors
Admin Route Groups
The current admin surface is split across six route groups:
| Area | Base path | Permission family |
|---|---|---|
| modules | /admin/subscription-modules | SubscriptionModules_* |
| tiers | /admin/subscription-tiers | SubscriptionTiers_* |
| plans | /admin/subscription-plans | SubscriptionPlans_* |
| plan prices | /admin/subscription-plan-prices | SubscriptionPlanPrices_* |
| plan features | /admin/subscription-plan-features | SubscriptionPlanFeatures_* |
| subscriptions | /admin/subscriptions | Subscriptions_* |
All admin endpoints require:
JwtAuthGuardRoleGuard- matching
@Permissions(...)
Catalog Setup Workflow
The current recommended setup order is:
- create a subscription module
- create tiers for that module
- create one plan per tier
- create one or more prices for the plan
- create plan features
Important current rules:
- module slug is generated from module name in the service layer
- tier slug is generated from tier name in the service layer
- a tier belongs to exactly one module
- a tier can have only one plan
- a plan can have many prices
- a plan can have many features
Delete Semantics
Older docs described soft delete in several places. That is no longer accurate for this module.
Current behavior:
- modules are hard-deleted, but deletion is blocked if the module still has tiers
- tiers are hard-deleted, but deletion is blocked if the tier still has a plan
- plans are hard-deleted, but deletion is blocked if subscriptions reference the plan
- plan prices are hard-deleted
- plan features are hard-deleted
Inactive states still exist on several tables, but the controller delete endpoints are actual deletes.
Admin Grant
POST /admin/subscriptions/grant
Body:
userIdplanId- optional
planPriceId - optional
customEndDate - optional
adminNote
Rules:
- either
planPriceIdorcustomEndDatemust be provided - the module is derived from the selected plan
- if the user already has a live active/trial subscription for that module, the existing row is updated
- otherwise a new active subscription is created
Side effects:
- subscription history gets
admin_granted user_accessis created or updated withgrantType = "admin_grant"
Admin Extend
PATCH /admin/subscriptions/:id/extend
Body:
- optional
durationDays - optional
newEndDate - optional
adminNote
Rules:
- one of
durationDaysornewEndDateis required newEndDatetakes precedence if both are sent- extension always updates the subscription and matching
user_access
Side effects:
- subscription history gets
admin_extended - user access history gets
extended
Admin Revoke
PATCH /admin/subscriptions/:id/revoke
Body:
- optional
adminNote
Behavior:
- only live
activeortrialsubscriptions can be revoked - subscription status changes to
cancelled cancelledAt = nowcancelsAt = now- matching
user_access.revokedAt = now - user access history gets
revoked
This is immediate revocation, not period-end cancellation.
Analytics and Read APIs
/admin/subscriptions also exposes:
GET /admin/subscriptions/analyticsGET /admin/subscriptionsGET /admin/subscriptions/:id
Analytics currently return:
- total active
- total trial
- total cancelled
- total expired
- total pending payment
- active/trial counts grouped by module