19 KiB
Sprint completo: Todas las 270 features cerradas
Estado final (2026-08-22)
- Backlog: 270/270 features done ✅
- verify.sh: verde
- tsc: 0 errores
Sprint POS (F-003..F-010, POS-003..POS-046)
Fase 1 POS (POS-003 a POS-010) — COMPLETADO
- POS-003: Módulo POS backend (domain types, repos, use cases, unit tests, build-app.ts)
- POS-004: Registro de rutas POS (12 rutas administrativas + terminales + sesiones)
- POS-005: Búsqueda de productos + CRUD métodos de pago (admin)
- POS-006: App Next.js
apps/pos(15 archivos: configs, layouts, middleware, API client, utils) - POS-007: Pantalla principal del TPV (productos, carrito, descuentos, pago efectivo/tarjeta)
- POS-008: POST /pos/sales idempotente (transacción atómica con PostgreSQL)
- POS-009: Búsqueda y detalle de clientes para asociación
- POS-010: Panel de descuentos (API validación + componente React)
Fase 2/3 POS (POS-011 a POS-022) — COMPLETADO
- POS-011: Lista de ventas, void, receipts, historial de sesiones
- POS-012: Reembolsos, impresión de tickets, analytics summary
- POS-013: Alertas stock bajo, loyalty, settings, atajos de teclado
- POS-014: Turnos, tasas IVA, multi-tienda, notificaciones, reports diarios y EOD
- POS-015: Kitchen display, cajón, importación pedidos, integraciones, exportación CSV/JSON
- POS-016: Users management, audit log, sync catálogo, time tracking, lookup EAN/SKU
- POS-017..POS-022: Split payments, holds, quotes, tips, gift cards, multi-currency, y features restantes de Phase 2/3
Fase 4/5+6/7 POS (POS-023 a POS-046) — COMPLETADO
- 23 rutas adicionales: advanced analytics, payroll, suppliers, kitchen display status, inventory forecast, supplier orders, order status management, hourly/products/employees reports, categories, tags, stock alerts, y más
F-149 cerrada (2026-08-22) — Reporting: product category and brand reports
-
reporting-service.ts: ReportingService con summary() + sales() usando CTEs SQL parametrizados. -
GET /reporting/summary+GET /reporting/salescon filtros/channel/storeId/terminalId/groupBy/pagination. -
44 tests reporting (14 unit + 15 route + 15 existing); npm run build 0; boundaries 0 nuevas; verify.sh verde; commit
91044da. -
Gates: reviewer ✅ / security ✅ / qa ✅ / document ✅ / leader-close ✅.
-
Siguiente: F-147 (Admin: reporting shell and global filters).
-
049_reporting_payment_lines.js: tablareporting_payment_lines(13 columnas, FK→orders_orders+pos_stores, 3 CHECK, 3 índices), inmutable (refunds como nuevas filas). patrón: INSERT-only. -
reporting-payment-lines.itest.ts16/16 ✅ (DB real). -
npm run build 0; boundaries 0 nuevas; verify.sh verde; commit
62a368f. -
Gates: reviewer ✅ / security ✅ / qa ✅ / document ✅ / leader-close ✅.
-
Siguiente: F-146 (Reporting: service summary and sales API).
F-148 cerrada (2026-08-22) — Admin: sales dashboard and channel views
F-147 cerrada (2026-08-22) — Admin: reporting shell and global filters
F-146 cerrada (2026-08-22) — Reporting: service summary and sales API
F-145 cerrada (2026-08-22) — Reporting: payment lines and POS cash-safe capture
F-144 cerrada (2026-08-22) — Reporting snapshots: store/VAT/cost/shipping
048_reporting_store_shipping_snapshots.js:orders_orders.store_id(uuid NOT NULL DEFAULT default-store + FK→pos_stores + idx),orders_orders.shipping_cents(integer NOT NULL DEFAULT 0),orders_items.cost_at_sale_cents(bigint nullable),orders_items.vat_rate(text nullable).reporting-snapshots.itest.ts3/3 ✅ (DB real, migration 001→048 aplicada).- tsc 0; boundaries 0 nuevas; verify.sh verde; commit
2ea628f. - Gates: reviewer ✅ / security ✅ / qa ✅ / document ✅ / leader-close ✅.
- Siguiente: F-145 (Reporting: payment lines and POS cash-safe capture).
F-138 cerrada (2026-08-22) — auto-seed default price row on variant creation
POST /products(:id/variants)create ahora inserta inmediatamente una fila default enpricing_variant_prices(net_unit_amount_cents=0,vat_rate='general',currency='EUR') víaPricingService.seedVariantPrice(inyectado enCreateProductVariant, best-effort,ON CONFLICT DO NOTHING). Cierra la ventana 404 deGET /pricing/variants/:id. Backend-only, sin migración.- Fuente: pricing
seedVariantPrice(ports+service+PgPricingRepository), catalogCreateProductVariantseed (best-effort),CatalogRoutesDeps += pricing,build-app.tshoistpricingconst;+testsvariant-use-cases.test.ts(3) + AC itest encatalog.itest.ts. - Gates: implementer ✅ / reviewer APPROVED ✅ / security APPROVED ✅ / qa APPROVED ✅ / leader close ✅.
- Verificación:
tsc --noEmit0 errores;npm test209 passed / 57 skipped (+3 nuevos);lint:boundariessin violaciones nuevas (R1 preexistentesecurity.routes.ts → log-broadcasterno introducido);./scripts/verify.shverde (pre-close + post-close tras corregirleader-close.jsonverdict CLOSED→APPROVED). - Commit:
feat(F-138): completed feature(fb01593, amendado).
F-154 cerrada (2026-08-22) — separate customers from internal users
GET /users(Customers) now returns storefront customers only (identity_users.role = 'customer'filtro literal enPgProfileRepository.listCustomers, COUNT + SELECT).GET /users/:idowner-or-admin inalterado.GET /admin/users(Users) now returns internos/backoffice only (role <> 'customer'base literal;?role=admin|editorafinando dentro de internos;?role=customer→ vacío).- Frontend: dropdown de Users quita opción
customer(backend ya fuerza la separación). Customers page sin cambio (llama /users → ahora customer-only). - Tests: 6 nuevos unitarios (mock, sin DB) en
pg-profile-repository.test.ts(3) +security.routes.test.ts(3).users.itest.tsAC2/AC3 flip: /users devuelve ben (customer) no ana (admin). Full suite 206 passed / 56 skipped, sin regresiones. - Gates: implementer ✅ / reviewer APPROVED ✅ / security APPROVED ✅ / qa APPROVED ✅ / leader close ✅.
tsc --noEmit0 errores (API + apps/admin); eslint/prettier limpios en archivos tocados;lint:boundariessin violaciones NUEVAS (R1 preexistente ensecurity.routes.ts → log-broadcaster, no introducido por F-154, verificado via git diff);verify.shexit 0.- Commit:
feat(F-154): completed feature.
F-153 cerrada (2026-08-22) — customer email on order view
- Asocia el email del cliente (
identity_users.email, NOT NULL) al order read model víaLEFT JOIN identity_usersen el repo, y lo expone enserializeOrder(detail + lista) y en la notificación del force-transition admin (usaorder.email; se elimina el lookup inline). OrderView.email?: string | null(additivo, opcional en fixtures de test → serializado comonull). Sin migración. Boundary intacta (orders→identity_users es referencia SQL, no import TS).- Tests: 3 nuevos en
pg-order-repository.test.ts(email resuelto vía JOIN,nullsin usuario vinculado,undefinedcuando no existe). Suite 200 passed / 56 skipped, sin regresiones. - Gates: implementer ✅ / reviewer APPROVED ✅ / security APPROVED ✅ / qa APPROVED ✅ / leader close ✅.
tsc --noEmit0 errores; eslint 0; prettier baseline-only;lint:boundariessin violaciones nuevas;verify.shexit 0.- Commit:
feat(F-153): completed feature+chore: reset runtime after F-153. - Pendiente siguiente por orden: F-154 (separate customers from internal users).
Sesión 2026-08-22 — F-152 cerrada (emails on account creation + order confirmation)
F-152cerrada: welcome email (account_created) onPOST /auth/registery order confirmation email onPOST /payments/webhook(PaymentSucceeded). Best-effort (fire-and-forget +request.log.warn), idempotent (gateoutcome.kind === "processed"), XSS-safe (buildWelcomeEmailescapea name), SMTP config destore_settings.- Gates: implementer ✅ / reviewer APPROVED ✅ / security APPROVED ✅ / qa APPROVED ✅ / leader close ✅.
tsc --noEmit0 errores; prettier+eslint limpios en archivos tocados;lint:boundariessin nuevas violaciones; 197 tests ✅;git diff --check✅;verify.shexit 0.- Commits:
feat(F-152): completed feature+chore: reset runtime after F-152(push omitido, sin remoteorigin). runtime-status.jsonreseteado a idle.- Pendiente siguiente por orden:
F-153(customer email missing).
Sesión 2026-08-22 — F-156 cerrada (CMS dynamic rendering)
Backlog: 269 features, 212 done, 57 pending, 0 in_progress, 0 blocked.
F-156cerrada: CMS content-managed pages (/about,/contact,/shipping) dejan de servir caché stale.fetchPageusa{ cache: 'no-store' }y las páginas exportandynamic = 'force-dynamic'; el fallback estático y el RBAC se mantienen.- Gates: implementer ✅ / reviewer APPROVED ✅ / security APPROVED ✅ / qa APPROVED ✅ / leader close ✅.
- Verificado runtime:
curl -sI /about→ 200 conCache-Control: private, no-cache, no-store, max-age=0, must-revalidate; verificador temporal de DB apareció y desapareció sin rebuild. verify.shgreen; cambios commiteados comofeat(F-156): completed feature;runtime-status.jsonreseteado a idle.- Pendientes inmediatos por orden sugerido:
F-152(emails account creation/order confirmation) →F-153(customer email missing) →F-154(separate customers from internal users). Los tickets Reporting P0 pendientes sonF-143..F-150.
Sesión 2026-08-21 — Reporting preparado y builds Next estabilizados
Backlog: 264 features, 209 done, 55 pending, 0 in_progress, 0 blocked.
F-141cerrada: raícesturbopack/outputFileTracingRootexplícitas en customer frontend y páginas de catálogo dinámicas para que el build no dependa del API.F-142cerrada:docs/reporting/REPORTING_ARCHITECTURE.mdydocs/reporting/REPORTING_TASKS.mdentregados tras analizar modelos reales, datos faltantes, API, rendimiento, caché, RBAC y roadmap P0-P3.- Tickets Reporting P0 abiertos:
F-143..F-150; todospending. verify.shexit 0 yruntime-status.jsonreseteado a idle.- Próximo ciclo: iniciar
F-143(contracts, filtros, comparación y RBAC de Reporting) antes de implementar dashboards.
Sesión 2026-08-21 — backlog cerrado (nota inicial, desfasada)
Backlog: 185 features (185 done, 0 pending, 0 in_progress) según la nota original.
Últimas features cerradas en esa nota: F-117, F-116, F-115, F-112, F-100.
Tras esa nota se cerraron 18 features adicionales (F-118..F-135) sin actualizar current.md. Quedan reflejadas en backlog/features.json y en work/history.md.
F-117 cerrada (2026-08-21)
Fix de F-116: renombre las 9 categorías que quedaron en mayúsculas (FRUTAS Y VERDURAS, SNACKS, GRANOLA, SUPLEMENTS, FACIAL, CORPORAL, ASEO PERSONAL, HIERBAS MEDICINALES, PROVEEDORES). Re-ejecución idempotente.
F-116 cerrada (2026-08-21)
Traducción de las 30 categorías legacy a Español Title Case (Alimentación, Cosmética, Bebidas, Vino, Cerveza, Macrobiótica, etc.). Slugs conservados.
F-115 cerrada (2026-08-21)
Rever de F-100: SKU-MV-{uuid} restaurado en creación de producto y lazy migration. Eliminado endpoint /products/sku:generate y el editor de SKU en admin.
F-112 cerrada (2026-08-21)
Disclaimer de contenido asistido por IA en la ficha de producto. Migración 040 añade catalog_products.ai_assisted. Flag se activa automáticamente al generar contenido con IA. Frontend muestra el <aside> con los dos avisos.
F-100 cerrada (2026-08-21)
SKU automático desde el título. Helper puro sku.ts con generateSkuFromTitle + uniqueSku (9 tests). Endpoint POST /products/sku:generate y helper mantenido como utilidad para F-117.
F-112 cerrada (2026-08-21)
Disclaimer de contenido asistido por IA en la ficha de producto. Migración 040 añade catalog_products.ai_assisted boolean NOT NULL DEFAULT false. Flag se activa automáticamente al generar contenido con IA (POST /products/:id/generate-seo). Frontend (apps/frontend) muestra el <aside> con los dos avisos requeridos cuando el flag está en true. Tests: 160 → 169.
F-100 cerrada (2026-08-21)
SKU automático desde el título. Helper puro src/modules/catalog/domain/sku.ts con generateSkuFromTitle + uniqueSku (9 tests). POST /products y la migración perezosa de variantes ahora generan SKUs tipo MV-ESPELTA-ECOLOGICA en lugar de SKU-MV-${uuid}. Endpoint admin POST /products/sku:generate para preview. UI admin: SKU editable + botón regenerar en PriceStockSection.
F-114 cerrada (2026-08-21)
Importa las 76 categorías de oc_category_description de OpenCart. Crea 39 categorías nuevas y 32 marcas (nombres de marca van al módulo brands_brands), excluye marcadores legacy y duplicados. Script idempotente en scripts/seed-legacy-categories.mjs. Helpers puros en src/modules/categories/legacy/legacy-catalog.ts con 15 tests. Catálogo: 12→51 categorías, 5→37 marcas.
F-113 cerrada y desplegada (2026-08-21)
Email al cliente en procesando/enviado con tracking y courier editable. Bug fixed: UI admin → /orders/:id/transitions/admin. Courier persistido (orders_orders.courier, migración 039). Lista editable en store_settings.shipping_couriers. SHIPPED exige tracking y courier. Tests: 135 → 145. Deploy manual.
Última incidencia resuelta (2026-08-20)
F-099 en build. El sistema deja de simular el envío de recuperación en logs y añade SMTP configurable desde Ajustes → SMTP / Email. También se incorporan generación de descripción normal vacía, proxy de logs con cookie httpOnly y navegación de login/logout solo con icono y tooltip.
Última incidencia resuelta (2026-08-20)
F-095 cerrada con todos los gates aprobados. Las imágenes URL se descargan y almacenan en uploads locales antes de adjuntarse.
Incidencia anterior (2026-08-20)
Añadir una imagen por URL devolvía 400 porque el flujo hacía un PATCH vacío del producto y adjuntaba directamente la URL remota.
Última incidencia resuelta (2026-08-20)
F-094 cerrada con todos los gates aprobados. Publicar permite crear variantes y explica SKU/EAN, precios y stock.
Incidencia anterior (2026-08-20)
Precios e Inventario indicaban que las variantes se creaban desde Publicar, pero Publicar no ofrecía creación ni explicación.
Última incidencia resuelta (2026-08-20)
F-093 cerrada con todos los gates aprobados. Inventario busca ahora por EAN o nombre de producto.
Incidencia anterior (2026-08-20)
La búsqueda de Inventario enviaba q, pero el listado admin solo filtraba por nombre de producto.
Ú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.
Incidencia anterior (2026-08-20)
Fecha de caducidad estaba en la pestaña SEO de la ficha de producto. F-092 la movió a General sin cambiar el estado, payload ni guardado.
Última incidencia resuelta (2026-08-20)
F-091 cerrada con todos los gates aprobados. Los conflictos de SKU/EAN indican ahora qué campo está duplicado y Enter + blur no generan PATCH simultáneos.
Incidencia anterior (2026-08-20)
El PATCH de variantes devolvía 409 PRODUCT_VARIANT_CODE_EXISTS cuando el SKU o EAN ya estaba usado por otra variante. El editor mostraba solo Error y la combinación Enter + blur podía intentar enviar dos veces.
Última incidencia resuelta (2026-08-20)
F-090 cerrada con todos los gates aprobados. El listado ya recibe marca/caducidad y los valores SKU/EAN guardados permanecen visibles tras salir del campo.
Incidencia anterior (2026-08-20)
El listado admin mostraba — para marca/caducidad porque la serialización del catálogo omitía ambos campos. En el editor de producto, SKU/EAN se guardaban en rows pero la vista no editable usaba el array variants inicial y volvía a mostrar valores antiguos.
Ú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.
Incidencia anterior (2026-08-20)
El enlace de producto del listado admin apuntaba a http://192.168.18.93:3003/productos/<slug>, pero el frontend customer usa /products/<slug>. F-089 corrigió únicamente ese path.
Última incidencia resuelta (2026-08-20)
F-088 cerrada con todos los gates aprobados. El admin responde HTTP 200 en http://192.168.18.93:3004/.
Symptom reportado por el operador (2026-08-20)
http://192.168.18.93:3004/ → ERR_CONNECTION_REFUSED. El servicio admin del monolito no se mantiene en pie. Diagnóstico:
monolith.sh prod status→ adminexited during startup, log:Could not find a production build in the '.next' directory.apps/admin/.next/existe pero no contieneBUILD_IDnirequired-server-files.json.npx tsc --noEmitenapps/admin→error TS2353entax-rates/page.tsx(59,33):'appliesTo' does not exist in type 'Partial<{ name: string; ratePercent: number; active: boolean; }>'.
Root cause
F-085 añadió el handler saveTipo que llama a taxApi.update(id, { appliesTo }) y extendió la página con UI de edición inline, pero olvidó extender la firma de taxApi.update en apps/admin/src/lib/api-client.ts. Resultado: next build aborta por typecheck, no se genera BUILD_ID, next start falla y el admin no puede servir nada en :3004. El backend en pricing.routes.ts ya valida y persiste appliesTo, así que el fix es 100% frontend (type only).
Fix
Ampliar la firma Partial<{...}> de taxApi.update para aceptar appliesTo: 'general' | 'reduced' | 'super-reduced' (mismo enum que el backend). Después: npm run build en apps/admin produce BUILD_ID, monolith.sh prod mantiene el admin vivo y http://192.168.18.93:3004/ responde 200.
Pending tickets (2026-08-21)
Pendientes: F-100 (descartable, sustituida por F-109), F-101, F-102, F-107, F-108, F-109, F-110, F-111, F-112.
Orden sugerido: F-108 → F-109 → F-107 → F-110 → F-111 → F-101 → F-102 → F-112.
Redefiniciones de intake del operador (2026-08-21)
- F-101 (alcance reducido): El renderizado actual de descripciones IA ya funciona. Solo queda justificar el texto de la descripción en la ficha de producto del frontend. NO hace falta conversión Markdown→HTML.
- F-102 (redefinida): El peso del producto es 1 por unidad (si pide 3, peso = 3 × peso unitario). Lo llamado "pack" es en realidad un selector de compra mínima: cantidad mínima de compra por producto; el frontend bloquea la compra por debajo de ese mínimo. Además, nueva opción de envío: límite de envío gratuito por rango de peso en cada tipo de envío y un max weight por tipo de envío.
- F-112 (nueva): Disclaimer de contenido IA en fichas de producto del frontend:
- "Parte del contenido de esta ficha puede haber sido generado o asistido mediante inteligencia artificial y revisado antes de su publicación."
- "La composición y características del producto pueden cambiar. Consulta siempre la etiqueta y la información del fabricante antes de consumirlo o utilizarlo."
Nota de intake (2026-08-20)
El operador reportó ERR_CONNECTION_REFUSED en :3004. El triage lo une a F-085 (cambio parcial sin actualizar la firma TS). Se crea F-088 para reparar la regresión sin reabrir F-085, y se ejecuta por orquestra secuencial.