- packages/auth: Argon2id password hashing, JWT access tokens (jose), opaque refresh tokens with rotation, generic error messages (no user-enumeration via timing or message differences) - roles/permissions/role_permissions/user_roles/sessions/audit_logs schema (agente.md secoes 142-150); RBAC scope PLATFORM vs TENANT - withUserContext(): narrow RLS exception so a user can discover their own tenant_memberships before a tenant is chosen (login flow) - userHasPermission()/isPlatformUser(): explicit service-layer RBAC checks (roles/permissions tables are not RLS-protected — documented why in docs/AUTHENTICATION.md) - seed: permission catalog, 4 system roles, initial Platform Super Admin (password written once to FIRST_LOGIN.txt, 600, outside Git) - automated end-to-end test: login, RBAC check, refresh rotation, logout
30 lines
775 B
TypeScript
30 lines
775 B
TypeScript
import type { Prisma, PrismaClient } from "@b2bcall/database";
|
|
|
|
export interface AuditEvent {
|
|
action: string;
|
|
tenantId?: string | null;
|
|
userId?: string | null;
|
|
entityType?: string;
|
|
entityId?: string;
|
|
before?: Prisma.InputJsonValue;
|
|
after?: Prisma.InputJsonValue;
|
|
ipAddress?: string;
|
|
userAgent?: string;
|
|
}
|
|
|
|
export async function recordAuditEvent(prisma: PrismaClient, event: AuditEvent): Promise<void> {
|
|
await prisma.auditLog.create({
|
|
data: {
|
|
action: event.action,
|
|
tenantId: event.tenantId ?? null,
|
|
userId: event.userId ?? null,
|
|
entityType: event.entityType,
|
|
entityId: event.entityId,
|
|
before: event.before,
|
|
after: event.after,
|
|
ipAddress: event.ipAddress,
|
|
userAgent: event.userAgent,
|
|
},
|
|
});
|
|
}
|