1import { Controller, Get, Inject, Param, Query, Req } from "@nestjs/common";
2import type { Request } from "express";
3import { z } from "zod";
4import { PrismaService } from "../../common/prisma.service.js";
5import { ZodValidate } from "../../common/pipes/zod-validation.pipe.js";
6import { requireUser } from "../../common/types.js";
7import { assertRole } from "../../lib/authorize.js";
8
9
16const ListQuery = z.object({
17 action: z.string().min(1).max(128).optional(),
18 limit: z.coerce.number().int().min(1).max(100).default(50),
19});
20
21@Controller("workspaces/:workspaceId/audit")
22export class AuditLogController {
23 constructor(@Inject(PrismaService) private readonly prisma: PrismaService) {}
24
25 @Get()
26 async list(
27 @Param("workspaceId") workspaceId: string,
28 @Query(ZodValidate(ListQuery)) query: z.infer<typeof ListQuery>,
29 @Req() req: Request,
30 ) {
31 const userId = requireUser(req);
32 await assertRole(this.prisma, { workspaceId, userId }, ["OWNER", "ADMIN"]);
33 const rows = await this.prisma.auditLog.findMany({
34 where: { workspaceId, ...(query.action ? { action: query.action } : {}) },
35 orderBy: [{ createdAt: "desc" }, { id: "desc" }],
36 take: query.limit,
37 select: {
38 id: true,
39 actorType: true,
40 actorId: true,
41 resourceType: true,
42 resourceId: true,
43 action: true,
44 ipAddress: true,
45 createdAt: true,
46 metadata: true,
47 },
48 });
49 return { data: rows };
50 }
51}
52