URD: Commerce
| Module | CORE-03 | Version | v0.8 |
|---|---|---|---|
| Status | Built | Date | 2026-06-15 |
Business documentation. This URD is Commerce's feature list - each feature below is one Functional Area (
<AREA>). The same<AREA>keys the feature's PRDs (PRD-<AREA>-NNN) and tests (TC-<AREA>-NNN), and each feature is listed in the Delivery feature catalog. See the Feature Spine convention.
1. Purpose
Commerce lets a business owner stand up and run their business structure: a single Organization (the brand) and one or more Merchants (the legal point-of-sale units), each with its own sale channels and product categories. The module delivers a one-step onboarding that creates the whole structure atomically, plus full lifecycle management of every entity afterwards.
2. Scope
| Included | Excluded |
|---|---|
| Organization creation via onboarding | Employee lifecycle & login (→ User Management) |
| Organization profile, hierarchy, settings, attachments | Role/permission definition (→ Permissions) |
| Merchant creation (single, batch, aggregate) | Product catalog content (→ Products) |
| Business-type classification | Stock levels (→ Inventory) |
| Sale-channel management | Order / checkout processing (→ Orders) |
| Category management with add-on flag | Payment processing (→ Payment) |
| Per-merchant deletion policy | E-invoice issuance (→ Tax & Invoice) |
| Encrypted merchant configuration | Technical API specifications (→ developer docs) |
| Role-based data filtering |
3. Definitions
| Term | Definition |
|---|---|
| Organization | Top-level virtual brand entity. Parent container for merchants, users, and devices. Carries branding, not legal identity. |
| Merchant | A physical/legal point-of-sale unit under an organization where transactions occur. Holds tax info, invoice profile, and wallet. |
| Sale Channel | A selling channel within a merchant (e.g. dine-in, takeout, delivery). Supports hierarchy. |
| Category | A product grouping within a merchant. Can be flagged as add-on. |
| Business Type | Classification that drives the POS UI: DEFAULT, TICKET, FNB, THEATER. |
| Aggregate Operation | A single request that creates or updates a merchant together with its categories and sale channels, atomically. |
| Deletion Policy | Per-merchant configuration controlling cascade behavior on entity deletion. |
| Configuration | Encrypted key-value settings for a merchant (payment providers, integrations). |
| Slug | URL-friendly identifier. Globally unique for organizations; unique per organization for merchants; unique per merchant for sale channels. |
4. Conceptual Model
Conceptual only - the full schema lives in the developer domain model.
5. Feature Catalog
The feature list of this module. Each row is one feature (a Functional Area). Detail in §6. Mirrored in the Delivery feature catalog.
| Feature ID | Feature | Phase | Status | Priority |
|---|---|---|---|---|
ORG | Organization | P1 | Built | High |
MER | Merchant | P1 | Built | High |
SC | Sale Channels | P1 | Built | High |
CAT | Categories | P2 | Built | High |
DEL | Deletion Policy | P2 | Built | Medium |
CFG | Configuration | P2 | Built | Medium |
ACC | Access | P1 | Built | High |
RCP | Receipt Templates | P2 | Built | Medium |
FLR | Table & Floor Allocation | P2 | Built | High |
RTL | Retail business type | P2 | Planned | High |
BOP | Backoffice portal | P2 | Planned | High |
Status: live from Plane where mapped, otherwise registry-declared. Vocabulary mirrors Plane (state-group / phase).
6. Features
One sub-section per feature, in catalog order. Each feature keeps its description, requirements, and acceptance together. Priority = MoSCoW (Must / Should / Could / Won't).
ORG - Organization Built
Feature ID: commerce/ORG · Phase: P1 · PRDs: PRD-ORG-001 · Dev: @nx/commerce
What it does for users: owners create a single brand entity via onboarding - the parent container for all merchants, users, and devices - then manage its profile, hierarchy, settings, and attachments throughout its lifecycle.
Requirements
| ID | P | Requirement |
|---|---|---|
| URD-ORG-001 | M | User can create one organization via onboarding |
| URD-ORG-002 | M | Onboarding atomically creates organization + default merchant + sale channels + access |
| URD-ORG-003 | M | The creating user is automatically assigned as Owner |
| URD-ORG-004 | M | Name (multilingual) and slug are required; all other fields optional |
| URD-ORG-005 | M | A unique system identifier is generated on creation and is not editable |
| URD-ORG-006 | M | Organization can be found by ID or by slug (cascading lookup) |
| URD-ORG-007 | M | Owner can update organization profile |
| URD-ORG-008 | M | Aggregate create/update supports file attachments |
| URD-ORG-009 | S | Organization list/count is filtered by the user's role |
| URD-ORG-010 | S | Organization can be deactivated (data preserved, reversible) |
| URD-ORG-011 | S | Organization can designate a headquarter merchant |
| URD-ORG-012 | S | Organization can be archived (permanently read-only) |
| URD-ORG-013 | C | Organization can have child organizations (hierarchy) |
| URD-ORG-014 | M | Self-service onboarding runs in one local transaction and grants the calling user Owner, with no license issued (PRD-ORG-001) |
| URD-ORG-015 | M | Administrative (aggregate) onboarding provisions a new owner user and a license as a two-phase operation, fully compensating in reverse on a phase-2 failure |
| URD-ORG-016 | M | Administrative onboarding is idempotent - an Idempotency-Key replays a completed result and rejects a concurrent retry as in-progress |
| URD-ORG-017 | S | Onboarding auto-creates a fixed default set: one headquarter merchant, two sale channels (Offline, Take away), and F&B category templates (F&B industry only) |
| URD-ORG-018 | S | Changing the headquarter merchant emits an organization-HQ-changed event to downstream consumers |
Acceptance
AC-ORG-01: Onboarding is atomic
| Given | When | Then |
|---|---|---|
| A new authenticated user with no organization | Onboarding completes with a valid name + slug | Organization (Activated) + default merchant + default channel(s) created; owner access granted; system & slug identifiers auto-generated |
| Any step fails | During onboarding | Entire operation rolls back - nothing persisted |
AC-ORG-02: Slug uniqueness
| Given | When | Then |
|---|---|---|
| An organization already uses slug "my-business" | Another user tries the same slug | Creation rejected - slug already in use |
AC-ORG-03: Two onboarding paths (PRD-ORG-001)
| Given | When | Then |
|---|---|---|
| An authenticated user with no organization | Completes self-service onboarding | Org + HQ merchant + defaults created in one local transaction; the calling user is Owner; no license issued |
| A back-office operator provisioning a client | Completes administrative (aggregate) onboarding | A new owner user and a license are provisioned; on a phase-2 failure everything is compensated and nothing is left behind |
AC-ORG-04: Idempotent administrative onboarding
| Given | When | Then |
|---|---|---|
| An administrative onboarding request with an Idempotency-Key | Submitted again after it completed | The stored result is replayed - no second organization is provisioned |
| The same Idempotency-Key | Submitted again while still in flight | The retry is rejected as in-progress |
MER - Merchant Built
Feature ID: commerce/MER · Phase: P1 · PRDs: PRD-ORG-001 · Dev: @nx/commerce
What it does for users: owners add the legal point-of-sale units under their organization - one at a time, several at once, or together with their categories and channels - and manage each merchant's profile and lifecycle.
Requirements
| ID | P | Requirement |
|---|---|---|
| URD-MER-001 | M | Default merchant created during onboarding |
| URD-MER-002 | M | Owner can create additional merchants |
| URD-MER-003 | M | Owner can batch-create multiple merchants |
| URD-MER-004 | M | Owner can aggregate-create a merchant with categories + sale channels |
| URD-MER-005 | M | Merchant slug is unique within the same organization |
| URD-MER-006 | M | Merchant can be viewed with its channels and categories |
| URD-MER-007 | M | Owner can update merchant information |
| URD-MER-008 | M | Aggregate update: ID-only = delete, ID+data = update, no ID = create |
| URD-MER-009 | M | Merchant can be found by ID or by slug (cascading lookup) |
| URD-MER-010 | M | Merchant list is filtered by the user's role |
| URD-MER-011 | M | Merchant count respects the same filtering as the list |
| URD-MER-012 | S | Merchant can be deactivated (reversible) |
| URD-MER-013 | S | Merchant can be archived (permanently read-only) |
| URD-MER-014 | C | Merchant hierarchy (parent-child) |
| URD-MER-015 | S | Explicit delete flag distinguishes "delete" from "leave unchanged" in aggregate update |
| URD-MER-016 | M | All legal & financial attributes (business type, tax identity, e-invoice details, finance accounts and wallets, currency) belong to the merchant only - never to the organization |
| URD-MER-017 | M | Every organization has exactly one headquarter merchant, created at onboarding and recorded on the organization |
| URD-MER-018 | M | A merchant's sectors must be valid business sectors; onboarding sets up the default sale channels and category templates for those sectors |
| URD-MER-019 | S | Tax identity entered on the merchant is automatically reused by the e-invoice profile, with no re-entry |
| URD-MER-020 | M | The headquarter merchant is created with a derived slug, "Headquarter" name, headquarter flag, and direct tax method |
| URD-MER-021 | M | Merchant enum defaults: business type Household (or Business); industry F&B (Retail / Ticket / Other); currency VND |
| URD-MER-022 | S | Onboarding progress is six ordered steps on the merchant (merchant info → sale channel → finance account → tax info → product → employee), surfaced as completed/total in the launchpad |
| URD-MER-023 | S | Slug uniqueness is soft-delete-aware (a removed slug is freed); aggregate onboarding auto-suffixes a unique token on collision; there is no maximum number of merchants per organization |
Acceptance
AC-MER-01: Aggregate create
| Given | When | Then |
|---|---|---|
| An owner with an existing organization | Creates a merchant with categories + channels | Merchant, categories, channels all created atomically; identifiers generated |
| Any child is invalid | During aggregate create | Entire operation rolls back |
AC-MER-02: Aggregate smart update
| Given | When | Then |
|---|---|---|
| Child item with ID only | Aggregate update | Item deleted |
| Child item with ID + data | Aggregate update | Item updated |
| Child item without ID | Aggregate update | Item created |
AC-MER-03: Headquarter & legal attributes
| Given | When | Then |
|---|---|---|
| A user completes onboarding | The organization is created | A headquarter merchant exists and is recorded as the organization's headquarter - in the same step |
| An organization | The owner looks for where to enter tax identity / e-invoice / wallet | There is nowhere - these are entered on a merchant, not the organization |
| A merchant has its tax code entered | The owner issues an e-invoice | It uses the merchant's tax identity automatically, with no re-entry |
AC-MER-04: Auto-created defaults (PRD-ORG-001)
| Given | When | Then |
|---|---|---|
| Any onboarding completes | The structure is created | Exactly one headquarter merchant (derived slug, "Headquarter", direct tax method) and two sale channels (Offline, Take away) exist |
| The onboarding industry is F&B | The merchant is created | F&B category templates are seeded |
| The onboarding industry is retail / ticket / other | The merchant is created | No category templates are seeded |
SC - Sale Channels Built
Feature ID: commerce/SC · Phase: P1 · PRDs: - · Dev: @nx/commerce
What it does for users: each merchant has one or more selling channels (dine-in, takeout, delivery), created at onboarding and managed via the merchant aggregate or batch-added to an existing merchant.
Requirements
| ID | P | Requirement |
|---|---|---|
| URD-SC-001 | M | Default channel(s) created during onboarding |
| URD-SC-002 | M | Channels managed as part of merchant aggregate operations |
| URD-SC-003 | M | Channels can be batch-created for an existing merchant |
| URD-SC-004 | M | Channel slug unique within the same merchant |
| URD-SC-005 | M | A unique system identifier is generated on creation and is not editable |
| URD-SC-006 | C | Channel hierarchy (parent-child) |
| URD-SC-007 | S | Channels can be deactivated or archived |
Acceptance
AC-SC-01: Channel via aggregate
| Given | When | Then |
|---|---|---|
| An owner with an existing merchant | Manages channels via merchant aggregate or batch-add | Channels created with a unique system identifier; slug unique within the merchant |
CAT - Categories Built
Feature ID: commerce/CAT · Phase: P2 · PRDs: - · Dev: @nx/commerce
What it does for users: owners group products into categories per merchant, managed through the merchant aggregate, with the option to flag a category as an add-on group.
Requirements
| ID | P | Requirement |
|---|---|---|
| URD-CAT-001 | M | Categories managed as part of merchant aggregate operations |
| URD-CAT-002 | M | Categories can be renamed via aggregate update without affecting their products |
| URD-CAT-003 | M | Categories can be deleted via aggregate update (soft-delete) |
| URD-CAT-004 | S | Category can be marked as add-on (and un-marked) |
Acceptance
AC-CAT-01: Category via aggregate
| Given | When | Then |
|---|---|---|
| A category with linked products | Renamed via aggregate update | Category renamed; its products are unaffected |
| A category | Deleted via aggregate update | Category soft-deleted |
DEL - Deletion Policy Built
Feature ID: commerce/DEL · Phase: P2 · PRDs: - · Dev: @nx/commerce
What it does for users: each merchant carries a configurable policy that controls how deletions cascade - whether a category with linked products can be removed, and whether deleting a category also deletes its products.
Requirements
| ID | P | Requirement |
|---|---|---|
| URD-DEL-001 | S | Each merchant has a configurable deletion policy |
| URD-DEL-002 | S | strictCategoryDeletion: when true, blocked if category has linked products |
| URD-DEL-003 | S | cascadeProductDeletion: when true, deleting a category cascades to its products |
| URD-DEL-004 | S | Owner can view and update the deletion policy |
Acceptance
AC-DEL-01: Deletion policy
| Given | When | Then |
|---|---|---|
strictCategoryDeletion = true | Deleting a category that has products | Blocked |
cascadeProductDeletion = true | Deleting a category | Its products are also deleted |
CFG - Configuration Built
Feature ID: commerce/CFG · Phase: P2 · PRDs: - · Dev: @nx/commerce
What it does for users: merchants store payment-provider credentials and integration settings as encrypted key-value configuration, organized into functional groups.
Requirements
| ID | P | Requirement |
|---|---|---|
| URD-CFG-001 | S | Merchants can store payment-provider credentials and integration settings |
| URD-CFG-002 | S | Sensitive credentials are encrypted at rest |
| URD-CFG-003 | S | Configurations are organized by group (system, table, integration) |
Acceptance
AC-CFG-01: Encrypted configuration
| Given | When | Then |
|---|---|---|
| A merchant stores payment-provider credentials | Saved | Sensitive credentials are encrypted at rest and organized by group |
ACC - Access Built
Feature ID: commerce/ACC · Phase: P1 · PRDs: - · Dev: @nx/commerce
What it does for users: data is isolated by role - owners see only their own organization and merchants, employees see only the merchants they are assigned to, and every list/count is filtered accordingly.
Requirements
| ID | P | Requirement |
|---|---|---|
| URD-ACC-001 | M | User access is managed via role-based policies (org-level or merchant-level) |
| URD-ACC-002 | M | Employees can be assigned to specific merchants |
| URD-ACC-003 | M | A user can be granted access to multiple organizations |
| URD-ACC-004 | M | Owner sees only their own organization and merchants |
| URD-ACC-005 | M | All list/count operations are filtered by the user's role (Admin bypasses) |
| URD-ACC-006 | M | Owner can create, view, and update their organization |
| URD-ACC-007 | M | Owner can create, update, and deactivate merchants |
| URD-ACC-008 | M | Owner can manage channels and categories via aggregate operations |
| URD-ACC-009 | M | Owner can assign an employee to a specific merchant |
| URD-ACC-010 | M | Employee sees only assigned merchants |
| URD-ACC-011 | M | Employee cannot access unassigned merchants |
| URD-ACC-012 | M | A user with an unrecognized role is denied (no silent empty result) |
| URD-ACC-013 | M | The license is issued against the new owner user; its activation/contract code is echoed back, never stored |
| URD-ACC-014 | M | The owner grant is three access rows - join-domain to org, join-domain to merchant, assign-role Owner |
| URD-ACC-015 | M | Administrative merchant aggregate-create branches on caller - a back-office admin scopes Owner to the merchant; an organization owner links themselves |
| URD-ACC-016 | S | Organization/merchant list/count/find reads are scoped at the handler from the caller's grants (the central policy engine does not currently gate these reads) |
Acceptance
AC-ACC-01: Role-based isolation
| Given | When | Then |
|---|---|---|
| Owner A (Org X) and Owner B (Org Y) | Owner A requests organization/merchant data | Only Org X data returned; Org Y not visible |
| Employee assigned to Merchant X only | Requests merchant list | Only Merchant X returned |
FLR - Table & Floor Allocation Built
Feature ID: commerce/FLR · Phase: P2 · PRDs: PRD-FLR-001 · Dev: @nx/commerce · @nx/sale
What it does for users: an F&B merchant designs its physical floor as a named layout holding a tree of zones (floor → room → table) whose leaf zones carry units (tables) with capacity, position, and style - built in one atomic aggregate - then at the POS occupies units with dine-in orders, sees each table free or busy live, finds free tables, transfers parties between zones, and frees a table when its order is done.
Requirements
| ID | P | Requirement |
|---|---|---|
| URD-FLR-001 | M | A merchant models its floor as a named layout; each layout belongs to one merchant |
| URD-FLR-002 | M | A layout holds a tree of zones (floor / room / table), self-nesting up to two levels below the layout root |
| URD-FLR-003 | M | A leaf zone holds units (tables); a unit declares an optional capacity, a placement (canvas position), and a style |
| URD-FLR-004 | M | Owner can create a layout with its whole nested zone tree in one atomic aggregate operation |
| URD-FLR-005 | M | Layout aggregate update follows the id-convention: id-only = delete (cascades to the sub-tree), id+data = update, no id = create |
| URD-FLR-006 | M | A zone is itself create/update-able as an aggregate with nested sub-zones and units; zones can also be batch-created |
| URD-FLR-007 | M | An aggregate that would exceed the two-level depth cap, or that references a zone not rooted in the target layout, is refused before anything persists |
| URD-FLR-008 | S | Owner can read a layout aggregate (zone tree + units) with a configurable max depth - full tree for back-office, shallow for the POS |
| URD-FLR-009 | S | Layouts, zones, and units each carry a lifecycle status (Activated / Deactivated / Archived) and are soft-deleted |
| URD-FLR-010 | M | Layouts, zones, and units are also managed standalone (CRUD), scoped per merchant |
| URD-FLR-011 | M | Opening a dine-in sale order on one or more units creates an occupancy usage that marks those units busy on the floor plan |
| URD-FLR-012 | M | A usage carries a reservation window (from / to); when no end is given, a default 90-minute window applies |
| URD-FLR-013 | M | Occupancy follows reserved/active → success → completed (table freed), or cancelled; a terminal usage cannot be cancelled again |
| URD-FLR-014 | M | A unit is shown busy while it holds a usage in the reserved / active / success states, and free otherwise |
| URD-FLR-015 | M | The POS can query available units in a zone, and available child zones where every unit is free, at the current resolution depth |
| URD-FLR-016 | M | Staff can transfer a party between zones - the source usages are cancelled and the target zone's units are occupied per order, atomically |
| URD-FLR-017 | M | Splitting an order clones its active usages onto each new order; merging moves them to the surviving order |
| URD-FLR-018 | M | Every occupancy change broadcasts a real-time floor-plan event so all POS terminals stay in sync |
| URD-FLR-019 | S | A usage may capture guest details (name, phone, email, party size) |
| URD-FLR-020 | S | The order / reservation keeps an allocation snapshot (the unit and its zone path, plus guest) so the assignment survives on the document |
| URD-FLR-021 | M | All allocation operations are scoped per merchant (x-merchant-id) and gated by allocation permissions |
Acceptance
AC-FLR-01: Atomic floor aggregate (PRD-FLR-001)
| Given | When | Then |
|---|---|---|
| An owner designing a floor | Saves a layout with its nested zones and units in one aggregate | Layout, zones, and units are all created atomically |
| A child item with id only / id + data / no id | A layout aggregate update | The id-only child is deleted (cascading), the id+data child is updated, the no-id child is created |
| Any sub-step fails | During the aggregate | The whole operation rolls back - no half-built tree persists |
AC-FLR-02: Depth cap & layout-rooted guard
| Given | When | Then |
|---|---|---|
| A zone tree deeper than two levels below the layout root | Submitted as an aggregate | The save is refused before anything persists |
| An update referencing a zone that belongs to a different layout (or is not a root zone) | Submitted | The save is refused as not-layout-rooted |
AC-FLR-03: Occupy & free a table
| Given | When | Then |
|---|---|---|
| A free table | A dine-in order opens on it | The unit shows busy on the floor plan; a usage with a reservation window (default 90 minutes) is recorded |
| A table whose order is paid (success) | The table is completed | The usage becomes completed and the unit shows free again |
| A usage already completed or cancelled | An attempt to cancel it | Refused - a terminal usage cannot be cancelled again |
AC-FLR-04: Free-table availability
| Given | When | Then |
|---|---|---|
| A zone with some tables occupied | A "free tables" query | Only units with no reserved/active/success usage are returned |
| A parent zone with several child zones | An available-zones query | Only child zones where every unit is free are returned |
AC-FLR-05: Transfer a party between zones
| Given | When | Then |
|---|---|---|
| A party seated in the main room | Transferred to the patio zone | Atomically: the source usages are cancelled and the patio's units are occupied for each affected order; both moves are broadcast live |
| The source zone has no active usage, or the target zone has no units | Transfer attempted | Refused with a clear reason; nothing is changed |
RCP - Receipt Templates Built
Feature ID: commerce/RCP · Phase: P2 · PRDs: PRD-RCP-001 · Dev: @nx/commerce
What it does for users: owners design how their printed receipt looks - per merchant or per sale channel, and per language - by assembling a named layout from a fixed set of blocks (text, separators, logo image, a line-item table, barcode, QR code, and a grid for side-by-side rows). The layout is validated on save, one template is the default per language, and at checkout the chosen template renders to a monochrome raster sized for 58mm or 80mm thermal paper.
Requirements
| ID | P | Requirement |
|---|---|---|
| URD-RCP-001 | M | A named receipt template is scoped to either a merchant or a sale channel |
| URD-RCP-002 | M | Each template declares a paper width (58mm or 80mm) and a base font size |
| URD-RCP-003 | M | Template name is unique per (principal, locale) and soft-delete aware |
| URD-RCP-004 | M | Templates are locale-specific; a merchant/channel keeps a template set per language |
| URD-RCP-005 | M | Exactly one template is the default per (principal, locale); promoting a default unsets the previous one |
| URD-RCP-006 | M | The layout is an ordered list of blocks from a fixed vocabulary: text, line, image, line-item table, barcode, QR code, grid |
| URD-RCP-007 | M | The layout is validated against the block vocabulary on create and update; a non-conforming layout is refused |
| URD-RCP-008 | M | Text, line-item, barcode, and QR blocks bind to dynamic order fields resolved at print time |
| URD-RCP-009 | S | The line-item table renders configurable columns (field, header, width, align, format) with an optional header row |
| URD-RCP-010 | S | A grid block lays children into proportional columns with alignment / justification (up to 5 rows) |
| URD-RCP-011 | S | Blocks carry presentation styling (alignment, weight, transform, decoration, borders, colors, padding) |
| URD-RCP-012 | S | Numeric, currency, and date values format per a declared format on the block or column |
| URD-RCP-013 | M | A template renders to a monochrome raster sized for its paper width (58mm → 384px, 80mm → 576px) |
| URD-RCP-014 | S | Templates carry a lifecycle status (Activated / Deactivated / Archived) and are soft-deleted |
| URD-RCP-015 | M | All operations are scoped per merchant (x-merchant-id) and gated by receipt-template permissions |
| URD-RCP-016 | S | Templates are listable/filterable by principal, locale, status, and default flag |
Acceptance
AC-RCP-01: Layout validated on save (PRD-RCP-001)
| Given | When | Then |
|---|---|---|
| An owner editing a receipt layout | Saves a layout built from the fixed block vocabulary | The template is stored; the layout is accepted |
| A layout with a missing column field or an unknown block type | Saved | The save is refused - invalid receipt template content; nothing is stored |
AC-RCP-02: One default per scope and language
| Given | When | Then |
|---|---|---|
| A merchant with template A as the Vietnamese default | Template B is marked default for Vietnamese | B becomes the default; A is no longer the default - exactly one default for that (principal, locale) |
| A channel's English default and Vietnamese default | Looked at together | Each language has its own single default; they do not interfere |
AC-RCP-03: Scope & render at checkout
| Given | When | Then |
|---|---|---|
| A merchant with an 80mm default template and a completed payment | The receipt prints | The merchant's default template for the order's language is used, order fields and items are bound, and a 576px-wide monochrome raster is produced |
| A sale channel with its own template | A sale on that channel prints | The channel's template is used in preference to the merchant's |
RTL - Retail Business Type Planned
Feature ID: commerce/RTL · Phase: P2 · PRDs: PRD-RTL-001 · Dev: @nx/commerce
What it does for users: a general retail shop (grocery, fashion, convenience) can run on KICKO the retail way - onboard as a retail business, get a retail catalog structure, and sell at a scan-first counter with no table/kitchen steps in the way. Retail is a full business line (business rules + dedicated UI), not an F&B variant.
Requirements
| ID | P | Requirement |
|---|---|---|
| URD-RTL-001 | M | Owner can onboard a merchant with business type Retail |
| URD-RTL-002 | M | Business type is an explicit choice at onboarding - never silently defaulted to F&B |
| URD-RTL-003 | M | Retail merchants receive retail category templates at onboarding (as F&B sectors do today) |
| URD-RTL-004 | M | At the POS, a retail merchant gets a counter selling flow: scan/search → cart → pay - no table/floor steps |
| URD-RTL-005 | M | Cashier can add an item to the cart by scanning its variant barcode |
| URD-RTL-006 | M | Invoicing and tax behave correctly for a retail merchant |
| URD-RTL-007 | S | F&B-only surfaces (floor map, kitchen, reservations) are hidden for retail merchants |
| URD-RTL-008 | S | Catalog screens handle variant-heavy goods (size/colour) efficiently |
| URD-RTL-009 | S | Retail merchants operate shifts and cash reconciliation identically to F&B |
| URD-RTL-010 | C | Grocery: the sale screen surfaces lot/expiry information where tracked |
Acceptance
AC-RTL-01: Retail onboarding
| Given | When | Then |
|---|---|---|
| A new owner choosing business type Retail | Onboarding completes | Merchant created with retail category templates; no F&B artifacts (floor plan, kitchen) are set up |
| A new owner skipping business type | Onboarding submits | Selection is required - no silent F&B default |
AC-RTL-02: Counter sale
| Given | When | Then |
|---|---|---|
| A retail merchant at the POS | Cashier scans a variant barcode | The item lands in the cart immediately; checkout completes with no table/kitchen step |
BOP - Backoffice Portal Planned
Feature ID: commerce/BOP · Phase: P2 (Jun-Aug) · PRDs: PRD-BOP-001 · Dev: @nx/commerce · @nx/helpdesk
What it does for users: an operator runs a client end-to-end from the BO alone - onboard, configure, import data, support, and monitor.
Requirements
| ID | P | Requirement |
|---|---|---|
| URD-BOP-001 | M | Operator onboards a client end-to-end from BO (org → merchant (MST) → channels → business type) |
| URD-BOP-002 | M | Operator configures packages & licenses, industries & category templates, tax groups from BO |
| URD-BOP-003 | M | Transaction lookup at admin level (across merchants) |
| URD-BOP-004 | M | Bulk Excel import: categories, products/variants, prices, tax - row-level errors, duplicate-safe re-import |
| URD-BOP-005 | M | Support Center in BO: ticket list + detail worked end-to-end |
| URD-BOP-006 | S | SLA / category / agent configuration |
| URD-BOP-007 | S | Admin dashboard: stores by industry, transactions by store |
| URD-BOP-008 | S | Payment-methods configuration promoted to admin level |
Acceptance
AC-BOP-01: Run a client from BO alone
| Given | When | Then |
|---|---|---|
| A new client signed | Operator onboards + configures via BO only | The merchant can sell - no other tool touched |
| A catalog spreadsheet | Operator imports it | Catalog ready; bad rows reported by row; re-import creates no duplicates |
7. Constraints & Non-Goals
Constraints
| ID | Constraint |
|---|---|
| C-01 | Organization must exist before creating merchants |
| C-02 | Aggregate operations are atomic - all or nothing |
| C-03 | All entities use soft-delete; nothing is physically removed |
| C-04 | Slug uniqueness: global for organizations, per-org for merchants, per-merchant for channels |
| C-05 | All operations require authentication |
| C-06 | Payment credentials are encrypted at rest |
Non-Goals
- Cross-organization access or sharing merchants between organizations
- Ownership transfer (Planned)
- Hard-delete of any entity
- Standalone sale-channel / category CRUD outside the merchant aggregate (Planned)
8. Version History
| Date | Author | Description | Ver |
|---|---|---|---|
| 2026-06-15 | Commerce squad | Added FLR Table & Floor Allocation feature (URD-FLR-001..021) - layout/zone/unit floor model authored as an atomic aggregate (depth cap, layout-rooted guard) plus live usage occupancy, availability, transfer, snapshot and real-time floor plan; backlinked to PRD-FLR-001 | v0.8 |
| 2026-06-15 | Commerce squad | Added RCP Receipt Templates feature (URD-RCP-001..016) - merchant/channel-scoped, locale-aware, fixed block vocabulary, one default per locale, thermal raster render; backlinked to PRD-RCP-001 | v0.7 |
| 2026-06-15 | Commerce squad | Onboarding internals: two onboarding paths, saga + compensation, idempotency, license, defaults, six steps, owner-grant rows (URD-ORG-014..018, MER-020..023, ACC-013..016); backlinked to PRD-ORG-001 | v0.6 |
| 2026-06-04 | Claude (AI pair) | Reorganize by feature (Feature Spine); each feature carries its own requirements + acceptance | v0.5 |
| 2026-05-30 | P. Nguyen | Migrated to module-docs convention; reconciled requirement IDs/areas with test cases | v0.4 |
| 2026-04-17 | P. Nguyen | Merged Organization + Merchant into Commerce module | v0.3 |
| 2026-02-27 | QE Assessment | QE findings | v0.2 |
| 2026-02-26 | P. Do - Product Owner | Initial | v0.1 |