43 lines
2.8 KiB
Markdown
43 lines
2.8 KiB
Markdown
# F-143 — Technical spec
|
|
|
|
## Module layout
|
|
```text
|
|
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/*` + `zod` → **ningú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`)
|
|
- `none` → `null`.
|
|
- `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+).
|