import { Injectable } from '@nestjs/common'; import type { NodePgDatabase } from 'drizzle-orm/node-postgres'; import { db } from '../db/client'; import { outboxEvents } from '../db/schema'; import * as schema from '../db/schema'; export interface OutboxEventInput { tenantId: string; /** Fara workspace, proiectiile nu stiu in ce partitie sa scrie si sar evenimentul. */ workspaceId?: string; eventType: string; subjectId?: string; aggregateType?: string; actorId?: string; payload: Record; correlationId?: string; /** Ce comanda/eveniment a produs acest eveniment. */ causationId?: string; /** C0-C4; controleaza catre ce servicii poate fi distribuit. */ classification?: string; provenance?: Record; eventVersion?: number; } type Transaction = Parameters['transaction']>[0]>[0]; /** * Blueprint 9.1 / principiul 2.1 "events before intelligence": orice scriere de * domeniu care trebuie sa produca un eveniment scrie in aceeasi tranzactie in * outbox_events. Publicarea efectiva (dispatch) se face separat, async, de catre * OutboxDispatcher -- niciodata inline in request path. */ @Injectable() export class OutboxService { async withTransaction(fn: (tx: Transaction) => Promise): Promise { return db.transaction(fn); } async record(tx: Transaction, event: OutboxEventInput): Promise { await tx.insert(outboxEvents).values({ tenantId: event.tenantId, workspaceId: event.workspaceId, eventType: event.eventType, eventVersion: event.eventVersion ?? 1, occurredAt: new Date(), actorId: event.actorId, aggregateType: event.aggregateType, subjectId: event.subjectId, payload: event.payload, correlationId: event.correlationId, causationId: event.causationId, classification: event.classification ?? 'c2', provenance: event.provenance ?? {}, }); } }