feat(F-138): completed feature
This commit is contained in:
@@ -1,30 +1,29 @@
|
||||
# F-154 — Admin: separate customers from internal users
|
||||
# F-138 — Auto-sembrar fila de precio en creación de variante
|
||||
|
||||
## Problem
|
||||
El panel admin muestra usuarios mezclados. `GET /users` (módulo `users`) devuelve
|
||||
TODOS los identity_users (clientes + backoffice) y `GET /admin/users` (módulo `security`)
|
||||
por defecto también devuelve todos. La página Customers llama a `/api/users` y la página
|
||||
Users llama a `/api/admin/users`; como ambos devuelven todo, ambos listados aparecen
|
||||
mezclados (conceptos de identity/storefront con backoffice en un mismo listado).
|
||||
## Título
|
||||
Auto-sembrar fila de precio en creación de variante para evitar la ventana 404 en `GET /pricing/variants/:id`.
|
||||
|
||||
## Goal
|
||||
Customers muestra SOLO clientes storefront (`role = 'customer'`); Users muestra SOLO
|
||||
usuarios internos/backoffice (`role != 'customer'`). Separación forzada en el backend
|
||||
(single source of truth), no solo filtrado cliente.
|
||||
## Contexto / Problema
|
||||
- `GET /pricing/variants/:variantId` (modulo `pricing`, `PricingService.getVariantPrice` → `PgPricingRepository.findByVariantId`) devuelve **404** cuando `pricing_variant_prices` no tiene fila para `variant_id`.
|
||||
- `CreateProductVariant.execute` (`catalog/application/variant-use-cases.ts`) solo llama a `variants.create` (inserta en `catalog_product_variants`) y **nunca** inserta en `pricing_variant_prices`.
|
||||
- 3 call sites disparan `createVariant.execute`:
|
||||
1. Creación de producto con variante por defecto (`POST /products`, autovariante `SKU-MV-{id}`).
|
||||
2. Lazy migration en `GET /products/:id/variants` (producto legacy sin variantes → crea variante default para admin).
|
||||
3. `POST /products/:id/variants` (creación explícita de variante).
|
||||
- En todos los casos, la variante existe en `catalog_product_variants` pero `GET /pricing/variants/:variantId` 404ea **hasta que un admin no asocie un precio** → la carrotera/pos pueden romper ("el precio no existe").
|
||||
|
||||
## Scope IN
|
||||
- `project/src/modules/users` (`listCustomers` / `GET /users`): filtrar `role = 'customer'`.
|
||||
- `project/src/modules/security` (`GET /admin/users`): default `role != 'customer'`;
|
||||
`?role=admin|editor` sigue afinando dentro de internos.
|
||||
- `project/apps/admin/.../users/page.tsx`: quitar opción `customer` del dropdown (Users = backoffice).
|
||||
- Tests unitarios (mock pool, sin DB) + actualizar itest AC2/AC3.
|
||||
## Solución
|
||||
Sembrar (seed) una fila de precio por defecto **inmediatamente después de crear la variante**, con valores neutros: `net_unit_amount_cents = 0`, `vat_rate = 'general'`, `currency = 'EUR'` (default DDL). El sembrado es **idempotente** (`ON CONFLICT (variant_id) DO NOTHING`) y **best-effort**: si falla, la creación de la variante no se anula (la variante primaria es la prioridad; el precio es secundario).
|
||||
|
||||
## Scope OUT
|
||||
- No se crea `/customers` (el cliente ya consume `/users`).
|
||||
- `/users/:id`, `/users/:id/addresses` (owner-or-admin) siguen sin filtro por rol (un admin
|
||||
ve el perfil de cualquier usuario; un cliente ve el suyo).
|
||||
- No migración (identity_users.role ya existe, NOT NULL con default 'customer').
|
||||
- Frontend Customer page: sin cambio (ya llama /users → ahora customer-only).
|
||||
## Alcance
|
||||
- Backend: `pricing` (nuevo método `seedVariantPrice`) + `catalog` (inyección en `CreateProductVariant` + wiring build-app).
|
||||
- Frontend: N/A (no hay cambios de UI).
|
||||
- Migración: N/A — `pricing_variant_prices.variant_id` ya es UNIQUE/PK (lo demuestra `setVariantPrice` usando `ON CONFLICT (variant_id)`); no se requiere migración ni columna nueva.
|
||||
|
||||
## Type
|
||||
fix — high priority / high risk.
|
||||
## Definición de terminado
|
||||
- [x] `PricingService.seedVariantPrice(variantId)` existe + persiste fila default.
|
||||
- [x] `CreateProductVariant` llama a `seedVariantPrice` tras `variants.create`.
|
||||
- [x] Los 3 call sites dejan fila de precio tras crear variante.
|
||||
- [x] Re-sembrar es no-op (idempotente).
|
||||
- [x] Tests unitarios (sin DB) pasan; itest de AC skipped sin `TEST_DATABASE_URL`.
|
||||
- [x] `npm run typecheck` 0 errores; `npm test` (targeted) verde; `verify.sh` green.
|
||||
|
||||
Reference in New Issue
Block a user