Skip to content

PRD: Categories

ModuleCommerce (CORE-03)PRD IDPRD-CAT-001
StatusShippedOwnerCommerce squad
Date2026-05-18Versionv1.0
Packages@nx/core · apps/clientURDCAT · 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

MetricTarget / signal
Visual adoptionShare of categories that carry a non-default icon + color trends up
Scan speedFaster category selection on the POS grid (fewer mis-taps)
Picker reuseIcon-color picker reused by at least one form beyond categories
Aggregate integrity100% of category mutations still flow through the merchant aggregate (no standalone CRUD path introduced)

4. Personas & Use Cases

PersonaGoal in this feature
OwnerGive categories a recognizable look and organize them into a tree
Inventory / catalog staffPick an icon + color and a parent when setting up categories
CashierScan 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

#RequirementURD ref
FR-1Categories are created/edited only through the merchant aggregate operationURD-CAT-001
FR-2A category carries an icon (Lucide name) and a color, persisted on the category model metadataURD-CAT-001
FR-3Icon picker covers the full Lucide library via a virtualized grid; color picker offers presets plus a native custom colorURD-CAT-001
FR-4The icon-color picker is RHF-bound and reusable beyond the category formURD-CAT-001
FR-5A category can select a parent category, feeding the category hierarchyURD-CAT-001
FR-6A category can be marked / un-marked as an add-on group, preserved alongside icon/colorURD-CAT-004
FR-7Rename and soft-delete remain available through the aggregate and are unchangedURD-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

AreaRequirement
Data integrityIcon/color live in the category model metadata; the add-on flag and parent reference are preserved across aggregate updates
Tenancy & authzCategories are scoped per merchant; mutations go through the merchant aggregate and its permissions
Performance / scaleThe full-Lucide icon grid is virtualized so rendering thousands of icons stays smooth
Backward compatibilityIcon/color and parent are optional; existing categories without them keep working
i18nForm 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

EntityRole
CategoryProduct grouping per merchant - name (i18n), add-on discrimination, parentId, and metadata.icon (name + color)
Category metadataCarries the visual identity (icon.name, icon.color) on the category model
Merchant aggregateThe 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 with metadata.icon and parentId.
  • 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 / questionMitigation / status
Rendering the full Lucide library could be slowIcon grid is virtualized; only visible icons render
Custom colors could clash with theme / dark modeColor picker offers themed presets; native picker is opt-in for custom values
Parent selection could create cyclesCycle / merchant / discrimination guards live in CategoryService
Standalone category CRUD demandOut of scope; categories stay aggregate-managed (see Commerce URD Non-Goals)

12. Release Plan & Launch Criteria

AspectPlan
PhaseP2 - see Commerce feature catalog
RolloutAll merchants; no feature flag
MigrationNone - icon/color are optional metadata; parentId defaults to null
Launch criteriaCategory form saves icon/color/parent via the aggregate; full-Lucide picker renders smoothly; existing categories unaffected
MonitoringShare 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

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