35 lines
2.0 KiB
Markdown
35 lines
2.0 KiB
Markdown
# F-079 — Architect: Product list /products does not show brand
|
|
|
|
## Root cause
|
|
|
|
The admin `/products` page already renders a `Marca` column with `{p.brand?.name ?? '—'}`, and the `Product` TS type already declares an optional `brand: { id, name, slug }`. However, the backend `PgProductRepository` never populates that field: `PRODUCT_COLUMNS` does not LEFT JOIN `brands_brands`, and `toProduct(row)` only emits `brandId: row.brand_id` without a denormalized `brand` object. So every row in the list renders `—` regardless of whether a brand is assigned.
|
|
|
|
## Design
|
|
|
|
Single change set in the repository:
|
|
|
|
1. **`ProductRow` interface** gains optional fields `brand_name: string | null` and `brand_slug: string | null`.
|
|
2. **`PRODUCT_COLUMNS`** is replaced with a subquery (`PRODUCT_BASE_COLUMNS`) that LEFT JOINs `brands_brands` and selects `b.name AS brand_name, b.slug AS brand_slug`. Existing queries (`findById`, `findActiveBySlug`, `listAll`) keep their semantics but read the new column set.
|
|
3. **`toProduct(row)`** emits `brand` only when `brand_id IS NOT NULL`:
|
|
```ts
|
|
brand: row.brand_id
|
|
? { id: row.brand_id, name: row.brand_name ?? '', slug: row.brand_slug ?? '' }
|
|
: undefined,
|
|
```
|
|
When `brand_id` is null the frontend falls back to the existing `—` placeholder.
|
|
|
|
## No new tables, no API contract change.
|
|
|
|
Frontend is already prepared (the column, the type and the placeholder all exist). After the change:
|
|
- Products with a brand: column shows the brand name.
|
|
- Products without a brand: column shows `—` (placeholder behavior is unchanged).
|
|
|
|
## Risk
|
|
|
|
Low. Pure read-side change. Existing tests on the repository must still pass.
|
|
|
|
## Acceptance mapping
|
|
- "Each row in /products listing shows the brand name" → toProduct now hydrates `brand.name`.
|
|
- "Brand column header is present" → already in page.tsx.
|
|
- "Empty brand renders as a placeholder" → existing `p.brand?.name ?? '—'` handles it.
|
|
- "verify.sh is green" → no test regression expected. |