16bd2cb92a
- 모노레포 구조 (Turborepo + pnpm): @relink/domain, @relink/shared, @relink/infrastructure, @relink/database, @relink/web - 도메인 레이어: 매장(store), 매칭(matching), 업체(vendor), 보조금(subsidy), 계약/에스크로(contract) TDD 완료 (158 단위 테스트) - 서비스 레이어: 전 도메인 서비스 함수 + 통합 테스트 (58 테스트) - 프론트엔드: Next.js 15 App Router, 13개 페이지 (사용자 6 + 관리자 7) - 인프라: PostgreSQL 16 + PostGIS, Prisma ORM, Docker Compose, AuditLog + OutboxEvent 패턴 - .env 파일 포함 (로컬 개발 기본값만 포함, 실제 시크릿 없음) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
38 lines
1.2 KiB
TypeScript
38 lines
1.2 KiB
TypeScript
import type { Prisma } from '@prisma/client';
|
|
import { randomUUID } from 'node:crypto';
|
|
|
|
type TxClient = Prisma.TransactionClient;
|
|
|
|
export interface RecordEventInput {
|
|
readonly aggregateType: string;
|
|
readonly aggregateId: string;
|
|
readonly eventName: string;
|
|
readonly eventVersion: number;
|
|
readonly payloadJson: Record<string, unknown>;
|
|
readonly actorUserId?: bigint;
|
|
readonly causationId?: string;
|
|
readonly correlationId?: string;
|
|
readonly piiLevel?: 'NONE' | 'LOW' | 'HIGH';
|
|
readonly occurredAt?: Date;
|
|
}
|
|
|
|
export async function recordEvent(tx: TxClient, input: RecordEventInput) {
|
|
const eventKey = `${input.aggregateType}:${input.aggregateId}:${input.eventName}:${randomUUID()}`;
|
|
|
|
return tx.eventLog.create({
|
|
data: {
|
|
aggregateType: input.aggregateType,
|
|
aggregateId: input.aggregateId,
|
|
eventName: input.eventName,
|
|
eventVersion: input.eventVersion,
|
|
eventKey,
|
|
payloadJson: input.payloadJson as object,
|
|
actorUserId: input.actorUserId ?? null,
|
|
causationId: input.causationId ?? null,
|
|
correlationId: input.correlationId ?? null,
|
|
piiLevel: input.piiLevel ?? 'NONE',
|
|
occurredAt: input.occurredAt ?? new Date(),
|
|
},
|
|
});
|
|
}
|