Skip to main content

Brands Module

Overview​

The brands module manages product brands within FlowPOS. Brands are used to classify products by manufacturer or label, supporting filtering, reporting, and catalog organization.

Brands are business-scoped: every brand belongs to a specific business and is isolated from other businesses.


Architecture​

The module follows Hexagonal Architecture with strict layer boundaries.

brands/
├── brands.module.ts # NestJS module wiring
├── domain/
│ └── brands-repository.domain.ts # IBrandsRepository port + injection token
├── application/
│ └── brands.service.ts # Use cases (CRUD)
├── infrastructure/
│ └── brands.repository.ts # Kysely DB adapter (implements port)
└── interfaces/
├── brands.controller.ts # HTTP adapter
├── dtos/
│ ├── create-brand.dto.ts
│ └── update-brand.dto.ts
└── query/
└── paginate-brands.query.ts

Layer responsibilities​

LayerResponsibility
domain/Repository port (IBrandsRepository) and BRANDS_REPOSITORY injection token.
application/BrandsService — orchestrates CRUD operations and pagination.
infrastructure/BrandsRepository — Kysely queries against the brand table. Implements IBrandsRepository.
interfaces/BrandsController — maps HTTP requests to service calls. Thin layer with no business logic.

Dependency rule​

interfaces → application → domain ← infrastructure

Domain Concepts​

Brand​

A named label used to classify products by manufacturer or product line.

FieldTypeDescription
idUUIDPrimary key (auto-generated)
namestringDisplay name (required)
businessIdUUIDFK to business
isActivebooleanDefaults to true
createdByUUIDFK to user
updatedByUUIDFK to user (nullable)
createdAttimestamptzAuto-set on creation
updatedAttimestamptzSet on update

API Endpoints​

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

POST /brands​

Create a new brand.

Body:

{
"name": "Nike",
"businessId": "<uuid>",
"isActive": true,
"createdBy": "<uuid>"
}

Responses: 201 Created | 400 Invalid body | 401 Unauthorized

GET /brands​

List brands with pagination, search, and sorting.

Query parameters:

ParamRequiredDescription
businessIdNoUUID of the business (filter)
pageNoPage number (default: 1)
sizeNoPage size (default: 10)
searchNoCase-insensitive name search
orderByNoSort field (name)
orderNoasc or desc

Responses: 200 Paginated list | 401 Unauthorized

GET /brands/:id​

Get a single brand by UUID.

Query parameters: businessId (required)

Responses: 200 Found | 404 Not found | 401 Unauthorized

PATCH /brands/:id​

Partially update a brand.

Body:

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

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

DELETE /brands/:id​

Delete a brand.

Query parameters: businessId (required)

Responses: 200 Deleted | 404 Not found | 401 Unauthorized


Data Import​

Brands can be bulk-imported via the data-import module. The BrandImportHandler supports:

  • Required field: name
  • Upsert behavior: matches by name within the business; updates if the brand exists, creates a new one otherwise.

  • Products — products reference brandId as a FK
  • Collections — merchandising collections can filter by brand
  • Markdown — MarkdownScopeType.Brand enables brand-level price markdowns