Files
mercadodevida/work/artifacts/F-143/documenter.md
2026-08-22 11:43:42 +02:00

3.4 KiB

F-143 — API contract documentation

Resumen del cambio (user-facing)

New backoffice Reporting module delivering the shared filter contract + RBAC foundation (F-142 §3/§6/§9). No report data is read here (F-144+ owns report data); GET /reporting/filters/schema only introspects the contract. Two new endpoints, both backoffice-only (backoffice_session or storefront mdv_session via combinedAuth):

Nuevas rutas

Method Path Auth (authenticate) Permission Body / Query 200 response
GET /reporting/filters/schema combinedAuth (authenticated) REPORTING_VIEW n/a { filterSchema, comparison, dataAvailability, permissions }
GET /reporting/filters/validate combinedAuth (authenticated) REPORTING_SALES ?from&to&compare?… (see below) { ok, filters, comparison: { range } }

RBAC

Permissions are role-based (no permission table yet — F-142 §9 "compatibilidad inicial"):

  • admin — all reporting permissions (incl. REPORTING_FINANCIAL, REPORTING_EXPORT).
  • editor — VIEW + SALES + PRODUCTS + CUSTOMERS + INVENTORY + DISCOUNTS + REFUNDS + TAXES.
  • pos_manager — VIEW + SALES + PAYMENTS + CASH.
  • pos_cashier — VIEW + SALES.
  • customer — none (403 on both routes).

A future backoffice_permissions migration keeps the requireReportingPermission(user, perm) call-site signature.

Filter schema (shared contract)

Query params parsed by reportingFiltersSchema via parseJson (→ 400 VALIDATION_ERROR on bad input):

  • from (string, required) — ISO 8601 datetime, inclusive start.
  • to (string, required) — ISO 8601 datetime, exclusive end. from < to enforced (400 on inversion).
  • compare — enum none | previous_equal | previous_calendar (default none).
  • channel — enum all | ecommerce | pos | admin (default all).
  • storeId, terminalId, cashierId, paymentMethodId, productId, categoryId, brandId — repeatable UUID (single value or repeated).
  • customerId — single UUID (optional; walk-in POS has none).
  • state — repeatable string (e.g. PAID,SHIPPED).
  • groupBy — enum day|week|month|hour|store|channel|terminal|cashier|payment.
  • page (int, default 1), pageSize (int, 1..200, default 50).
  • sort — string (e.g. -revenue).

Comparison range (comparisonRange, [from,to))

  • nonecomparison.range = null.
  • previous_equal → exact-duration mirror; prior window ends exactly at range.from.
  • previous_calendar → UTC-aligned prior window of ceil(span_days) days.

dataAvailability (metadata only — F-142 §4 baseline)

Never converted to 0. Currently:

  • available: grossSales, discounts, tax, unitsSold, orders, customers.
  • unavailable: netSales, margin, paymentMethod, refunds, shipping.

Errores

  • 401 — unauthenticated (authenticate rejects).
  • 403 — authenticated but lacks the route permission.
  • 400 — malformed query (zod → VALIDATION_ERROR), incluyendo from >= to e UUIDs inválidos.

Implementación

  • project/src/modules/reporting/ (domain/application/api + tests + index).
  • project/src/app/build-app.tsregisterReportingRoutes registered inside if (deps.pool) with combinedAuth. No migrations, no DB schema or data-table changes in this ticket.