PRD: Categories
| Module | Commerce (CORE-03) | PRD ID | PRD-CAT-001 |
| Status | Shipped | Owner | Commerce squad |
| Date | 2026-05-18 | Version | v1.0 |
| Packages | @nx/core · apps/client | URD | CAT · DEL |
TL;DR
Gives every product category a visual identity - a Lucide icon plus a color - and a place in a category hierarchy, so categories render as recognizable, color-coded tiles in the POS and back office instead of plain text. Owners and inventory staff manage it all through the existing merchant aggregate, with a reusable icon-color picker that other forms can adopt.
1. Context & Problem
Categories group products within a merchant and are managed through the merchant aggregate (see CAT). The category form is a thin name/merchant input with no visual identity, so categories render as plain text on the POS grid and in the back office. On a busy touch-screen POS, text-only categories are slow to scan and easy to mis-tap, and there is no way to express a category tree beyond a flat list.
This increment redesigns the category form to give each category an icon (drawn from the full Lucide library) and a color, and adds parent-category selection so categories can form a hierarchy - without breaking the rule that categories are only ever created/edited through the merchant aggregate.
2. Goals & Non-Goals
Goals
- Each category carries a visual identity - an icon (full Lucide library) plus a color - surfaced on the POS and back office (URD-CAT-001).
- Parent-category selection feeding a category hierarchy.
- A reusable icon-color picker (RHF-bound) usable beyond categories.
- Persist icon/color on the category model alongside the existing add-on flag (URD-CAT-004), all via the merchant aggregate.
Non-Goals
- Standalone category CRUD outside the merchant aggregate (URD Non-Goals) - categories stay aggregate-managed.
- Category rename / soft-delete semantics (URD-CAT-002, URD-CAT-003) - already delivered by the merchant aggregate; not re-touched here.
- Deletion-policy cascade behavior (→
DEL).
3. Success Metrics
| Metric | Target / signal |
|---|---|
| Visual adoption | Share of categories that carry a non-default icon + color trends up |
| Scan speed | Faster category selection on the POS grid (fewer mis-taps) |
| Picker reuse | Icon-color picker reused by at least one form beyond categories |
| Aggregate integrity | 100% of category mutations still flow through the merchant aggregate (no standalone CRUD path introduced) |
4. Personas & Use Cases
| Persona | Goal in this feature |
|---|---|
| Owner | Give categories a recognizable look and organize them into a tree |
| Inventory / catalog staff | Pick an icon + color and a parent when setting up categories |
| Cashier | Scan color-coded category tiles quickly on the POS |
Core scenarios: open the merchant aggregate → add/edit a category → pick a Lucide icon and a color from the reusable picker → optionally choose a parent category → save through the aggregate → the category renders as a color-coded, icon-bearing tile in the POS and back office.
5. User Stories
- As an owner, I want to assign an icon and a color to a category, so it is instantly recognizable on the POS grid.
- As catalog staff, I want to pick from the full Lucide icon library, so I can find a fitting icon without being limited to a short list.
- As catalog staff, I want to choose any color (preset or custom), so a category's tile matches how I think about it.
- As an owner, I want to set a parent category, so categories form a hierarchy rather than a flat list.
- As a developer, I want a reusable icon-color picker, so the same control can be dropped into other forms.
6. Functional Requirements
| # | Requirement | URD ref |
|---|---|---|
| FR-1 | Categories are created/edited only through the merchant aggregate operation | URD-CAT-001 |
| FR-2 | A category carries an icon (Lucide name) and a color, persisted on the category model metadata | URD-CAT-001 |
| FR-3 | Icon picker covers the full Lucide library via a virtualized grid; color picker offers presets plus a native custom color | URD-CAT-001 |
| FR-4 | The icon-color picker is RHF-bound and reusable beyond the category form | URD-CAT-001 |
| FR-5 | A category can select a parent category, feeding the category hierarchy | URD-CAT-001 |
| FR-6 | A category can be marked / un-marked as an add-on group, preserved alongside icon/color | URD-CAT-004 |
| FR-7 | Rename and soft-delete remain available through the aggregate and are unchanged | URD-CAT-002 · URD-CAT-003 |
Full requirement text and acceptance criteria live in the Commerce URD. This PRD references them rather than restating them.
7. Non-Functional Requirements
| Area | Requirement |
|---|---|
| Data integrity | Icon/color live in the category model metadata; the add-on flag and parent reference are preserved across aggregate updates |
| Tenancy & authz | Categories are scoped per merchant; mutations go through the merchant aggregate and its permissions |
| Performance / scale | The full-Lucide icon grid is virtualized so rendering thousands of icons stays smooth |
| Backward compatibility | Icon/color and parent are optional; existing categories without them keep working |
| i18n | Form labels and the category name are bilingual ({ en, vi }) |
8. UX & Flows
Key screens (in apps/client): the category form with its details, add-on, and live-preview sections; the reusable icon-color picker (icon grid, color swatch + native picker); and the parent-category input.
9. Data & Domain
| Entity | Role |
|---|---|
Category | Product grouping per merchant - name (i18n), add-on discrimination, parentId, and metadata.icon (name + color) |
| Category metadata | Carries the visual identity (icon.name, icon.color) on the category model |
| Merchant aggregate | The only create/update path for categories |
Conceptual only - full schema and invariants in the developer domain model.
10. Dependencies & Assumptions
Depends on
- Merchant aggregate (URD-MER-004) - the sole create/update path for categories.
- Category model (
@nx/core) - extended withmetadata.iconandparentId. - Lucide icon library - the icon source rendered in the picker.
Assumptions
- A merchant exists; categories are always managed in the context of their merchant aggregate.
- Icon name and color are optional - categories without them render with a default appearance.
11. Risks & Open Questions
| Risk / question | Mitigation / status |
|---|---|
| Rendering the full Lucide library could be slow | Icon grid is virtualized; only visible icons render |
| Custom colors could clash with theme / dark mode | Color picker offers themed presets; native picker is opt-in for custom values |
| Parent selection could create cycles | Cycle / merchant / discrimination guards live in CategoryService |
| Standalone category CRUD demand | Out of scope; categories stay aggregate-managed (see Commerce URD Non-Goals) |
12. Release Plan & Launch Criteria
| Aspect | Plan |
|---|---|
| Phase | P2 - see Commerce feature catalog |
| Rollout | All merchants; no feature flag |
| Migration | None - icon/color are optional metadata; parentId defaults to null |
| Launch criteria | Category form saves icon/color/parent via the aggregate; full-Lucide picker renders smoothly; existing categories unaffected |
| Monitoring | Share of categories with custom icon/color, picker error rate, aggregate save success |
13. FAQ
Can I create a category without going through a merchant? No - categories are created and edited only through the merchant aggregate; there is no standalone category CRUD.
Which icons can I choose from? The full Lucide icon library, presented in a virtualized grid so it stays fast.
Can I use a custom color, not just presets? Yes - the color picker offers themed presets plus a native custom-color picker.
Do existing categories break without an icon or parent? No - icon, color, and parent are all optional; categories without them keep their default appearance.
Is the icon-color picker only for categories? No - it is RHF-bound and reusable, so other forms can adopt the same control.
References
- URD: Commerce -
CATCategories ·DELDeletion Policy - Related:
MERMerchant aggregate - Module: Commerce - overview + traceability
- Developer: @nx/commerce · domain model