feat(F-093): completed feature
This commit is contained in:
@@ -4196,6 +4196,40 @@
|
|||||||
"close": true
|
"close": true
|
||||||
},
|
},
|
||||||
"completed_at": "2026-08-20T19:51:46Z"
|
"completed_at": "2026-08-20T19:51:46Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "F-093",
|
||||||
|
"type": "fix",
|
||||||
|
"title": "Inventory search by product name or EAN",
|
||||||
|
"problem": "Inventory search currently sends q to the admin product list endpoint, but the backend list query only matches product name. Searching a variant EAN therefore returns no inventory rows.",
|
||||||
|
"goal": "Make the inventory product lookup match product name or any variant EAN, and label the search input accordingly.",
|
||||||
|
"scope_in": [
|
||||||
|
"admin inventory search and catalog admin list query"
|
||||||
|
],
|
||||||
|
"scope_out": [
|
||||||
|
"No SKU search",
|
||||||
|
"no changes to variant uniqueness",
|
||||||
|
"no schema change"
|
||||||
|
],
|
||||||
|
"priority": "med",
|
||||||
|
"risk": "low",
|
||||||
|
"description": "Problem: Inventory search currently sends q to the admin product list endpoint, but the backend list query only matches product name. Searching a variant EAN therefore returns no inventory rows.. Goal: Make the inventory product lookup match product name or any variant EAN, and label the search input accordingly.. Scope IN: admin inventory search and catalog admin list query. Scope OUT: No SKU search, no changes to variant uniqueness, no schema change. Type: fix. Priority: med. Risk: low.",
|
||||||
|
"acceptance": [
|
||||||
|
"- Inventory search by product name returns matching variants",
|
||||||
|
"- Inventory search by EAN returns the product's variants",
|
||||||
|
"- Search remains case-insensitive for names and supports partial EAN input",
|
||||||
|
"- Placeholder states EAN or product name",
|
||||||
|
"- Typecheck, tests, 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:57:43Z"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ export default function InventoryPage() {
|
|||||||
type="search"
|
type="search"
|
||||||
id="admin-inventory-search"
|
id="admin-inventory-search"
|
||||||
name="q"
|
name="q"
|
||||||
placeholder="Buscar por producto o SKU..."
|
placeholder="Buscar por EAN o nombre..."
|
||||||
value={search}
|
value={search}
|
||||||
onChange={(e) => setSearch(e.target.value)}
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
className="w-full pl-10 pr-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] focus:border-transparent outline-none"
|
className="w-full pl-10 pr-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] focus:border-transparent outline-none"
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -189,7 +189,13 @@ export class PgProductRepository implements ProductRepository {
|
|||||||
|
|
||||||
const countResult = await this.pool.query<{ count: string }>(
|
const countResult = await this.pool.query<{ count: string }>(
|
||||||
q
|
q
|
||||||
? `SELECT COUNT(*) FROM catalog_products WHERE name ILIKE $1`
|
? `SELECT COUNT(*)
|
||||||
|
FROM catalog_products p
|
||||||
|
WHERE p.name ILIKE $1
|
||||||
|
OR EXISTS (
|
||||||
|
SELECT 1 FROM catalog_product_variants v
|
||||||
|
WHERE v.product_id = p.id AND v.ean ILIKE $1
|
||||||
|
)`
|
||||||
: 'SELECT COUNT(*) FROM catalog_products',
|
: 'SELECT COUNT(*) FROM catalog_products',
|
||||||
q ? [`%${q}%`] : [],
|
q ? [`%${q}%`] : [],
|
||||||
);
|
);
|
||||||
@@ -202,6 +208,10 @@ export class PgProductRepository implements ProductRepository {
|
|||||||
LEFT JOIN catalog_product_categories pc ON pc.product_id = p.id
|
LEFT JOIN catalog_product_categories pc ON pc.product_id = p.id
|
||||||
LEFT JOIN brands_brands b ON b.id = p.brand_id
|
LEFT JOIN brands_brands b ON b.id = p.brand_id
|
||||||
WHERE p.name ILIKE $1
|
WHERE p.name ILIKE $1
|
||||||
|
OR EXISTS (
|
||||||
|
SELECT 1 FROM catalog_product_variants v
|
||||||
|
WHERE v.product_id = p.id AND v.ean ILIKE $1
|
||||||
|
)
|
||||||
GROUP BY p.id, b.name, b.slug
|
GROUP BY p.id, b.name, b.slug
|
||||||
ORDER BY p.created_at DESC
|
ORDER BY p.created_at DESC
|
||||||
LIMIT $2 OFFSET $3`
|
LIMIT $2 OFFSET $3`
|
||||||
|
|||||||
14
work/artifacts/F-093/implementer.md
Normal file
14
work/artifacts/F-093/implementer.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# F-093 — Implementer evidence
|
||||||
|
|
||||||
|
## Change
|
||||||
|
|
||||||
|
- Admin catalog `listAll` now matches `q` against product name or any related variant EAN using an `EXISTS` query.
|
||||||
|
- Inventory search placeholder now says `Buscar por EAN o nombre...`.
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
- Root `npm run typecheck` → exit 0
|
||||||
|
- Root `npm test -- --run` → 133 passed, 56 skipped
|
||||||
|
- Admin `npx tsc --noEmit` → exit 0
|
||||||
|
- Admin ESLint on inventory page → exit 0
|
||||||
|
- Search remains case-insensitive for names and supports partial EAN values.
|
||||||
14
work/artifacts/F-093/leader-close.json
Normal file
14
work/artifacts/F-093/leader-close.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"feature_id": "F-093",
|
||||||
|
"agent": "leader",
|
||||||
|
"verdict": "APPROVED",
|
||||||
|
"summary": "F-093 adds inventory search by product name or variant EAN and passes all gates.",
|
||||||
|
"evidence": [
|
||||||
|
"reviewer.json verdict=APPROVED",
|
||||||
|
"security.json verdict=APPROVED",
|
||||||
|
"qa.json verdict=APPROVED",
|
||||||
|
"scripts/verify.sh exit 0",
|
||||||
|
"Root tests: 133 passed, 56 skipped"
|
||||||
|
],
|
||||||
|
"timestamp": "2026-08-20T19:57:40Z"
|
||||||
|
}
|
||||||
14
work/artifacts/F-093/qa.json
Normal file
14
work/artifacts/F-093/qa.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"feature_id": "F-093",
|
||||||
|
"agent": "qa",
|
||||||
|
"verdict": "APPROVED",
|
||||||
|
"summary": "Inventory EAN/name search changes pass typechecks, tests, lint, and harness verification.",
|
||||||
|
"evidence": [
|
||||||
|
"Root npm run typecheck exit 0",
|
||||||
|
"Root tests: 133 passed, 56 skipped",
|
||||||
|
"Admin npx tsc --noEmit exit 0",
|
||||||
|
"Admin inventory page ESLint exit 0",
|
||||||
|
"scripts/verify.sh exit 0"
|
||||||
|
],
|
||||||
|
"timestamp": "2026-08-20T19:57:30Z"
|
||||||
|
}
|
||||||
13
work/artifacts/F-093/reviewer.json
Normal file
13
work/artifacts/F-093/reviewer.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"feature_id": "F-093",
|
||||||
|
"agent": "reviewer",
|
||||||
|
"verdict": "APPROVED",
|
||||||
|
"summary": "Inventory search now finds products by name or related variant EAN without adding SKU matching or changing the API shape.",
|
||||||
|
"evidence": [
|
||||||
|
"Count and item queries use product name ILIKE or related variant EAN ILIKE",
|
||||||
|
"EXISTS avoids duplicate products when multiple variants are present",
|
||||||
|
"Inventory placeholder matches the supported search fields",
|
||||||
|
"Typechecks pass"
|
||||||
|
],
|
||||||
|
"timestamp": "2026-08-20T19:57:10Z"
|
||||||
|
}
|
||||||
13
work/artifacts/F-093/security.json
Normal file
13
work/artifacts/F-093/security.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"feature_id": "F-093",
|
||||||
|
"agent": "security",
|
||||||
|
"verdict": "APPROVED",
|
||||||
|
"summary": "EAN search uses the existing parameterized query value and does not expose new data or alter authorization.",
|
||||||
|
"evidence": [
|
||||||
|
"Search value remains passed as PostgreSQL parameter $1",
|
||||||
|
"No SQL string interpolation was added",
|
||||||
|
"Admin authentication and product visibility are unchanged",
|
||||||
|
"No schema, dependency, or secret changes"
|
||||||
|
],
|
||||||
|
"timestamp": "2026-08-20T19:57:20Z"
|
||||||
|
}
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
# Feature actual
|
# Feature actual
|
||||||
|
|
||||||
## Feature activa: ninguna — F-092 cerrada
|
## Feature activa: F-093 (in_progress) — Inventory search by product name or EAN
|
||||||
|
|
||||||
Backlog: 160 features (151 done, 9 pending, 0 in_progress).
|
Backlog: 161 features (151 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**.
|
Últimas features cerradas: **F-080**, **F-081**, **F-082**, **F-083**, **F-084**, **F-085**, **F-086**, **F-087**.
|
||||||
|
|
||||||
|
## Incidencia actual (2026-08-20)
|
||||||
|
|
||||||
|
La búsqueda de Inventario envía `q`, pero el listado admin solo filtra por nombre de producto. F-093 añade coincidencias por EAN de variante y actualiza el placeholder a EAN o nombre.
|
||||||
|
|
||||||
## Última incidencia resuelta (2026-08-20)
|
## Última incidencia resuelta (2026-08-20)
|
||||||
|
|
||||||
F-092 cerrada con todos los gates aprobados. `Fecha de caducidad` está ahora en General; backend y admin fueron reconstruidos y desplegados.
|
F-092 cerrada con todos los gates aprobados. `Fecha de caducidad` está ahora en General; backend y admin fueron reconstruidos y desplegados.
|
||||||
|
|||||||
@@ -1,55 +1,13 @@
|
|||||||
{
|
{
|
||||||
"feature_id": "F-092",
|
"feature_id": "F-093",
|
||||||
"stage": "close",
|
"stage": "close",
|
||||||
"agent": "leader",
|
"agent": "leader",
|
||||||
"action": "F-092 cerrado: caducidad en General y backend/admin redeployados",
|
"action": "Validate F-093 gates and close inventory EAN/name search",
|
||||||
"state": "done",
|
"state": "running",
|
||||||
"next_agent": "leader",
|
"next_agent": "leader",
|
||||||
"waiting_for": "Seleccionar la siguiente feature pending",
|
"waiting_for": "verify.sh green",
|
||||||
"updated_at": "2026-08-20T19:51:56Z",
|
"updated_at": "2026-08-20T19:57:34Z",
|
||||||
"timeline": [
|
"timeline": [
|
||||||
{
|
|
||||||
"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"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ts": "2026-08-20T19:40:49Z",
|
|
||||||
"agent": "leader",
|
|
||||||
"stage": "close",
|
|
||||||
"state": "done",
|
|
||||||
"message": "F-090 cerrado: marca/caducidad serializadas y SKU/EAN reflejan guardado"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ts": "2026-08-20T19:44:59Z",
|
"ts": "2026-08-20T19:44:59Z",
|
||||||
"agent": "leader",
|
"agent": "leader",
|
||||||
@@ -147,6 +105,48 @@
|
|||||||
"stage": "close",
|
"stage": "close",
|
||||||
"state": "done",
|
"state": "done",
|
||||||
"message": "F-092 cerrado: caducidad en General y backend/admin redeployados"
|
"message": "F-092 cerrado: caducidad en General y backend/admin redeployados"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ts": "2026-08-20T19:55:40Z",
|
||||||
|
"agent": "leader",
|
||||||
|
"stage": "intake",
|
||||||
|
"state": "running",
|
||||||
|
"message": "Triage inventory search limited to product name; add EAN matching"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ts": "2026-08-20T19:55:51Z",
|
||||||
|
"agent": "implementer",
|
||||||
|
"stage": "build",
|
||||||
|
"state": "running",
|
||||||
|
"message": "Extend admin catalog list query with partial EAN matching and update inventory search label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ts": "2026-08-20T19:57:04Z",
|
||||||
|
"agent": "reviewer",
|
||||||
|
"stage": "review_gate",
|
||||||
|
"state": "running",
|
||||||
|
"message": "Review inventory EAN/name search query and UI label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ts": "2026-08-20T19:57:14Z",
|
||||||
|
"agent": "security",
|
||||||
|
"stage": "security_gate",
|
||||||
|
"state": "running",
|
||||||
|
"message": "Check EAN search query parameterization and scope"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ts": "2026-08-20T19:57:23Z",
|
||||||
|
"agent": "qa",
|
||||||
|
"stage": "qa_gate",
|
||||||
|
"state": "running",
|
||||||
|
"message": "Run inventory search checks and verify"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ts": "2026-08-20T19:57:34Z",
|
||||||
|
"agent": "leader",
|
||||||
|
"stage": "close",
|
||||||
|
"state": "running",
|
||||||
|
"message": "Validate F-093 gates and close inventory EAN/name search"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user