Saltar al contenido principal

Tags Module

Overview

The tags module manages a global catalog of tags used to classify addons in FlowPOS. Unlike most modules, tags are not business-scoped — they are system-wide entities shared across all businesses.

Tags are linked to addons via the addon_tag join table (managed by the separate addon-tags module).


Architecture

The module follows Hexagonal Architecture with strict layer boundaries.

tags/
├── tags.module.ts # NestJS module wiring
├── domain/
│ └── tags-repository.domain.ts # ITagsRepository port, TAGS_REPOSITORY token, sortable keys
├── application/
│ └── tags.service.ts # Use cases (CRUD + pagination)
├── infrastructure/
│ └── tags.repository.ts # Kysely DB adapter (implements port)
└── interfaces/
├── tags.controller.ts # HTTP adapter
├── dtos/
│ ├── create-tag.dto.ts
│ └── update-tag.dto.ts
└── query/
└── paginate-tags.query.ts

Layer responsibilities

LayerResponsibility
domain/Repository port (ITagsRepository), TAGS_REPOSITORY injection token, and sortable key constants.
application/TagsService — orchestrates CRUD operations and pagination.
infrastructure/TagsRepository — Kysely queries against the tag table. Implements ITagsRepository.
interfaces/TagsController — maps HTTP requests to service calls. Thin layer with no business logic.

Dependency rule

interfaces → application → domain ← infrastructure

Domain Concepts

Tag

A named label used to classify addons by purpose or category.

FieldTypeDescription
idUUIDPrimary key (auto-generated)
uniqueNamestringMachine-readable identifier (e.g., business, customer)
namestringDisplay name
descriptionstringDescription of the tag's purpose (nullable)
isActivebooleanDefaults to true
createdByUUIDFK to user
updatedByUUIDFK to user (nullable)
createdAttimestamptzAuto-set on creation
updatedAttimestamptzSet on update

Known Tag UniqueNames

Defined in TagUniqueName enum (packages/backend/database/src/enums/tag.enums.ts):

ValuePurpose
businessBusiness configuration addons
customerCustomer-facing addons
payment_gatewayPayment integration addons
personalizationUI/UX customization addons

API Endpoints

All endpoints require Bearer token authentication and are scoped to PolicyResource.Tag for RBAC.

POST /tags

Create a new tag.

Body:

{
"uniqueName": "custom_tag",
"name": "Custom Tag",
"description": "A custom tag for addon classification.",
"isActive": true,
"createdBy": "<uuid>"
}

Responses: 201 Created | 400 Invalid body | 401 Unauthorized

GET /tags

List tags with pagination, search, and sorting.

Query parameters:

ParamRequiredDescription
pageNoPage number (default: 1)
sizeNoPage size (default: 10)
searchNoCase-insensitive search on name and uniqueName
orderByNoSort field (name, uniqueName)
orderNoasc or desc

Responses: 200 Paginated list | 401 Unauthorized

GET /tags/:id

Get a single tag by UUID.

Responses: 200 Found | 404 Not found | 401 Unauthorized

PATCH /tags/:id

Partially update a tag.

Body:

{
"name": "Updated Name",
"updatedBy": "<uuid>"
}

Responses: 200 Updated | 400 Invalid body | 404 Not found | 401 Unauthorized

DELETE /tags/:id

Delete a tag permanently.

Responses: 200 Deleted | 404 Not found | 401 Unauthorized


Design Decisions

  1. Global scope (no businessId): Tags classify addon capabilities, which are system-level concerns — not business-specific data.
  2. Dependency injection via Symbol token: TAGS_REPOSITORY follows the same pattern as BRANDS_REPOSITORY, enabling easy testing and swapping of repository implementations.
  3. Sortable keys in domain layer: Placed in domain/tags-repository.domain.ts to avoid the interface layer leaking into domain — respecting hexagonal dependency rules.

  • Addon Tags — many-to-many relationship between addons and tags (addon_tag table)
  • Addons — the entities being classified by tags