@krizaka /审计
谁做了什么,为每一个克里扎卡产品。 trail是只能追加的,并且存在于产品的数据库中,在Postgres模式中 audit.
- 两种写法: 在调用者的事务内部(它与工作一起提交或回滚),或静静地在它旁边(记录失败,从不抛出)。
- 对于管理员: 过滤和分页。
- Loi 25: 导出并编辑。
- 保留: 在保留管理集后清除。
没有数据库客户端,也没有挂钟:您传递了一个 Query 和一个 Clock.
pnpm add @krizaka/audit @krizaka/db
将其模式添加到您的迁移中
模式嵌入到 @krizaka/db,按你自己的顺序:
import { emitMigration } from "@krizaka/db";
import { auditSchema } from "@krizaka/audit";
// commit the output as one of your migrations (drizzle-kit `generate --custom`, or your list)
emitMigration(auditSchema, 1, { tables: { owner: "accounts" } });
这张桌子是 audit.entry. 它持有的时间,演员(指你) accounts, ON DELETE SET NULL)、可读标签、带点的动作(billing.checkout_started)、可选目标、详细信息(jsonb)和IP。
使用
import { createAudit } from "@krizaka/audit";
import { transaction } from "@krizaka/db";
const audit = createAudit({ clock: { now: () => new Date() }, onError: (e) => logger.warn(e) });
// Inside a unit of work: the entry exists only if the work commits.
await transaction(connect, async (tx) => {
await suspendUser(tx, userId);
await audit.record(tx, { actorId: admin.id, actorLabel: admin.name, action: "admin.user_suspended", target: { type: "account", id: userId } });
});
// Beside it: never fails the request.
await audit.recordQuietly(query, { actorId: null, actorLabel: "stripe webhook", action: "billing.event_ignored", detail: { type } });
// The admin's view: newest first, filtered, paged by cursor.
const page = await audit.list(query, { actionPrefix: "admin.", limit: 50 });
const next = await audit.list(query, { actionPrefix: "admin.", limit: 50, before: page.at(-1)?.id });
-
25法则:
exportFor(query, accountId)给出该人的条目;redactActor(tx, accountId)保留事实并删除人:id和IP变为空,标签变为“擦除”。
输入尽可能少的个人信息
detail根据行动需要。 -
保留: 注册
auditSettings在你的@krizaka/settings注册表(audit.retentionDays:默认为1095天,30-3650天)。你的工作需要你audit.purge(tx, { retentionDays }). -
来自请求的输入以相同的方式检查每个存储: 页面大小必须是一个正整数(上限为200),游标必须是一个条目id, IP必须是一个地址,保留期必须在设置的范围内(30-3650天),所以错误的值永远不会清除整个跟踪。每一次拒绝都是一次
AuditError具有稳定的代码(AUDIT_BAD_FILTER,AUDIT_BAD_IP,AUDIT_BAD_RETENTION……)。 -
固定的动作列表:
createAudit({ allowedActions: [...] })拒绝其他任何东西(AUDIT_UNKNOWN_ACTION)。 -
另一个商店 运行合同工具包:
auditStoreContract从@krizaka/audit/testkit.memoryAuditStore()是参考。