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

51 lines
3.2 KiB
JSON

{
"feature_id": "F-143",
"agent": "reviewer",
"stage": "review_gate",
"verdict": "APPROVED",
"summary": "F-143 reporting module (contracts + RBAC, no DB reads, no migration) approved. Architecture matches the pricing module layering (api>application>domain>shared) and R1/R2 boundaries are respected: reporting imports only shared/* + zod (no other module), and build-app wires it via the public index. The zod schema enforces [from,to) inclusive-start/exclusive-end semantics (from<to refine -> 400 on inversion), repeatable UUID fields accept single-or-array via z.preprocess (Fastify querystring parity), and the two-route/two-permission split (REPORTING_VIEW on /schema, REPORTING_SALES on /validate) exercises RBAC end-to-end. reportingFiltersSchema.parse runs inside parseJson (shared/http-input) so refinement+transform execute on parse and zod issues map to AppError(400,VALIDATION_ERROR). dataAvailability is metadata-only baseline (never converts unavailable->0); no report data is queried (F-144 owns that). build-app.ts registers the module inside if(deps.pool) with combinedAuth (F-154 combined authenticator), matching the thin backoffice-module pattern (no pool needed for F-143 itself, authenticate is the only dep).",
"checks": [
{
"item": "R1: reporting imports only shared/* + zod",
"ok": true,
"evidence": "check-module-boundaries.mjs reports 0 reporting violations; sources import '../../../shared/{auth,errors,http-input,swagger}.js' + 'zod' only"
},
{
"item": "R2: build-app imports reporting via public index only",
"ok": true,
"evidence": "build-app.ts: import { registerReportingRoutes } from '../modules/reporting/index.js'"
},
{
"item": "single ReportingRoutesDeps (authenticate only — no pool)",
"ok": true,
"evidence": "ReportingRoutesDeps { authenticate: Authenticate }; registered inside if(deps.pool) block with combinedAuth"
},
{
"item": "[from,to) range semantics + from<to -> 400 on inversion",
"ok": true,
"evidence": "application/filters.ts .refine(from<to); routes.test 'returns 400 on inverted range'"
},
{
"item": "repeatable UUID accepts single OR array",
"ok": true,
"evidence": "z.preprocess(string|array->array); filters.test 'accepts repeated and single storeId as a UUID array'"
},
{
"item": "two routes, two distinct permissions (RBAC end-to-end)",
"ok": true,
"evidence": "/reporting/filters/schema -> REPORTING_VIEW; /reporting/filters/validate -> REPORTING_SALES; customer->403 on both"
},
{
"item": "dataAvailability is metadata-only baseline (no unavailable->0)",
"ok": true,
"evidence": "REPORTING_FILTER_META.dataAvailability hardcoded baseline; grossSales/discounts/tax/unitsSold/orders/customers=available, netSales/margin/paymentMethod/refunds/shipping=unavailable; no metric computation in routes"
},
{
"item": "schema driven by zod (DRY const arrays derive union types)",
"ok": true,
"evidence": "domain/filters.ts exports REPORTING_COMPARISON/CHANNELS/GROUP_BY as const; types derived via typeof[x][number]; z.enum uses the const tuples"
}
],
"issues": []
}