feat: add new legal document and database schema for module L compliance

Co-authored-by: cetinmustafa83 <30570791+cetinmustafa83@users.noreply.github.com>
This commit is contained in:
v0andcetinmustafa83 committed 2026-07-31 13:34:58 +00:00
1 parent e6d82083d7
commit 927aae8580
24 files changed
+6565 -1

No files matched your search

Executable → Regular
+134
View File
@@ -138,3 +138,137 @@ export function withAuditLog(
return response;
};
}
// ─── Module L: Compliance Audit Logging ────────────────────────────────
export interface ComplianceAuditParams extends AuditLogParams {
dataSubject?: string; // Student ID if applicable (for GDPR export scope)
}
/**
* Log compliance-specific actions (DPO approvals, policy changes, etc.)
* Includes dataSubject field for tracking affected individuals
*/
export async function logComplianceAudit(params: ComplianceAuditParams): Promise<void> {
try {
let userId = params.userId;
if (!userId) {
const session = await getSession();
userId = session?.user?.id ?? undefined;
}
await db.auditLog.create({
data: {
userId: userId ?? null,
schoolId: params.schoolId ?? null,
action: params.action,
entityType: params.entityType,
entityId: params.entityId ?? null,
changes: params.changes ? JSON.stringify(params.changes) : null,
ipAddress: params.ipAddress ?? null,
userAgent: params.userAgent ?? null,
metadata: params.metadata ? JSON.stringify(params.metadata) : null,
dataSubject: params.dataSubject ?? null, // Track affected individual
},
});
} catch (error) {
console.error("[v0] Compliance audit log error:", error);
}
}
/**
* Log when a student's data is accessed (for audit trail)
*/
export async function logDataAccess(
userId: string,
studentId: string,
action: string,
schoolId?: string,
metadata?: Record<string, unknown>
): Promise<void> {
await logComplianceAudit({
userId,
schoolId,
action: `DATA_ACCESS_${action}`, // e.g., DATA_ACCESS_VIEW_GRADES
entityType: "Student",
entityId: studentId,
dataSubject: studentId,
metadata: {
...metadata,
timestamp: new Date().toISOString(),
},
});
}
/**
* Log DPO approval actions
*/
export async function logDPOApproval(
dpoId: string,
schoolId: string,
approvalType: string,
metadata?: Record<string, unknown>
): Promise<void> {
await logComplianceAudit({
userId: dpoId,
schoolId,
action: `DPO_APPROVAL_${approvalType}`,
entityType: "ComplianceStatus",
metadata,
});
}
/**
* Log policy updates
*/
export async function logPolicyUpdate(
userId: string,
schoolId: string,
policyType: string,
changes: AuditLogParams['changes'],
): Promise<void> {
await logComplianceAudit({
userId,
schoolId,
action: "POLICY_UPDATE",
entityType: policyType, // e.g., "DataRetentionPolicy"
changes,
});
}
/**
* Query audit logs for a specific data subject (student)
* Used for GDPR right-of-access requests
*/
export async function getAuditTrailForDataSubject(
schoolId: string,
studentId: string,
limit: number = 100
) {
try {
const logs = await db.auditLog.findMany({
where: {
schoolId,
dataSubject: studentId,
},
orderBy: { timestamp: "desc" },
take: limit,
select: {
id: true,
action: true,
entityType: true,
userId: true,
timestamp: true,
metadata: true,
},
});
return logs.map((log) => ({
...log,
metadata: log.metadata ? JSON.parse(log.metadata) : null,
}));
} catch (error) {
console.error("[v0] Error querying audit trail:", error);
return [];
}
}