Repara criteriul de acceptare "dashboardurile citesc read models, nu
interogheaza haotic toate modulele".
- projection_processed_events (unique: name+version+event_id) = garantia de
idempotency. Checkpointul e doar optimizare de scanare, nu corectitudine:
rescanam cu un safety lag de 60s si sarim ce s-a aplicat deja, ca sa nu
pierdem evenimente comise dupa unul cu created_at mai mare.
- ProjectionRegistry cu ProjectionDefinition (name, version, subscribedEvents,
rebuildStrategy, apply, rebuildTenant).
- executive_dashboard foloseste rebuildStrategy 'canonical-tables':
recalculeaza contorii din tabelele canonice, nu incrementeaza. Contorii
incrementali pot deriva daca un eveniment se pierde sau se dubleaza;
recalcularea e corecta prin constructie si idempotenta natural. Costul e o
interogare per eveniment relevant -- ok la volumul actual.
- GET /v1/dashboard/executive citeste proiectia. Cand proiectia inca n-a rulat
pentru workspace, intoarce status 'building' explicit, NU zerouri care ar
parea date reale.
- POST /v1/dashboard/executive/rebuild -- owner/admin, auditat.
- Serviciile de taskuri/organizatii/segmente emit acum evenimente in outbox
(in aceeasi tranzactie cu scrierea). Fara ele proiectia era cod mort.
- Campurile din spec care depind de module neconstruite (documents,
transactions, approvals) raman 0 explicit, nu inventate.
- SessionGuard resolves Supabase JWT (local HS256 verify, GoTrue fallback)
and loads the tenant membership from x-tenant-id; TenantGuard keeps
deny-by-default and rejects client-supplied tenant_id (blueprint 11.3).
- New bootstrap routes: GET /v1/me, POST/GET /v1/tenants, tenant member
management (list/add/remove) with owner/admin RBAC.
- Organizations and Tasks modules: full CRUD scoped to session.tenantId,
soft delete, audit log + outbox events on every write.
- AuditService (global) for blueprint 3.4 "100% audit on material ops".
- jest + tenant.guard.spec covering deny-by-default and anti-IDOR cases.