Commit graph

63 commits

Author SHA1 Message Date
e3b5cca72c chore: regenerate lockfile after supertest devDep addition 2026-07-31 15:00:09 +00:00
4f801d6964 fix(deps): add supertest + @types/supertest devDeps for TST-012 security tests 2026-07-31 15:00:08 +00:00
b9f9c970b7 fix(ts): cast SupabaseClient through unknown in Proxy get trap (TS2352) 2026-07-31 15:00:07 +00:00
ebbac2dc58 docs(privacy): PRV-005 GDPR Legal Basis Registry — CC-046 securizare 2026-07-31 14:58:03 +00:00
e22215ab64 test(security): TST-012 HTTP-level security test suite (auth, headers, CORS, CASL, route enum) 2026-07-31 14:57:03 +00:00
1c784b654f feat(security): Goal/Decision/Observation/Opportunity as explicit CASL subjects for member role (SEC-004/F4) 2026-07-31 14:57:02 +00:00
ace0000349 fix(security): startup env validation + CORS origin filter (SEC-012/F6) 2026-07-31 14:57:01 +00:00
7d43bc6b70 fix(security): USER node + HEALTHCHECK in production stage (SEC-013/F9/F11) 2026-07-31 14:57:01 +00:00
97c32222ce fix(supabase): lazy client init — validates env vars at first use, not at import time 2026-07-31 14:44:00 +00:00
c7e09ed647 test(integration): audit log, outbox atomicity and transaction minor units tests 2026-07-31 14:40:30 +00:00
458217a0ec test(integration): tenant isolation tests for goals and organizations 2026-07-31 14:40:29 +00:00
c3b0005e19 feat(db): versioned Drizzle migration for workspace_id columns (CC-044 backfill) 2026-07-31 14:39:24 +00:00
21c6ff2fde feat(schema): add workspaceId to 11 tables missing from Drizzle ORM (organizations, tasks, goals, decisions, transactions, documents, opportunities, observations, ai_requests, research_briefs, saved_segments) 2026-07-31 14:39:23 +00:00
f5ac5f11f1 chore: regenerate package-lock.json after dependency version fixes 2026-07-31 14:36:21 +00:00
94506c8f80 fix(deps): @nestjs/schedule ^5.0.0 + @nestjs/testing devDep for NestJS 11 compatibility 2026-07-31 14:36:19 +00:00
0e016edec2 fix(opportunities): enforce @IsInt() on valueRangeMin/Max to prevent float input 2026-07-31 10:48:40 +00:00
6c44c327cf fix(transactions): remove ad-hoc UUID regex, use ParseUUIDPipe for path params 2026-07-31 10:48:38 +00:00
3b1b14e380 fix(decisions): wrap mutations in db.transaction() for audit atomicity 2026-07-31 10:48:37 +00:00
880c2a7018 test(transactions): add unit tests for TransactionsService 2026-07-31 10:47:16 +00:00
19fd999441 test(goals): add unit tests for GoalsService 2026-07-31 10:47:15 +00:00
281fb9e780 feat(projection): wire transactionsUnclassifiedCount to executive dashboard 2026-07-31 10:46:11 +00:00
bdcf63e2a6 feat: register Goals, Decisions, Transactions, Observations, Opportunities modules 2026-07-31 10:45:07 +00:00
7569d7ee87 feat(opportunities): add opportunities.module 2026-07-31 10:45:06 +00:00
5caa233bea feat(opportunities): add opportunities.controller 2026-07-31 10:45:05 +00:00
80fd3e0b4e feat(opportunities): add opportunities.service 2026-07-31 10:45:04 +00:00
0243e78fea feat(opportunities): add dto 2026-07-31 10:45:03 +00:00
0105bf1f73 feat(observations): add observations.module 2026-07-31 10:45:02 +00:00
8db3ccf300 feat(observations): add observations.controller 2026-07-31 10:45:01 +00:00
f2733c6e72 feat(observations): add observations.service 2026-07-31 10:45:01 +00:00
3cd2bdc82b feat(observations): add dto 2026-07-31 10:45:00 +00:00
4315e7f31f feat(transactions): add transactions.module 2026-07-31 10:44:59 +00:00
78d60c69ab feat(transactions): add transactions.controller 2026-07-31 10:44:58 +00:00
a80bd5080b feat(transactions): add transactions.service 2026-07-31 10:44:57 +00:00
844dd81af2 feat(transactions): add dto 2026-07-31 10:44:56 +00:00
00b0c843f9 feat(decisions): add decisions.module 2026-07-31 10:44:56 +00:00
e1fc7eb0b7 feat(decisions): add decisions.controller 2026-07-31 10:44:55 +00:00
b60c255080 feat(decisions): add decisions.service 2026-07-31 10:44:54 +00:00
df054750f2 feat(decisions): add dto 2026-07-31 10:44:53 +00:00
284fba0d3a feat(goals): add goals.module 2026-07-31 10:44:52 +00:00
90c4932227 feat(goals): add goals.controller 2026-07-31 10:44:51 +00:00
160daab7c9 feat(goals): add goals.service 2026-07-31 10:44:51 +00:00
9d9870877e feat(goals): add dto 2026-07-31 10:44:50 +00:00
a3b29e6cc2 fix: guard Swagger /docs behind SWAGGER_ENABLED env var 2026-07-31 10:32:52 +00:00
10fe16a7f5 fix: guard Swagger /docs behind SWAGGER_ENABLED env var 2026-07-31 10:30:29 +00:00
765ec37c3a feat: Saga Manager (Sprint 4-6)
Motor generic pentru procese cu mai multi pasi care nu incap intr-o
tranzactie. Garantia nu e atomicitatea, ci compensarea in ordine inversa.

- saga-registry: definitii versionate in cod, backoff exponential plafonat
- saga-runner: corelator outbox->instanta, step runner, timeout, retry,
  compensare; revendicare cu FOR UPDATE SKIP LOCKED ca doua procese sa nu
  avanseze aceeasi saga simultan
- idempotenta la pornire prin index unic (saga, versiune, trigger_event),
  nu prin SELECT-apoi-INSERT care ar avea race
- compensarea are propriul retry: o compensare esuata lasa sistemul mai rau
  decat esecul original
- monitor /v1/sagas cu instante blocate si retry manual care NU sare pasi
- prima saga reala: imbogatire research brief, fara pas AI (un apel AI
  automat per brief ar schimba profilul de cost)
2026-07-29 15:02:56 +02:00
c8b9be585e refactor: extrage quiet hours in functie pura si o acopera cu teste
Aritmetica ferestrei care traverseaza miezul noptii era netestata si prinsa
intr-o metoda privata. Extrasa in quiet-hours.ts cu 10 teste care acopera
fereastra simpla, traversarea miezului noptii si politica de bypass CRITICAL.

Documenteaza explicit ca agregarea nu reevalueaza quiet hours: incrementarea
unui contor pe o notificare deja vizibila nu e o intrerupere noua.
2026-07-29 14:48:04 +02:00
80e9ede875 feat: Sprint 2-3 -- Notifications Engine
Motorul NU trimite o notificare per eveniment. Decide daca merita notificat,
cui, ce severitate, daca se agrega, ce canal si cand.

- notifications / notification_preferences / notification_processed_events.
  Ultimul da idempotency: aceeasi regula nu proceseaza acelasi eveniment de
  doua ori (unique rule_id + event_id).
- Reguli in COD, nu in DB cu condition_expression evaluat dinamic. Un
  evaluator de expresii e o suprafata de atac si un limbaj in plus, fara ca
  nimeni sa administreze inca reguli per tenant. Contractul ramane acelasi
  cand vor migra in DB.
- Destinatarii se rezolva server-side din memberships, niciodata din payload.
  Implicit nu notificam actorul despre propria actiune.
- Deduplicare pe cheia tenant+recipient+categorie+entitate+versiune regula.
- Agregare: 47 de taskuri intr-o ora devin o notificare cu aggregated_count,
  nu 47 de notificari. Testul verifica invariantul ca fereastra de agregare
  <= fereastra de dedup, altfel s-ar crea una noua inainte sa se agrege.
- Quiet hours cu fereastra care poate traversa miezul noptii. CRITICAL le
  depaseste DOAR daca politica userului permite, nu implicit.
- Inbox: filtre (unread/action_required/critical/intelligence/system),
  mark-read, acknowledge (opreste escaladarea), dismiss, snooze.
- Preferinte per user+tenant cu UPSERT (NULLS NOT DISTINCT pe category, ca
  randul implicit "toate categoriile" sa fie unic).
2026-07-29 14:36:29 +02:00
eb652446f6 feat: Sprint 1 -- Projection Kernel (read models pentru dashboard)
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.
2026-07-29 12:03:34 +02:00
42cefaddb2 feat: Platform Kernel v1 -- workspaces, ExecutionContext, /v1/navigation, event envelope
Specul de arhitectura cere Platform Kernel INAINTEA modulelor de domeniu.
Modulele A1/A2 au fost construite peste un kernel caruia ii lipseau exact
piesele astea. Le adaug acum, aditiv, fara sa rup ce merge.

- workspaces: tenant != workspace. Workspace-ul e contextul de lucru DIN
  tenant. Backfill: fiecare tenant existent primeste workspace implicit,
  altfel SessionGuard i-ar respinge toate requesturile.
- memberships.workspace_id + valid_from/valid_until: rol per workspace si
  acces delegat cu expirare (contabil pana la o data). SessionGuard respinge
  membership expirat si membership legat de alt workspace.
- ExecutionContext inlocuieste sesiunea subtire (userId+tenantId+role):
  requestId, correlationId, workspaceId, membershipId, roles, permissions,
  purpose, timezone, source. Tipul vechi ramane exportat sub acelasi nume,
  ca sa nu ating ~15 module de domeniu doar pentru o redenumire.
- GET /v1/navigation: menu registry mutat in backend. Filtreaza pe rol, tip
  de workspace, permisiuni si feature flags; intoarce doar itemii autorizati.
  Ramane UX, nu securitate -- fiecare endpoint verifica din nou.
- event envelope: workspace_id, occurred_at, actor_id, aggregate_type,
  causation_id, classification, provenance
- audit envelope: workspace_id, actor_type, purpose, changed_fields,
  before/after hash, session_id
2026-07-29 11:46:20 +02:00
3bc0d65c46 feat: AI Gateway -- Context Manifest, model routing, cost audit, guardrails
- AiGatewayService: punct unic de acces la modele (LiteLLM -> OpenRouter).
  Clasele de actiuni din blueprint 14.3 sunt aplicate hard: high_risk blocat
  permanent, material blocat pana exista coada de aprobare + idempotency;
  doar read_only si draft ruleaza.
- Spotlighting (design doc Strat 1): continutul untrusted (date Apollo) e
  impachetat in <untrusted-data> cu instructiune de sistem ca e DATE, nu
  comenzi -- plus redactie PII deterministica (email/telefon/CNP) inainte
  sa plece catre provider extern.
- ai_requests: adaugat action_class + context_manifest complet (nu doar
  hash) pentru audit; cost_usd_minor_units (integer) inlocuit cu
  cost_usd numeric(12,6) -- costurile reale sunt fractiuni de cent.
- research-briefs: POST /draft genereaza un rezumat AI din datele Apollo
  fara sa salveze nimic (clasa draft -- userul revizuieste, apoi salveaza).
- briefing: aiExplanation devine narativ real peste prioritizarea
  determinista; esecul AI intoarce null, nu strica briefingul.
- teste: clase de actiuni blocate, spotlighting, redactie PII.
2026-07-28 22:34:36 +02:00