Skip to main content

Styles Module

Product styles represent classification groups within a brand (e.g., "IPA - India Pale Ale" under a beer brand, or "Slim Fit" under a clothing brand). A style belongs to a single brand and a single business.

Domain Concepts

EntityDescription
StyleA named classification linked to a brand and business. Has an optional styleCode for internal referencing.
BrandParent entity — each style belongs to exactly one brand.

Architecture

Follows hexagonal architecture:

domain/
styles-repository.domain.ts # IStylesRepository port + STYLES_REPOSITORY token
application/
styles.service.ts # Use cases (CRUD + paginated list)
infrastructure/
styles.repository.ts # Kysely adapter implementing IStylesRepository
interfaces/
styles.controller.ts # REST controller with RBAC guards
dtos/
create-style.dto.ts # Validation + Swagger for creation
update-style.dto.ts # Partial update DTO
query/
paginate-styles.query.ts # Pagination, search, sort query params

API Endpoints

All endpoints require authentication (Bearer token) and RBAC permission on PolicyResource.Style.

MethodPathPermissionDescription
POST/stylesCreateCreate a new style
GET/stylesReadList styles (paginated, searchable)
GET/styles/:idReadGet a style by ID
PATCH/styles/:idUpdatePartially update a style
DELETE/styles/:idDeleteDelete a style

Query Parameters (GET /styles)

ParamTypeRequiredDescription
businessIdUUIDNoFilter by business
searchstringNoSearch by style name or brand name
sizenumberNoPage size
pagenumberNoPage number
orderBystringNoSort field (name)
orderasc / descNoSort direction

Create Style (POST /styles)

{
"name": "IPA - India Pale Ale",
"businessId": "uuid",
"brandId": "uuid",
"createdBy": "uuid",
"isActive": true,
"styleCode": "STY-001"
}

Update Style (PATCH /styles/:id)

{
"name": "IPA - West Coast",
"updatedBy": "uuid",
"styleCode": "STY-002"
}

Design Decisions

  • Brand join on list: The findAll query joins with brand to include brandName in the response, avoiding N+1 queries.
  • Filter whitelist: Only whitelisted filter keys are accepted in the repository to prevent SQL injection through dynamic column names.
  • No soft delete: Styles are hard-deleted. Use isActive: false to deactivate instead of deleting.
  • Data import: Styles can be bulk-imported via the data-import module. CSV columns: name (required), code (optional), brandName (required). Brands must be imported first.