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
| Layer | Responsibility |
|---|---|
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.
| Field | Type | Description |
|---|---|---|
id | UUID | Primary key (auto-generated) |
name | string | Display name (required) |
businessId | UUID | FK to business |
isActive | boolean | Defaults to true |
createdBy | UUID | FK to user |
updatedBy | UUID | FK to user (nullable) |
createdAt | timestamptz | Auto-set on creation |
updatedAt | timestamptz | Set 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:
| Param | Required | Description |
|---|---|---|
businessId | No | UUID of the business (filter) |
page | No | Page number (default: 1) |
size | No | Page size (default: 10) |
search | No | Case-insensitive name search |
orderBy | No | Sort field (name) |
order | No | asc 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
namewithin the business; updates if the brand exists, creates a new one otherwise.
Related Modules
- Products — products reference
brandIdas a FK - Collections — merchandising collections can filter by brand
- Markdown —
MarkdownScopeType.Brandenables brand-level price markdowns