Files
mercadodevida/spec/tech.md
2026-08-22 11:43:42 +02:00

2.8 KiB

F-143 — Technical spec

Module layout

src/modules/reporting/
  domain/filters.ts        — pure types (ReportingFilters, ComparisonMode, GroupBy, ComparisonRange, DataAvailability, ReportingFilterMeta)
  domain/permissions.ts    — ReportingPermission + REPORTING_ROLE_PERMISSIONS + requireReportingPermission (imports shared/auth + shared/errors)
  application/filters.ts   — reportingFiltersSchema (zod), parseReportingFilters, comparisonRange, REPORTING_FILTER_META (imports domain)
  api/reporting.routes.ts  — registerReportingRoutes(app, deps:{authenticate}) (imports application + domain + shared)
  index.ts                 — public surface (re-exports only)
  tests/filters.test.ts    — unit: parser + comparisonRange
  tests/permissions.test.ts— unit: role matrix + requireReportingPermission
  api/reporting.routes.test.ts — HTTP: schema/validate + RBAC (mirror security.routes.test.ts)

Boundaries (R1/R2)

  • reporting importa SOLO shared/* + zodningún otro módulo. ✓ R1.
  • src/app/build-app.ts importa registerReportingRoutes (+ tipos) desde modules/reporting/index.js (R2). ✓.
  • Registrado dentro de if (deps.pool) con authenticate: combinedAuth (backplane backoffice), junto al resto de módulos backoffice.

Filter contract (F-142 §6)

  • Rango [from,to): from inclusivo, to exclusivo → evita doble conteo.
  • from/to: ISO datetime with offset → z.string().datetime({ offset: true }).
  • Arrays repetibles de UUID aceptan single OR array vía z.preprocess((v)=>Array.isArray(v)?v:v===undefined?undefined:[v], z.array(z.uuid()).optional()).
  • compare default none; channel default all; page (1..); pageSize (1..200, default 50).
  • from > to → refine → AppError(400) (mapeado por parseJson).

Comparison (comparisonRange)

  • nonenull.
  • previous_equal → shift ventana atrás por la duración exacta ([start-duration, start)).
  • previous_calendar → shift atrás por los días calendario transcurridos, alineado a UTC (00:00) → [prevStart, prevStart+spanDays). Documented como aproximación calendar-aligned.

RBAC (role-based, F-142 §9)

  • admin → todos los REPORTING_*.
  • editor → VIEW+SALES+PRODUCTS+CUSTOMERS+INVENTORY+DISCOUNTS+REFUNDS+TAXES (sin FINANCIAL/EXPORT/ADMIN).
  • pos_manager → VIEW+SALES+PAYMENTS+CASH.
  • pos_cashier → VIEW+SALES.
  • customer → [] (403).
  • requireReportingPermission(user, permission) lanza AppError(403). Futuro: tabla backoffice_permissions; la firma no cambia.

Data availability (F-142 §4 baseline, server-truth)

grossSales/discounts/tax/unitsSold/orders/customers = available; netSales/margin/paymentMethod/refunds/shipping = unavailable. Se expone via REPORTING_FILTER_META.dataAvailability (no cálculos aún — F-144+).