feat(F-090): completed feature
This commit is contained in:
@@ -4091,6 +4091,43 @@
|
||||
"close": true
|
||||
},
|
||||
"completed_at": "2026-08-20T19:34:12Z"
|
||||
},
|
||||
{
|
||||
"id": "F-090",
|
||||
"type": "fix",
|
||||
"title": "Product listing metadata and variant SKU/EAN edits are not reflected",
|
||||
"problem": "The admin product listing receives products without brand and expirationDate because catalog serialization omits those fields. In the product editor inventory section, SKU and EAN saves update row state but the display renders from the original variants array, so edited values appear not to persist.",
|
||||
"goal": "Include brand and expirationDate in catalog product serialization and render saved SKU/EAN values from the updated row state so edits remain visible after the PATCH succeeds.",
|
||||
"scope_in": [
|
||||
"backend catalog serialization",
|
||||
"admin product listing",
|
||||
"admin product inventory section"
|
||||
],
|
||||
"scope_out": [
|
||||
"No database schema change",
|
||||
"no new fields",
|
||||
"no API redesign"
|
||||
],
|
||||
"priority": "high",
|
||||
"risk": "low",
|
||||
"description": "Problem: The admin product listing receives products without brand and expirationDate because catalog serialization omits those fields. In the product editor inventory section, SKU and EAN saves update row state but the display renders from the original variants array, so edited values appear not to persist.. Goal: Include brand and expirationDate in catalog product serialization and render saved SKU/EAN values from the updated row state so edits remain visible after the PATCH succeeds.. Scope IN: backend catalog serialization, admin product listing, admin product inventory section. Scope OUT: No database schema change, no new fields, no API redesign. Type: fix. Priority: high. Risk: low.",
|
||||
"acceptance": [
|
||||
"- Product list response includes brand and expirationDate when present",
|
||||
"- Product listing displays the brand name and expiration date instead of — for populated products",
|
||||
"- Successful SKU edit remains visible after leaving edit mode",
|
||||
"- Successful EAN edit remains visible after leaving edit mode",
|
||||
"- Existing PATCH /products/:id/variants/:variantId behavior remains used",
|
||||
"- Admin typecheck/lint and verify.sh pass"
|
||||
],
|
||||
"status": "done",
|
||||
"created_at": "2026-08-20",
|
||||
"gates": {
|
||||
"reviewer": true,
|
||||
"security": true,
|
||||
"qa": true,
|
||||
"close": true
|
||||
},
|
||||
"completed_at": "2026-08-20T19:40:41Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -455,13 +455,13 @@ export function InventorySection({ productId }: InventorySectionProps) {
|
||||
onClick={() =>
|
||||
setRows((prev) => ({
|
||||
...prev,
|
||||
[variant.id]: { ...prev[variant.id], editingSku: true, skuValue: variant.sku },
|
||||
[variant.id]: { ...prev[variant.id], editingSku: true, skuValue: r.variant.sku },
|
||||
}))
|
||||
}
|
||||
title="Clic para editar SKU"
|
||||
className="font-mono text-xs text-gray-600 hover:text-[#2D6A4F] cursor-text text-left w-full truncate block"
|
||||
>
|
||||
{variant.sku}
|
||||
{r.variant.sku}
|
||||
</button>
|
||||
)}
|
||||
</td>
|
||||
@@ -503,14 +503,14 @@ export function InventorySection({ productId }: InventorySectionProps) {
|
||||
[variant.id]: {
|
||||
...prev[variant.id],
|
||||
editingEan: true,
|
||||
eanValue: variant.ean ?? '',
|
||||
eanValue: r.variant.ean ?? '',
|
||||
},
|
||||
}))
|
||||
}
|
||||
title="Clic para editar EAN"
|
||||
className="font-mono text-xs text-gray-500 hover:text-[#2D6A4F] cursor-text text-left w-full truncate block"
|
||||
>
|
||||
{variant.ean ?? '—'}
|
||||
{r.variant.ean ?? '—'}
|
||||
</button>
|
||||
)}
|
||||
</td>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -663,6 +663,8 @@ function serializeProduct(product: Product, images: ProductImage[] = []) {
|
||||
seoDescription: product.seoDescription,
|
||||
categoryIds: product.categoryIds,
|
||||
brandId: product.brandId,
|
||||
brand: product.brand,
|
||||
expirationDate: product.expirationDate,
|
||||
createdAt: product.createdAt.toISOString(),
|
||||
updatedAt: product.updatedAt.toISOString(),
|
||||
};
|
||||
|
||||
17
work/artifacts/F-090/implementer.md
Normal file
17
work/artifacts/F-090/implementer.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# F-090 — Implementer evidence
|
||||
|
||||
## Changes
|
||||
|
||||
- `project/src/modules/catalog/api/catalog.routes.ts`
|
||||
- `serializeProduct` now includes `brand` and `expirationDate`, which are already present on the domain/repository product.
|
||||
- This fixes `/catalog/products` responses consumed by the admin listing.
|
||||
- `project/apps/admin/src/features/products/components/sections/InventorySection.tsx`
|
||||
- SKU and EAN display/edit controls now use `rows[variant.id].variant`, the state updated after a successful PATCH, instead of the immutable initial `variants` array.
|
||||
- This keeps the newly saved value visible after leaving edit mode and when opening the editor again.
|
||||
|
||||
## Validation
|
||||
|
||||
- Root `npm run typecheck` → exit 0
|
||||
- Admin `npx tsc --noEmit` → exit 0
|
||||
- Admin ESLint on `InventorySection.tsx` → exit 0
|
||||
- Backend PATCH route remains `/products/:id/variants/:variantId`; no API contract or schema change.
|
||||
15
work/artifacts/F-090/leader-close.json
Normal file
15
work/artifacts/F-090/leader-close.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"feature_id": "F-090",
|
||||
"agent": "leader",
|
||||
"verdict": "APPROVED",
|
||||
"summary": "F-090 restores brand and expiration data in the admin product list and keeps successful SKU/EAN edits visible from updated row state.",
|
||||
"evidence": [
|
||||
"reviewer.json verdict=APPROVED",
|
||||
"security.json verdict=APPROVED",
|
||||
"qa.json verdict=APPROVED",
|
||||
"scripts/verify.sh exit 0",
|
||||
"Root and admin typechecks exit 0",
|
||||
"Root test suite: 133 passed, 56 skipped"
|
||||
],
|
||||
"timestamp": "2026-08-20T19:40:40Z"
|
||||
}
|
||||
14
work/artifacts/F-090/qa.json
Normal file
14
work/artifacts/F-090/qa.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"feature_id": "F-090",
|
||||
"agent": "qa",
|
||||
"verdict": "APPROVED",
|
||||
"summary": "Product metadata serialization and updated SKU/EAN row rendering pass backend, admin, unit, and harness checks.",
|
||||
"evidence": [
|
||||
"Root npm run typecheck exit 0",
|
||||
"Admin npx tsc --noEmit exit 0",
|
||||
"Admin ESLint on InventorySection exit 0",
|
||||
"Root npm test: 42 files passed, 133 tests passed, 15 files/56 tests skipped",
|
||||
"scripts/verify.sh exit 0"
|
||||
],
|
||||
"timestamp": "2026-08-20T19:40:30Z"
|
||||
}
|
||||
13
work/artifacts/F-090/reviewer.json
Normal file
13
work/artifacts/F-090/reviewer.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"feature_id": "F-090",
|
||||
"agent": "reviewer",
|
||||
"verdict": "APPROVED",
|
||||
"summary": "The catalog response now exposes existing brand and expiration data, and SKU/EAN cells render the row state that is updated by the existing variant PATCH flow.",
|
||||
"evidence": [
|
||||
"serializeProduct includes brand and expirationDate without changing persistence or routes",
|
||||
"SKU and EAN non-editing cells use r.variant values updated after save",
|
||||
"Existing PATCH /products/:id/variants/:variantId remains the persistence path",
|
||||
"Root and admin TypeScript checks pass"
|
||||
],
|
||||
"timestamp": "2026-08-20T19:40:00Z"
|
||||
}
|
||||
13
work/artifacts/F-090/security.json
Normal file
13
work/artifacts/F-090/security.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"feature_id": "F-090",
|
||||
"agent": "security",
|
||||
"verdict": "APPROVED",
|
||||
"summary": "The change exposes only existing product fields already authorized by the admin endpoint and changes no authorization, validation, SQL, or client input boundaries.",
|
||||
"evidence": [
|
||||
"brand and expirationDate are existing domain fields from the authenticated admin catalog response",
|
||||
"SKU/EAN still use the existing authenticated admin PATCH endpoint and backend validation",
|
||||
"No new dependencies, secrets, routes, SQL, or authorization behavior",
|
||||
"No unsafe URL or HTML handling added"
|
||||
],
|
||||
"timestamp": "2026-08-20T19:40:10Z"
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
# Feature actual
|
||||
|
||||
## Feature activa: ninguna — F-089 cerrada
|
||||
## Feature activa: F-090 (in_progress) — Product listing metadata and SKU/EAN edits are not reflected
|
||||
|
||||
Backlog: 157 features (148 done, 9 pending, 0 in_progress).
|
||||
Backlog: 158 features (148 done, 9 pending, 1 in_progress).
|
||||
|
||||
Últimas features cerradas: **F-080**, **F-081**, **F-082**, **F-083**, **F-084**, **F-085**, **F-086**, **F-087**.
|
||||
|
||||
## Incidencia actual (2026-08-20)
|
||||
|
||||
El listado admin muestra `—` para marca/caducidad porque la serialización del catálogo omite ambos campos. En el editor de producto, SKU/EAN se guardan en `rows` pero la vista no editable usa el array `variants` inicial y vuelve a mostrar valores antiguos. F-090 corrige serialización y fuente de renderizado.
|
||||
|
||||
## Última incidencia resuelta (2026-08-20)
|
||||
|
||||
F-089 cerrada con todos los gates aprobados. El enlace del listado admin apunta ahora a `http://192.168.18.93:3003/products/<slug>`, ruta del frontend customer.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"feature_id": "F-089",
|
||||
"feature_id": "F-090",
|
||||
"stage": "close",
|
||||
"agent": "leader",
|
||||
"action": "F-089 cerrado: enlace del listado usa /products/:slug y verify.sh verde",
|
||||
"state": "done",
|
||||
"action": "Validate F-090 gates and close metadata/save-state fix",
|
||||
"state": "running",
|
||||
"next_agent": "leader",
|
||||
"waiting_for": "Seleccionar la siguiente feature pending",
|
||||
"updated_at": "2026-08-20T19:34:21Z",
|
||||
"waiting_for": "verify.sh green",
|
||||
"updated_at": "2026-08-20T19:40:33Z",
|
||||
"timeline": [
|
||||
{
|
||||
"ts": "2026-08-20T19:15:36Z",
|
||||
@@ -105,6 +105,48 @@
|
||||
"stage": "close",
|
||||
"state": "done",
|
||||
"message": "F-089 cerrado: enlace del listado usa /products/:slug y verify.sh verde"
|
||||
},
|
||||
{
|
||||
"ts": "2026-08-20T19:38:52Z",
|
||||
"agent": "leader",
|
||||
"stage": "intake",
|
||||
"state": "running",
|
||||
"message": "Triage missing brand/expiration serialization and stale SKU/EAN display state"
|
||||
},
|
||||
{
|
||||
"ts": "2026-08-20T19:39:07Z",
|
||||
"agent": "implementer",
|
||||
"stage": "build",
|
||||
"state": "running",
|
||||
"message": "Include brand/expiration in catalog serialization and render current row SKU/EAN state"
|
||||
},
|
||||
{
|
||||
"ts": "2026-08-20T19:39:49Z",
|
||||
"agent": "reviewer",
|
||||
"stage": "review_gate",
|
||||
"state": "running",
|
||||
"message": "Review product metadata serialization and current SKU/EAN row rendering"
|
||||
},
|
||||
{
|
||||
"ts": "2026-08-20T19:39:59Z",
|
||||
"agent": "security",
|
||||
"stage": "security_gate",
|
||||
"state": "running",
|
||||
"message": "Check F-090 serialization exposure and variant edit scope"
|
||||
},
|
||||
{
|
||||
"ts": "2026-08-20T19:40:08Z",
|
||||
"agent": "qa",
|
||||
"stage": "qa_gate",
|
||||
"state": "running",
|
||||
"message": "Run F-090 typecheck, lint, tests, and verify"
|
||||
},
|
||||
{
|
||||
"ts": "2026-08-20T19:40:33Z",
|
||||
"agent": "leader",
|
||||
"stage": "close",
|
||||
"state": "running",
|
||||
"message": "Validate F-090 gates and close metadata/save-state fix"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user