From b85670cb51295a6a997780a4071f727b8b1a50cf Mon Sep 17 00:00:00 2001 From: chattie Date: Sat, 22 Aug 2026 22:29:26 +0200 Subject: [PATCH] feat(F-194): completed feature --- backlog/features.json | 17 +++++++++++++++ .../(dashboard)/{ => settings}/audit/page.tsx | 2 ++ .../(dashboard)/{ => settings}/logs/page.tsx | 2 ++ .../src/app/(dashboard)/settings/page.tsx | 12 +++++++++++ .../{ => settings}/tax-rates/page.tsx | 2 ++ project/apps/admin/src/lib/permissions.ts | 6 +++--- project/apps/pos/src/app/(terminal)/page.tsx | 2 +- .../apps/pos/src/components/PaymentModal.tsx | 3 ++- work/artifacts/F-194/implementer.md | 21 +++++++++++++++++++ work/artifacts/F-194/leader-close.json | 1 + work/artifacts/F-194/qa.json | 1 + work/artifacts/F-194/reviewer.json | 1 + work/artifacts/F-194/security.json | 1 + work/history.md | 6 ++++++ work/runtime-status.json | 2 +- 15 files changed, 73 insertions(+), 6 deletions(-) rename project/apps/admin/src/app/(dashboard)/{ => settings}/audit/page.tsx (98%) rename project/apps/admin/src/app/(dashboard)/{ => settings}/logs/page.tsx (86%) rename project/apps/admin/src/app/(dashboard)/{ => settings}/tax-rates/page.tsx (98%) create mode 100644 work/artifacts/F-194/implementer.md create mode 100644 work/artifacts/F-194/leader-close.json create mode 100644 work/artifacts/F-194/qa.json create mode 100644 work/artifacts/F-194/reviewer.json create mode 100644 work/artifacts/F-194/security.json diff --git a/backlog/features.json b/backlog/features.json index dd3e187..185a152 100644 --- a/backlog/features.json +++ b/backlog/features.json @@ -7322,6 +7322,23 @@ "security": false, "qa": false } + }, + { + "id": "F-194", + "type": "fix", + "title": "Fix crypto.randomUUID runtime error and move IVA/audit/logs into settings", + "description": "1) Replace bare crypto.randomUUID() calls in POS PaymentModal and cashier page with the safe generateIdempotencyKey fallback. 2) Move tax-rates, audit and logs navigation and routes into the settings section.", + "priority": "high", + "risk": "low", + "status": "done", + "created_at": "2026-08-22", + "gates": { + "reviewer": true, + "security": true, + "qa": true, + "close": true + }, + "completed_at": "2026-08-22T20:29:26Z" } ] } diff --git a/project/apps/admin/src/app/(dashboard)/audit/page.tsx b/project/apps/admin/src/app/(dashboard)/settings/audit/page.tsx similarity index 98% rename from project/apps/admin/src/app/(dashboard)/audit/page.tsx rename to project/apps/admin/src/app/(dashboard)/settings/audit/page.tsx index 8ca04ef..09a0820 100644 --- a/project/apps/admin/src/app/(dashboard)/audit/page.tsx +++ b/project/apps/admin/src/app/(dashboard)/settings/audit/page.tsx @@ -1,5 +1,6 @@ 'use client'; import { useState, useEffect, useCallback, useRef } from 'react'; +import Link from 'next/link'; import { auditApi, type AuditEntry } from '@/lib/api-client'; const PAGE_SIZE = 50; @@ -79,6 +80,7 @@ export default function AuditLogPage() { return (
+ ← Ajustes

Log de auditoría {pollingActive && ( diff --git a/project/apps/admin/src/app/(dashboard)/logs/page.tsx b/project/apps/admin/src/app/(dashboard)/settings/logs/page.tsx similarity index 86% rename from project/apps/admin/src/app/(dashboard)/logs/page.tsx rename to project/apps/admin/src/app/(dashboard)/settings/logs/page.tsx index 9a632e9..7eb5bed 100644 --- a/project/apps/admin/src/app/(dashboard)/logs/page.tsx +++ b/project/apps/admin/src/app/(dashboard)/settings/logs/page.tsx @@ -1,4 +1,5 @@ 'use client'; +import Link from 'next/link'; import { ServerLogViewer } from '@/components/ServerLogViewer'; export default function ServerLogsPage() { @@ -10,6 +11,7 @@ export default function ServerLogsPage() { return (
+ ← Ajustes

Logs del servidor

Stream en tiempo real via SSE. Las líneas erróneas se resaltan en rojo. Máximo 200 líneas. diff --git a/project/apps/admin/src/app/(dashboard)/settings/page.tsx b/project/apps/admin/src/app/(dashboard)/settings/page.tsx index c8973b9..d380b73 100644 --- a/project/apps/admin/src/app/(dashboard)/settings/page.tsx +++ b/project/apps/admin/src/app/(dashboard)/settings/page.tsx @@ -1,5 +1,6 @@ 'use client'; import { useState, useEffect } from 'react'; +import Link from 'next/link'; import { settingsApi, type StoreSettings } from '@/lib/api-client'; type FormData = StoreSettings; @@ -105,6 +106,17 @@ export default function SettingsPage() { {t.label} ))} +

+

Sistema

+ + 💰 IVA + + + 📋 Auditoría + + + 🖥️ Logs + {/* Form area */} diff --git a/project/apps/admin/src/app/(dashboard)/tax-rates/page.tsx b/project/apps/admin/src/app/(dashboard)/settings/tax-rates/page.tsx similarity index 98% rename from project/apps/admin/src/app/(dashboard)/tax-rates/page.tsx rename to project/apps/admin/src/app/(dashboard)/settings/tax-rates/page.tsx index 3ec80fb..12a77c8 100644 --- a/project/apps/admin/src/app/(dashboard)/tax-rates/page.tsx +++ b/project/apps/admin/src/app/(dashboard)/settings/tax-rates/page.tsx @@ -1,6 +1,7 @@ 'use client'; import { useState, useEffect, useCallback } from 'react'; import { taxApi, type TaxRate } from '@/lib/api-client'; +import Link from 'next/link'; import { RowActions } from '@/components/ui/RowActions'; export default function TaxRatesPage() { @@ -69,6 +70,7 @@ export default function TaxRatesPage() { return (
+ ← Ajustes

Tipos impositivos (IVA)

Configura los tipos de IVA aplicables a los productos.

diff --git a/project/apps/admin/src/lib/permissions.ts b/project/apps/admin/src/lib/permissions.ts index a0eacb2..3c99178 100644 --- a/project/apps/admin/src/lib/permissions.ts +++ b/project/apps/admin/src/lib/permissions.ts @@ -55,10 +55,10 @@ export const NAV_ITEMS: NavItem[] = [ { href: '/reviews', label: 'Reseñas', icon: '⭐', permission: 'reviews.read' }, { href: '/cms', label: 'CMS', icon: '📄', permission: 'cms.read' }, { href: '/users', label: 'Usuarios', icon: '🔐', permission: 'admin-users.read' }, - { href: '/tax-rates', label: 'IVA', icon: '📊', permission: 'orders.read' }, - { href: '/audit', label: 'Auditoría', icon: '📋', permission: 'audit.read' }, - { href: '/logs', label: 'Logs', icon: '🖥️', permission: 'audit.read' }, { href: '/settings', label: 'Ajustes', icon: '⚙️', permission: 'dashboard' }, + { href: '/settings/tax-rates', label: 'IVA', icon: '💰', permission: 'orders.read' }, + { href: '/settings/audit', label: 'Auditoría', icon: '📋', permission: 'audit.read' }, + { href: '/settings/logs', label: 'Logs', icon: '🖥️', permission: 'audit.read' }, ]; export function visibleNavItems(role: Role): NavItem[] { diff --git a/project/apps/pos/src/app/(terminal)/page.tsx b/project/apps/pos/src/app/(terminal)/page.tsx index 67c91a5..a9bfac2 100644 --- a/project/apps/pos/src/app/(terminal)/page.tsx +++ b/project/apps/pos/src/app/(terminal)/page.tsx @@ -274,7 +274,7 @@ export default function RegisterPage() { setCart((current) => [ ...current, { - lineId: `free-${crypto.randomUUID()}`, + lineId: `free-${generateIdempotencyKey()}`, kind: 'free', variantId: null, productId: null, diff --git a/project/apps/pos/src/components/PaymentModal.tsx b/project/apps/pos/src/components/PaymentModal.tsx index 08caabb..5e47c42 100644 --- a/project/apps/pos/src/components/PaymentModal.tsx +++ b/project/apps/pos/src/components/PaymentModal.tsx @@ -3,6 +3,7 @@ import { useMemo, useState } from 'react'; import { formatPrice } from '@/lib/money'; import type { PaymentAllocation, PaymentMethod } from '@/types/checkout'; +import { generateIdempotencyKey } from '@/lib/idempotency'; interface PaymentModalProps { method: PaymentMethod; @@ -48,7 +49,7 @@ export default function PaymentModal({ return; } onAdd({ - id: crypto.randomUUID(), + id: generateIdempotencyKey(), methodCode: method.code, methodLabel: method.label, kind: method.kind, diff --git a/work/artifacts/F-194/implementer.md b/work/artifacts/F-194/implementer.md new file mode 100644 index 0000000..907a78d --- /dev/null +++ b/work/artifacts/F-194/implementer.md @@ -0,0 +1,21 @@ +# F-194 — Fix evidence + +## Changes + +### Fix 1: `crypto.randomUUID()` runtime TypeError +- `project/apps/pos/src/components/PaymentModal.tsx`: replaced `crypto.randomUUID()` with `generateIdempotencyKey()` (already imported pattern from `@/lib/idempotency` with safe fallback). +- `project/apps/pos/src/app/(terminal)/page.tsx`: same fix for the free-item lineId. + +### Fix 2: IVA, Auditoría, Logs → inside Settings +- Moved routes: `app/(dashboard)/{tax-rates,audit,logs}/page.tsx` → `app/(dashboard)/settings/{tax-rates,audit,logs}/page.tsx` +- Updated `permissions.ts` NAV_ITEMS: `/tax-rates` → `/settings/tax-rates`, `/audit` → `/settings/audit`, `/logs` → `/settings/logs` +- Added "Sistema" sub-navigation in settings sidebar with links to each sub-page. +- Added "← Ajustes" breadcrumb link at the top of each moved page. + +## Validation +- Admin typecheck: PASS +- POS typecheck: PASS +- Admin build: PASS (routes show `/settings/{audit,logs,tax-rates}`) +- POS build: PASS +- Backend unit tests: 268/268 PASS +- `./scripts/verify.sh`: PASS diff --git a/work/artifacts/F-194/leader-close.json b/work/artifacts/F-194/leader-close.json new file mode 100644 index 0000000..8688303 --- /dev/null +++ b/work/artifacts/F-194/leader-close.json @@ -0,0 +1 @@ +{"feature_id":"F-194","agent":"leader","stage":"close","verdict":"APPROVED","checks":[{"item":"All gates APPROVED","ok":true},{"item":"Builds and tests pass","ok":true}],"issues":[]} diff --git a/work/artifacts/F-194/qa.json b/work/artifacts/F-194/qa.json new file mode 100644 index 0000000..35e32ec --- /dev/null +++ b/work/artifacts/F-194/qa.json @@ -0,0 +1 @@ +{"feature_id":"F-194","agent":"qa","stage":"qa_gate","verdict":"APPROVED","acceptance":[{"id":1,"criterion":"PaymentModal no longer calls bare crypto.randomUUID()","ok":true},{"id":2,"criterion":"Terminal free-item uses safe ID generation","ok":true},{"id":3,"criterion":"IVA/Audit/Logs are accessible under /settings/...","ok":true},{"id":4,"criterion":"Old /tax-rates, /audit, /logs routes removed","ok":true},{"id":5,"criterion":"Typecheck/builds/regression green","ok":true}],"issues":[]} diff --git a/work/artifacts/F-194/reviewer.json b/work/artifacts/F-194/reviewer.json new file mode 100644 index 0000000..7d13364 --- /dev/null +++ b/work/artifacts/F-194/reviewer.json @@ -0,0 +1 @@ +{"feature_id":"F-194","agent":"reviewer","stage":"review_gate","verdict":"APPROVED","checks":[{"item":"crypto.randomUUID replaced with safe fallback","ok":true},{"item":"Routes moved from top-level to settings sub-paths","ok":true},{"item":"Navigation items updated to new paths","ok":true},{"item":"Settings sidebar links to sub-pages","ok":true},{"item":"Back-to-settings breadcrumbs on each page","ok":true},{"item":"Typecheck and builds pass","ok":true}],"issues":[]} diff --git a/work/artifacts/F-194/security.json b/work/artifacts/F-194/security.json new file mode 100644 index 0000000..0441664 --- /dev/null +++ b/work/artifacts/F-194/security.json @@ -0,0 +1 @@ +{"feature_id":"F-194","agent":"security","stage":"security_gate","verdict":"APPROVED","checks":[{"item":"No new auth/authz changes","ok":true},{"item":"No secrets or sensitive data introduced","ok":true},{"item":"Moved pages preserve existing RBAC","ok":true}],"issues":[]} diff --git a/work/history.md b/work/history.md index 8765951..a402dd2 100644 --- a/work/history.md +++ b/work/history.md @@ -502,3 +502,9 @@ - Seguridad: login y sesiones bloquean cuentas inactivas/eliminadas; revocación y auditoría atómicas; sesión de caja abierta impide la baja. - Integridad: la fila/UUID se conserva para atribución histórica y la apertura de caja se serializa con la baja mediante bloqueo de fila. - Evidencia: 354/354 tests con PostgreSQL real en secuencia, migración up/no-op/down/up y builds backend/admin verdes; `work/artifacts/F-187/`. + +## F-194 cerrada (2026-08-22) — Fix crypto.randomUUID runtime error and move admin modules to settings +- Gates: reviewer APPROVED, security APPROVED, qa APPROVED, verify.sh exit 0. +- Fix 1: replaced bare crypto.randomUUID() with generateIdempotencyKey() in PaymentModal and terminal page. +- Fix 2: moved tax-rates, audit and logs routes from top-level dashboard into /settings/... with breadcrumb navigation. +- Evidencia: admin/POS typecheck and builds green; 268/268 unit tests pass; verify.sh green. diff --git a/work/runtime-status.json b/work/runtime-status.json index a2180a0..6f01e91 100644 --- a/work/runtime-status.json +++ b/work/runtime-status.json @@ -6,6 +6,6 @@ "state": "waiting", "next_agent": "leader", "waiting_for": "Seleccionar una feature pending y actualizar este estado", - "updated_at": "2026-08-22T20:23:50Z", + "updated_at": "2026-08-22T20:29:26Z", "timeline": [] }