feat(p9): iios_audit_link table + audit binding at decision points
Task O.3: IiosAuditLink (traceId/correlationId/scopeId/actorRefId/action/ resourceType/resourceId) + recordAudit() helper (reads the current trace from ALS, best-effort). Written at the decision/mutation points — route approve/deny, AI accept/reject, meeting summarize, outbound send — so the trace appears in DB and a decision can be replayed / traced across services (mandated iios_audit_link). Migration audit-link; resetDb truncates it. 2 tests bind approve/accept to a trace. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import type { PrismaService } from '../prisma/prisma.service';
|
||||
import { currentTraceId } from './trace-context';
|
||||
|
||||
export interface AuditInput {
|
||||
action: string;
|
||||
resourceType: string;
|
||||
resourceId: string;
|
||||
scopeId?: string;
|
||||
actorRefId?: string;
|
||||
correlationId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an audit link (P9): binds an action to its trace + actor + resource so a
|
||||
* decision can be replayed / a request traced across services. Plain function — reads
|
||||
* the current request's trace id from AsyncLocalStorage (no DI). Best-effort: never
|
||||
* throws into the caller's happy path.
|
||||
*/
|
||||
export async function recordAudit(prisma: PrismaService, input: AuditInput): Promise<void> {
|
||||
try {
|
||||
await prisma.iiosAuditLink.create({
|
||||
data: {
|
||||
action: input.action,
|
||||
resourceType: input.resourceType,
|
||||
resourceId: input.resourceId,
|
||||
scopeId: input.scopeId,
|
||||
actorRefId: input.actorRefId,
|
||||
traceId: currentTraceId(),
|
||||
correlationId: input.correlationId ?? currentTraceId(),
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
/* audit is best-effort; do not break the request */
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user