Skip to main content

Product Attributes Module

Overview

The product-attributes module manages the many-to-many association between products and attribute definitions. Each record stores a value linking a specific product to an attribute (e.g., "Color: Red", "Material: Cotton").

Product attributes are business-scoped: every entry belongs to a specific business and is isolated from other businesses.


Architecture

The module follows Hexagonal Architecture with strict layer boundaries.

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

Layer responsibilities

LayerResponsibility
domain/Repository port (IProductAttributesRepository) and PRODUCT_ATTRIBUTES_REPOSITORY injection token.
application/ProductAttributesService — orchestrates CRUD operations and pagination.
infrastructure/ProductAttributesRepository — Kysely queries against the product_attribute table. Implements IProductAttributesRepository.
interfaces/ProductAttributesController — maps HTTP requests to service calls. Thin layer with no business logic.

Dependency rule

interfaces → application → domain ← infrastructure

Domain Concepts

Product Attribute

An association record that assigns a value from an attribute definition to a specific product.

FieldTypeDescription
idUUIDPrimary key (auto-generated)
productIdUUIDFK to product
attributeIdUUIDFK to attribute
valuestringThe attribute value (e.g., "Red", "Large")
businessIdUUIDFK to business
isActivebooleanDefaults to true
createdByUUIDUser who created
updatedByUUIDUser who last updated (nullable)
createdAttimestamptzAuto-set on creation
updatedAttimestamptzSet on update

Access Control

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

ActionPermission
CreatePolicyAction.Create
ListPolicyAction.Read
Get by IDPolicyAction.Read
UpdatePolicyAction.Update
DeletePolicyAction.Delete

API Endpoints

POST /product-attributes

Create a new product attribute.

Body:

{
"productId": "<uuid>",
"attributeId": "<uuid>",
"value": "Red",
"businessId": "<uuid>",
"isActive": true,
"createdBy": "<uuid>"
}

Responses: 201 Created | 400 Invalid body | 401 Unauthorized

GET /product-attributes

List product attributes with pagination, search, and sorting.

Query parameters:

ParamRequiredDescription
businessIdNoUUID filter by business
productIdNoUUID filter by product
pageNoPage number (default: 1)
sizeNoPage size (default: 10; 0 = no limit)
searchNoCase-insensitive search on value, product name, attribute name
orderByNoSort field (value)
orderNoasc or desc

Responses: 200 Paginated list | 401 Unauthorized

GET /product-attributes/:id

Get a single product attribute by UUID.

Query parameters: businessId (required)

Responses: 200 Found | 404 Not found | 401 Unauthorized

PATCH /product-attributes/:id

Partially update a product attribute.

Body:

{
"value": "Blue",
"businessId": "<uuid>",
"updatedBy": "<uuid>"
}

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

DELETE /product-attributes/:id

Delete a product attribute.

Query parameters: businessId (required)

Responses: 200 Deleted | 404 Not found | 401 Unauthorized


  • Products — products own product attribute records via productId FK
  • Attributes — attribute definitions referenced via attributeId FK
  • Product Variants — variant option types/values are a separate system; product attributes store additional metadata