Brand Series Module - Feature List
Brand series feature surfaces, admin capabilities, customer listing, and storefront merchandising rules.
Brand Series Module - Feature List
1. Feature Overview
Brand Series groups product collections within a brand for storefront merchandising. Each series belongs to exactly one brand and one category, and can be linked from individual products via a nullable foreign key.
The module follows a simple execution model:
- all operations are synchronous (no queue workers)
- admin surface provides full CRUD plus reorder
- customer/mobile surface provides visible-only listing and slug-based detail
The customer surface is public (no authentication required) and mounted through the shared mobile composition layer.
2. Route Ownership and Surfaces
| Surface | Route prefix | Owner |
|---|---|---|
| Admin API | /api/admin/brand-series | BrandSeriesAdminController |
| Customer API | /api/brand-series | BrandSeriesCustomerController |
| Mobile-composed customer API | /api/mobile/brand-series | MobileModule composition of BrandSeriesCustomerModule |
Swagger tags used by brand series controllers:
Brand Series (Admin)Brand Series
Customer/mobile routes are public (no JWT required) and filtered to visible series only.
3. Admin Feature Matrix
| Capability | Endpoint | AuthZ |
|---|---|---|
| List brand series (paginated + filters) | GET /api/admin/brand-series | BrandSeries_READ |
| Brand series detail by id | GET /api/admin/brand-series/:id | BrandSeries_READ |
| Create brand series | POST /api/admin/brand-series | BrandSeries_CREATE |
| Update brand series | PATCH /api/admin/brand-series/:id | BrandSeries_UPDATE |
| Reorder brand series | PUT /api/admin/brand-series/reorder | BrandSeries_UPDATE |
| Delete brand series | DELETE /api/admin/brand-series/:id | BrandSeries_DELETE |
4. Customer/Mobile Feature Matrix
| Capability | Endpoint | Visibility filter |
|---|---|---|
| List brand series (paginated + filters) | GET /api/brand-series | Visible only (isActive = true) |
| Brand series detail by slug | GET /api/brand-series/:slug | Visible only |
Notes:
- Customer list accepts optional
brandIdandcategoryIdquery parameters to scope results. - Mobile-composed equivalents are available at
/api/mobile/brand-series/...via routing composition. - Customer list and detail include resolved
brandName,brandSlug,categoryName, andcategorySlugfor storefront rendering. - Customer detail additionally includes
productCount(count of published sellable products linked to the series).
5. Key Business Rules
- Series name must be unique within brand-category pair (enforced by DB unique constraint
brand_series_brand_category_uidx). - Slug is auto-generated from name and suffix-resolved on conflict (e.g.
dell-laptops,dell-laptops-1,dell-laptops-2). - Slug has a database-level unique constraint (
brand_series_slug_uidx). - Public endpoints only return series where
isActive = true. - Reorder accepts an array of
{ id: number, order: number }and updates all rows in a loop (no transaction wrapper; each update is atomic). - Product-to-series linkage is via
product.series_id(nullable FK tobrand_series.id). - Admin list defaults to
order ASC, name ASCfor consistent storefront ordering. - Customer list defaults to
order ASC, name ASCfor consistent display order. brandIdandcategoryIdare required for creation; both are validated against existing records.descriptionandimageUrlare optional nullable fields.
6. State Models
6.1 Simple active toggle lifecycle
Brand series does not have a complex state machine. The only state dimension is visibility:
isActive = true <--> isActive = false
isActive = true(default): series appears in customer/public endpoints and can be linked from products.isActive = false: series is hidden from customer/public endpoints but remains accessible via admin.- Product-to-series linkage via
product.series_idis independent of the series visibility state.
6.2 No status history table
Unlike Order, Brand Series does not maintain an append-only status history log. State changes are tracked via the updatedAt timestamp only. Audit trails for series visibility changes rely on database-level logging or application-level introspection.
7. Caching Strategy
Read-side keyspaces:
catalog:brand-series:list:*-- customer list responsescatalog:brand-series:detail:slug:*-- customer slug-based detail
Configured TTL:
CATALOG_CACHE_TTL_SECONDS(default300, falls back toREDIS_CACHE_TTL_SECONDSthen300).
Admin endpoints bypass cache and query the database directly on every request.
7.1 Invalidation triggers
Admin write operations (create, update, delete, reorder) invalidate:
- All cached list keys via
catalog:brand-series:list:*pattern invalidation - Affected detail keys via
catalog:brand-series:detail:slug:<slug>key invalidation
Customer/mobile read endpoints use getOrSet pattern: cache hit returns immediately, cache miss fetches from DB and populates the cache.
7.2 Cache key composition
Customer list cache keys are built from the query parameters:
catalog:brand-series:list:brand:<brandId>-cat:<categoryId>-page:<page>-size:<size>Customer detail cache keys:
catalog:brand-series:detail:slug:<slug>8. Rate Limiting
This module does not apply rate limiting.
Customer endpoints are public and currently unthrottled. If storefront abuse is observed, rate limiting can be added via the common @Throttle() decorator or a reverse-proxy layer (e.g. Cloudflare, Nginx).
Admin endpoints rely on the global admin rate limiting defaults.
9. Queue/Worker Features
No queues or workers are used in this module.
All operations are synchronous and complete within the request-response lifecycle. Unlike Order, there are no async commands, no background jobs, and no outbox events.
10. Error UX Mapping
| errorCode | Typical HTTP | UX action |
|---|---|---|
BRAND_SERIES_NOT_FOUND | 404 | Show not-found notice; disable series CTA buttons |
BRAND_SERIES_DUPLICATE | 409 | Highlight name field; show "series for this brand and category already exists" |
BRAND_SERIES_SLUG_EXISTS | 409 | Internal error; show generic retry message (should not occur in normal flow) |
BRAND_NOT_FOUND | 404 | Validate brand selection before submission |
CATEGORY_NOT_FOUND | 404 | Validate category selection before submission |
RATE_LIMIT_EXCEEDED | 429 | Backoff and retry after short delay (admin writes only) |
ERR_CONFIG_INVALID | 503 | Show generic server support message |
11. Integration Flows
11.1 Admin creates series and associates products
An admin creates a brand series and links products to it.
- Admin calls
POST /api/admin/brand-serieswith{ brandId, categoryId, name, description?, imageUrl?, isActive?, order? }. - System validates brand and category exist.
- System generates URL-safe slug from name with suffix resolution on conflict.
- System creates brand_series row with
isActive: trueby default. - Product team updates products by setting
product.series_idto the new series id. - Customer visiting the brand storefront now sees the series in the series list.
- Customer can drill into series to see all published sellable products.
11.2 Customer discovers brand and browses series
A customer explores a brand's product lineup through series groupings.
- Customer navigates to brand page on the storefront.
- Storefront calls
GET /api/brand-series?brandId=<brandId>to fetch series for this brand. - Customer sees visible series cards (name, description, image, product count).
- Customer clicks a series to drill in.
- Storefront calls
GET /api/brand-series/:slugfor series detail. - Response includes
productCountshowing how many products are available. - Storefront displays products filtered by
series_idbelonging to this series.
11.3 Admin reorders series for storefront sequencing
An admin changes the display order of series within a brand.
- Admin opens brand series management in admin panel.
- Admin uses drag-and-drop to reorder series items.
- Admin panel calls
PUT /api/admin/brand-series/reorderwith{ items: [{ id: 1, order: 0 }, { id: 2, order: 1 }] }. - System updates each series
orderfield individually. - Admin list cache is invalidated via pattern
catalog:brand-series:list:*. - On next storefront load, series display in the new order.
12. Release/QA Checklist
- Admin list returns all series with correct pagination, brandId/categoryId/isActive filters.
- Admin create validates brand and category existence; returns
BRAND_NOT_FOUND/CATEGORY_NOT_FOUNDfor invalid references. - Admin create auto-generates slug; duplicate name within brand-category returns
BRAND_SERIES_DUPLICATE. - Admin update with name change regenerates slug and invalidates old+new detail cache.
- Admin reorder updates all items in the array; list cache is invalidated.
- Admin delete removes series and invalidates list+detail cache.
- Customer list returns only
isActive = trueseries; respects brandId/categoryId filters. - Customer detail by slug returns 404 for inactive or non-existent series.
- Customer detail includes accurate
productCount(published + sellable products only). - Mobile-composed routes (
/api/mobile/brand-series/...) resolve throughMobileModulerouting. - Cache TTL is respected; writes invalidate customer list and detail cache correctly.
13. See Also
- API Reference: See Brand Series - API & Integration Guide Section 11 (Endpoint Reference + Payload Cheatsheet) for complete request/response DTOs.
- Backend Reference: See Brand Series - Backend Documentation Section 3 (Data Model) for schema details.
- Brand Module: See
/docs/developer/catalog/brandfor brand-level feature documentation. - Product Module: See
/docs/developer/productfor product-to-series linkage documentation.