PRD: Licensing & Activation Administration (Back Office)
| Module | Licensing | PRD ID | PRD-LADM-001 |
| Status | Ready to dev | FEAT | LADM |
| Epic | BANA-1337 | Plane | BANA-1739 |
| Date | 2026-06-30 | Version | v1.0 |
| Packages | @nx/licensing | URD | LADM |
| Surface | BO · Ops | ||
| Owner | Phát Nguyễn | ||
What Licensing & Activation Administration is
The licensing engine - plans, license lifecycle, device activation, runtime entitlements - already exists, but as machinery behind the scenes. The Operations team had no managed surface to define what we sell (the subscription plans) or to see and operate licenses platform-wide: who holds which plan, which licenses are active or expired, which devices are activated.
This PRD is the Operations team's licensing console: it turns the engine into workable screens - authoring plans, browsing licenses platform-wide, and managing activations. It complements onboarding, which auto-provisions a license when a client is created (Onboarding); this console is where plans are defined and licenses are managed afterwards.
What the console covers
Lets the Operations team run licensing from the Back Office: author subscription plans (3 types: Trial / Subscription / Perpetual, with entitlements and duration - grace - activation-limit terms), view and operate every license granted to a merchant or a user (issue, edit, suspend, reinstate, renew, revoke against a 4-status matrix), and manage device activations across the platform - all without touching the database.
How the Operations team runs licensing
The Operations team authors a subscription plan with its entitlements; browsing the platform-wide license list, they filter by status or entity type, open a license to review its plan, date milestones, and activated devices; they issue a license to a new merchant (or user); when needed they suspend, renew, or revoke - every operation goes through a confirmation dialog.
Where it's easy to get wrong
Revoke is one-way, and plans carry no price
Revoking a license cannot be undone - the confirmation dialog must warn explicitly before it proceeds. Plans authored in this console carry no price - a plan's "terms" are only duration, grace period, and activation limit. Pricing and collection sit outside this console.
1. Goals & Exclusions
Goals
- Author subscription plans - create, edit, and list plans with their type (Trial / Subscription / Perpetual), entitlements, and duration / grace / activation-limit terms.
- Platform-wide license visibility - list and inspect every license, granted to a merchant or a user, with its status and date milestones.
- Operate a license - issue, edit (name + dates), suspend / reinstate, renew, and revoke against the status matrix.
- Manage device activations - list, inspect, add, edit, and delete the devices activated against a license.
Exclusions
- The licensing engine itself - it runs behind the scenes.
- Auto-provisioning a license during onboarding - that is the onboarding flow (Onboarding).
- The merchant-facing entitlement / paywall experience consumed at runtime.
- Plan pricing - plans carry no money amount; pricing and collection sit outside this console.
2. Success Metrics
| Metric | Target / signal |
|---|---|
| Plan-to-sale | A plan defined here is immediately selectable when issuing a license |
| License visibility | The Operations team answers "which entity holds which license / status" from one screen, no database query |
| Operability | The Operations team issues, suspends, or revokes a license without engineering help |
3. Personas & Use Cases
| Persona | Goal in this feature |
|---|---|
| Operations team | Define plans, issue and operate licenses, manage device activations |
| Commercial owner | Set the plan catalogue that sales offers |
Core scenario: the Operations team authors a subscription plan with its entitlements; browsing the platform-wide license list, they filter by status or entity type, open a license to review its plan, date milestones, and activated devices; they issue a license to a new merchant (or user); when needed they suspend, renew, or revoke - every operation goes through a confirmation dialog.
4. User Stories
| # | As a | I want | So that |
|---|---|---|---|
| 01 | Operations team | I author subscription plans with entitlements | sales has a catalogue to offer |
| 02 | Operations team | I see every license with its status and grantee | I have platform-wide visibility |
| 03 | Operations team | I issue a license to a merchant or a user, and revoke it when needed | I can provision or cut off service |
| 04 | Operations team | I renew, suspend, or reinstate a license | I can manage its lifecycle without permanently cutting it off |
| 05 | Operations team | I edit a license's name and date milestones | I can adjust terms without re-issuing |
| 06 | Operations team | I manage a license's device activations | I know which devices use it and can remove one when needed |
5. Functional Requirements
| # | Requirement | Status | URD ref |
|---|---|---|---|
FR-001 | Author subscription plans - manage the plan list and each plan's terms. • List, create, and edit subscription plans. • Each plan has a type: Trial / Subscription / Perpetual. • Each plan carries entitlements. • Each plan carries duration / grace / activation-limit terms. | ✅ | URD-LADM-001 · URD-LADM-008 |
FR-002 | Declare entitlements for a plan. • An entitlement carries a code, a data type, and a value. • Entitlements can only be declared on a saved plan. | ✅ | URD-LADM-001 · URD-LADM-008 |
FR-003 | Platform-wide license list and detail. • The list has 7 columns. • Filterable by 6 criteria. | ✅ | URD-LADM-002 · URD-LADM-007 |
FR-004 | Issue a license to a merchant or a user. • Grantee: a merchant or a user. • The license key is auto-generated. | ✅ | URD-LADM-004 |
FR-005 | Edit a license: name and date milestones. • Editable fields: name and 3 date milestones. • The date milestones must follow a strict ordering rule. | ✅ | URD-LADM-005 |
FR-006 | License lifecycle: suspend / reinstate / renew / revoke against a 4-status matrix. | ✅ | URD-LADM-005 |
FR-007 | Manage device activations: list, detail, add / edit / delete. | ✅ | URD-LADM-003 |
FR-008 | Commercial view on the license list. • Adds plan and seat columns. • Adds filters by merchant and by plan. | 🚧 | URD-LADM-002 · URD-LADM-007 |
FR-009 | Self-issue a free-trial license in one action. | 🚧 | URD-LADM-004 |
FR-010 | Show seat usage and block over the activation limit. • The license detail shows seat usage. • Blocks additional activations past the activation limit. | 🚧 | URD-LADM-003 · URD-LADM-007 |
FR-011 | Append-only operation history on a license. | 🚧 | URD-LADM-005 |
FR-012 | Console gated to the Operations team. | ✅ | URD-LADM-006 |
FR-001 - Author subscription plans ✅
- Plan list - columns: Name (bilingual) · Product · Type (colored label) · Status (colored label) · Sequence. Filters: Name, Product, Type, Status (Sequence not filterable). Row actions: Edit · Delete (confirmation naming the plan).
- Plan form:
| Field | Required | Rule |
|---|---|---|
| Name | required | bilingual EN/VI, ≤ 200 characters |
| Description | optional | single-language text (not bilingual), multiline |
| Product | required | the commercial product the plan belongs to |
| Type | required | 3 values: Trial · Subscription · Perpetual |
| Status | required | Activated (default) · Deactivated · Archived |
| Sequence | optional | integer ≥ 0 (default 0) - display order in the catalogue |
| Duration | - | number ≥ 0 + unit day / week / month / year (default 0 days) |
| Grace period | - | number ≥ 0 + unit day / week / month / year (default 0 days) |
| Activation limit | - | integer ≥ 0 (default 0) - this is the plan's seat count |
- A live preview card next to the form reflects the input: name, type, status, duration, activation limit, grace period.
- Plans carry no price - a plan's "terms" are only duration, grace period, and activation limit.
- Leaving the form with unsaved changes → warning.
FR-002 - Plan entitlements ✅
Each plan carries a list of feature grants (entitlements / feature flags), managed on the plan's edit screen - the plan must be saved first.
| Field | Required | Rule |
|---|---|---|
| Code | required | feature code, e.g. max_users |
| Name | required | bilingual EN/VI, ≤ 200 characters |
| Description | optional | bilingual EN/VI, ≤ 400 characters |
| Data type | required | Boolean · Number · Text · JSON |
| Value | - | the input changes with the chosen data type; locked until a type is chosen; changing the type resets the value to the type's default |
| Status | required | Activated · Deactivated |
| Sequence | optional | integer |
- Entitlement table: Code · Name · Data type · Status · Sequence; edit via dialog, delete with a confirmation naming the code.
FR-003 - License list + detail ✅
- Columns: License key · Name (bilingual) · Status (colored label) · Entity type (Merchant · User) · Entity ID · Starts at · Expires at.
- Filters: key, name, status, entity type, starts at, expires at. (Filters by merchant name and by plan live in FR-008.)
- License detail: the header shows the key (one-tap copy) + status; the info block shows Name, Plan, Entity type, Entity ID, Issued at, Starts at, Expires at, Grace expires at, Last validated at; a block of entitlements inherited from the plan (read-only); a block of the license's activations (each deletable, with confirmation).
FR-004 - Issue a license ✅
| Field | Required | Rule |
|---|---|---|
| Plan | required | picked from the plan catalogue, shown with its product |
| Entity type | required | Merchant · User |
| Entity | required | picked per the chosen type; locked until a type is chosen; changing the type clears the selection |
| Name | optional | bilingual EN/VI |
| Key prefix | optional | ≤ 32 characters; letters, digits, and hyphens only |
- The license key is auto-generated (carrying the prefix if given) - never typed by hand.
FR-005 - Edit a license ✅
- Editable: Name + the 3 date milestones Starts at / Expires at / Grace expires at.
- Strict ordering rule: starts < expires < grace-expires - equal dates are also invalid.
- Immutable after issue: plan, entity, license key.
FR-006 - License lifecycle ✅
A license has 4 statuses: Active · Expired · Suspended · Revoked. Operation matrix:
| Operation | Allowed from | Notes |
|---|---|---|
| Suspend | Active | optional reason field |
| Reinstate | Suspended | - |
| Renew | Active · Expired | Perpetual-plan licenses cannot be renewed |
| Revoke | Any status except Revoked | one-way, irreversible - the confirmation warns explicitly; optional reason field |
- Every lifecycle operation goes through a confirmation dialog; the action menu only offers operations valid for the current status.
FR-007 - Device activations ✅
- List - columns: License · Device fingerprint · Platform · Label · Hostname · IP · Created at. Filters: fingerprint, platform, label, hostname, IP, created at.
- Add: License (required, picked by license key) + Device fingerprint (required); Platform / Label / Hostname optional; IP is recorded by the system.
- Edit: platform / label / hostname only - license and fingerprint are immutable after creation.
- Delete = hard delete (an activation has no status of its own; "deactivating" is deleting), always behind a confirmation naming the fingerprint - available from the activation list, the activation detail, or the license detail page.
- Activation detail: device info (fingerprint, platform, label, hostname, IP, created/updated dates) + a block for the attached license (key linking through to the license page, name, status, plan, expiry).
FR-008 - Commercial view on the license list 🚧
The license list carries a Plan column, a Seats column (activations used / limit), and filters by merchant (by name, not raw ID) and by plan.
FR-009 - Self-issued free-trial license 🚧
A one-action shortcut issuing a trial license to an entity without manually picking a plan - the system selects the Trial-type plan and generates the license in a single tap.
FR-010 - Seat usage 🚧
The license detail shows activated devices over the plan's activation limit (e.g. 3/5) and blocks new activations once the limit is reached.
FR-011 - Append-only operation history 🚧
Every operation on a license (issue, edit, suspend, reinstate, renew, revoke) leaves an append-only history - who, when, reason - viewable on the license detail.
FR-012 - Gated to the Operations team ✅
The console opens only with a Back-Office account of the Operations team; a merchant's own users cannot reach it. The console lives in the Back Office "Support" section.
5.1 Acceptance Criteria
- Creating a plan without name, product, type, or status → error, nothing saved; a name > 200 characters → error; a new plan defaults to Activated, sequence 0, duration / grace 0 days, activation limit 0.
- Entitlements can only be added on a saved plan; changing the data type resets the value input to the type's default; the value input is locked until a type is chosen.
- Issuing a license: the entity picker is locked until an entity type is chosen; changing the entity type clears the selection; a key prefix of 33 characters or with characters beyond letters/digits/hyphens → error; the key is auto-generated.
- Editing a license: setting expires ≤ starts → error; grace-expires ≤ expires → error; plan / entity / key cannot be changed.
- An Active license: the menu offers Suspend, Renew, Revoke (no Reinstate); Suspended: Reinstate, Revoke; Expired: Renew, Revoke; Revoked: no lifecycle operations remain.
- Revoke always warns it cannot be undone; Suspend and Revoke offer an optional reason field; a Perpetual-plan license cannot be renewed.
- Activations: editing cannot change the license / fingerprint; deletion always goes through a confirmation naming the fingerprint; the activation detail links through to the license page.
- A merchant's own user cannot open the console.
6. Non-Functional Requirements
| Area | Requirement |
|---|---|
| Tenancy & authz | Platform-wide, Operations-team Back-Office accounts only; not reachable by a merchant's own users |
| Auditability | License operations leave an append-only history (who, when, reason), viewable on the license detail |
| Integrity | A license binds to exactly one entity (merchant or user); revoke is terminal |
| Operation safety | Every state-changing or deleting operation goes through a confirmation dialog stating the consequence |
| i18n | Plan / license names are entered bilingually (EN/VI); type and status labels display bilingually |
7. UX & Flows
How the Operations team runs licensing:
What the console covers:
The console lives in the Back Office "Support" section. Plans are authored; licenses and activations are browsed platform-wide; every state change goes through a confirmation dialog.
8. Data & Domain
| Concept | Role in this screen |
|---|---|
| Subscription plan | A commercial plan: type (Trial / Subscription / Perpetual) + duration, grace, activation limit + entitlements; carries no price |
| Entitlement | A plan's feature grant: code + data type (Boolean / Number / Text / JSON) + value |
| License | A plan granted to exactly one entity, with an auto-generated key and a 4-status lifecycle |
| Entity | A merchant or a user - the grantee of a license |
| Device activation | A device bound to a license, consuming one seat; no status of its own - deleting it is the deactivation |
| Seat | The activation limit declared on the plan; usage is shown on the license detail (FR-010) |
Conceptual only - the licensing engine (plans, lifecycle, activation, validation) lives behind the scenes; the data model is in the developer docs.
9. Dependencies & Assumptions
Depends on
| # | Feature | Depends on what |
|---|---|---|
| 01 | Licensing engine (Licensing) | the plans, license lifecycle, and activation this surface drives. |
| 02 | Onboarding (Onboarding) | auto-provisions a license at client creation, using plans defined here. |
| 03 | Merchants & Users (Commerce) | the entities a license is bound to. |
Assumptions
| # | Assumption | What breaks if wrong |
|---|---|---|
| 01 | The Operations team is authenticated with a licensing-admin role. | If an account without that role could still reach the console, every merchant's license data would be exposed and open to unintended changes (see URD-LADM-006). |
| 02 | A plan must exist (and be Activated) before a license can be issued against it. | If issuance were allowed before a plan exists or is active, the resulting license would reference a plan that doesn't exist or is no longer sold, leaving its entitlement undefined. |
10. Release Plan & Launch Criteria
| Aspect | Plan |
|---|---|
| Phase | P1 - the licensing console is available in the Back Office |
| Rollout | Operations-team users; no feature flag |
| Migration | None - it drives the existing licensing engine |
| Launch criteria | Plans author with all fields + entitlements; licenses issue to merchants / users with auto-generated keys; the 4 lifecycle operations follow the status matrix with confirmations; activations add / edit / delete; every screen is reachable by the Operations team only |
| Monitoring | Plan authoring and license operation volume; revoke rate |
References
- URD: Licensing -
LADM·PLN·LIC·ACT - Related: Onboarding (auto-provisioning)
- Module: Licensing - URD · Roadmap: Phase 2 - By Month
- Developer: @nx/licensing
Risks & Open Questions
| # | Risk / question | Mitigation / status |
|---|---|---|
| 01 | Is plan authoring ops-only, or a distinct commercial-admin role? | Open - start gated to the Operations team; split the role later if needed |
| 02 | Does revoke need a grace window vs immediate seat release? | Open - today revoke is immediate and one-way; seats are not counted or released on revoke (FR-010) |
| 03 | The platform-wide license list could grow large | Filterable by 6 criteria + countable; merchant / plan filters added by FR-008 |
| 04 | Operating a license is sensitive | Every operation confirms + captures a reason; an append-only history traces sensitive operations (FR-011) |
FAQ
| # | Question | Answer |
|---|---|---|
| 01 | Is this the licensing engine? | No - the engine is built behind the scenes; this is the Operations team's console that drives it. |
| 02 | Where does a license first get created? | Usually onboarding auto-provisions one when a client is created; this console authors the plans and manages licenses afterwards. |
| 03 | Can a license be granted to an individual user? | Yes - when issuing, pick the entity type: Merchant or User. |
| 04 | How do I issue a trial license? | Either issue with a Trial-type plan via the issue form, or use the one-tap trial shortcut (FR-009) that picks the trial plan and generates the license for you. |
| 05 | What is an activation? | A device bound to a license, consuming one of its seats; to deactivate, delete the activation record (with confirmation). |
| 06 | Can a merchant's own user open this? | No - it is platform-wide and gated to the Operations team. |