Skip to content

PRD: Policy definition, permission catalog & grants

ModulePermissions (CORE-02)PRD IDPRD-PERM-001
StatusShippedOwnerPermissions squad
Date2026-05-28Versionv1.0
Packages@nx/identity · @nx/core · apps/bo · apps/clientURDPERM · GRANT · EFF

TL;DR

Gives administrators and merchant owners a usable management surface for KICKO's authorization model: browse and maintain the permission catalog as CRUD screens, then render the policy definition as per-target sections - role, user, merchant, and organizer - each with its own grant/revoke dialog and table. Grant/revoke flows are idempotent and scoped to the active merchant domain, so authorization can finally be managed in-product instead of by editing the database directly.

1. Context & Problem

KICKO's authorization model - a priority-based Casbin RBAC with per-merchant domains - already stores a permission catalog and policy grants inside the identity package, and the underlying grant/revoke/effective-permission services already exist. What is missing is a usable surface to drive them: administrators cannot browse the permission catalog, attach or detach permissions, or inspect which roles, users, merchants, and organizers a policy applies to without touching the database directly.

This increment builds that management surface on top of the existing identity services. It exposes the permission catalog as CRUD screens and renders the policy definition as a set of target sections (role, user, merchant, organizer), each with its own grant/revoke dialog and table. The same surface is cloned into the merchant-facing team module (client) so an owner can manage policy within their own merchant scope, backed by an @nx/core i18n pass that supplies the en/vi labels these screens render.

2. Goals & Non-Goals

Goals

  • Surface the permission catalog as create/edit/list screens - unique code, action, scope, subject, and i18n name/description.
  • Surface the policy definition with per-target grant/revoke: role, user, merchant, and organizer targets - each a section + table + grant dialog.
  • Make grant/revoke flows idempotent and respect the per-request merchant domain, driving the existing identity grant/revoke services.
  • Clone the policy-definition surface into the client team module so owners manage policy within their own merchant scope, with list filtering by target.
  • Ship the en/vi i18n strings (@nx/core) the screens depend on.

Non-Goals

  • The resource/action/domain hierarchy and the declaration toolkit - coarse manage/write grants and module roll-up are a separate increment (PRD-HIER-001).
  • Wildcard/glob permissions, permission categories / UI grouping, role templates / bundles (URD Non-Goals).
  • Time- or shift-based permissions and permission audit logging.
  • The underlying authorization engine - this increment is the management UI, not the Casbin enforcer or the identity services it consumes.

3. Success Metrics

MetricTarget / signal
Self-service managementPermission catalog and grants are managed in-product; zero direct database edits to grant/revoke
Catalog integrityEvery permission has a globally unique code; in-use permissions cannot be deleted
Grant safetyRe-granting an already-granted permission is a no-op (idempotent), never a duplicate
Scope correctnessEach grant/revoke resolves within the active merchant domain selected per request
Owner reachMerchant owners can manage policy within their own scope via the team module

4. Personas & Use Cases

PersonaGoal in this feature
Admin (bo)Maintain the permission catalog and grant/revoke permissions across roles, users, merchants, and organizers
Owner (client team module)Manage policy within their own merchant scope
OperatorInspect which targets a policy applies to without database access

Core scenarios: maintain the permission catalog (create/edit/list) → open the policy definition → pick a target section (role / user / merchant / organizer) → grant or revoke permissions through the section's dialog → the change resolves within the active merchant domain, idempotently.

5. User Stories

  • As an admin, I want to create, edit, and list permissions with a unique code, action, scope, and subject, so the catalog is maintained in-product.
  • As an admin, I want to grant or revoke permissions to a role through a role-target section, so I control what a role can do.
  • As an admin, I want to grant or revoke permissions to a user, merchant, or organizer through their own target section, so policy can be attached at the right level.
  • As an admin, I want re-granting an existing permission to be skipped rather than duplicated, so grant operations are safe to retry.
  • As an owner, I want the same policy-definition surface inside the client team module, so I manage policy within my own merchant scope.
  • As an admin, I want grant/revoke to resolve within the active merchant domain, so changes apply only where intended.

6. Functional Requirements

#RequirementURD ref
FR-1Permission catalog CRUD - create/edit/list with unique code, action, scope, subject, and i18n name/descriptionURD-PERM-001..004
FR-2A permission code is globally unique; an in-use permission cannot be deletedURD-PERM-002 · URD-PERM-005
FR-3Role-target grant/revoke - section + table + grant dialog driving the identity grant/revoke servicesURD-GRANT-001..002
FR-4User-target grant/revoke - assign/unassign through a user-target sectionURD-GRANT-004
FR-5Merchant-target and organizer-target grant/revoke - each a section + table + grant dialogURD-GRANT-001..002 · URD-EFF-004
FR-6Grant/revoke is idempotent - an already-granted permission is skipped, not duplicatedURD-GRANT-003
FR-7View which permissions a role holds and which users/roles a policy target applies toURD-GRANT-006..007
FR-8Each grant/revoke resolves within the active merchant domain chosen per requestURD-EFF-004
FR-9Team-module clone (client) - the same role/user/merchant/organizer target surface scoped to a merchant, filterable by targetURD-GRANT-001..007 · URD-EFF-004
FR-10en/vi i18n strings (@nx/core) for the permission and policy-definition screensURD-PERM-003

Full requirement text and acceptance criteria live in the Permissions URD. This PRD references them rather than restating them.

7. Non-Functional Requirements

AreaRequirement
Data integrityPermission codes are globally unique; in-use permissions cannot be deleted; records are soft-deleted, never physically removed
IdempotencyGrant/revoke operations are safe to retry - re-granting is skipped, returning a skip count rather than erroring
Tenancy & authzEvery grant/revoke resolves within one active merchant domain per request (active-merchant header); privilege-escalation guard enforced by the underlying services
Performance / scaleList screens read the catalog and per-target grants without per-row fan-out; grant subqueries must read all grant rows (no default-limit truncation)
i18nAll user-facing labels and descriptions are bilingual ({ en, vi }), supplied by the @nx/core locale pass

8. UX & Flows

Key screens: in apps/bo, the permission catalog (permission/{create,edit,list}) and the policy definition (policy-definition/{create,edit,list}) with its role/user/merchant/organizer target sections, each a section + table + grant dialog. In apps/client, the same target surface lives under the team module (team/policy-definition), scoped to a merchant and filterable by target.

9. Data & Domain

EntityRole
PermissionA catalog entry - globally unique code, action, scope, subject, i18n name/description
PolicyDefinitionThe grant/policy record attaching a permission to a target
Role targetA grant of permissions to a role
User targetA grant of permissions to a user (and role-to-user assignment)
Merchant / Organizer targetA grant scoped to a merchant or organizer domain

Conceptual only - full schema and the policy data model in the developer RBAC docs.

10. Dependencies & Assumptions

Depends on

  • Identity policy/grant services (@nx/identity) - the PolicyDefinition / Permission / grant-revoke services this surface drives.
  • Casbin per-merchant RBAC (@nx/core) - the model + per-merchant policy adapter + enforcer that resolves grants within a domain.
  • Fixed & custom roles (URD-ROLE · URD-CROLE) - grants attach to roles that already exist.
  • i18n strings (@nx/core) - en/vi labels the screens render.

Assumptions

  • The underlying identity catalog/grant/revoke and effective-permission services already exist (they predate this increment).
  • An active merchant domain is selected per request via the active-merchant header.
  • Roles, users, merchants, and organizers exist as grant targets.

11. Risks & Open Questions

Risk / questionMitigation / status
Grant subqueries truncated by a default query limitRead all grant rows (no default-limit cap) so users with many grants are not silently dropped
Duplicate grants on retryGrant/revoke is idempotent - re-granting is skipped, never duplicated
Policy-definition query syntax correctnessVerified against the identity services; a query-syntax issue is corrected before launch
Two surfaces (bo + client team module) driftShared target components/hooks/utils; the team-module surface is a scoped clone, not a fork
Flat per-target grants do not scale to coarse accessSuperseded by the resource/action/domain hierarchy (PRD-HIER-001)

12. Release Plan & Launch Criteria

AspectPlan
PhaseP2 - see URD feature catalog (PERM / GRANT / EFF marked Built)
RolloutAll merchants; bo admin surface + client team-module clone; no feature flag
MigrationNone - drives existing identity entities/services; @nx/core i18n strings added
Launch criteriaCatalog CRUD verified; grant/revoke verified idempotent across role/user/merchant/organizer targets within a merchant domain; team-module clone verified within merchant scope
MonitoringGrant/revoke error rate, idempotent-skip counts, policy-definition query correctness

13. FAQ

Does this increment build the authorization engine? No - the Casbin enforcer and the identity grant/revoke/effective-permission services already exist. This increment is the management UI that drives them.

What are "target sections"? The policy definition is rendered as four sections - role, user, merchant, and organizer - each with its own grant/revoke dialog and table, so a grant can be attached at the right level.

Why is grant/revoke idempotent? So operations are safe to retry - re-granting an already-granted permission is skipped (and counted), never duplicated.

Can an owner manage policy themselves? Yes - the same policy-definition surface is cloned into the client team module, scoped to the owner's merchant and filterable by target.

Does a grant apply everywhere? No - each grant/revoke resolves within the active merchant domain chosen per request via the active-merchant header.

What about coarse manage/write grants? Out of scope here - module roll-up and the resource/action/domain hierarchy are owned by PRD-HIER-001.

References

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.