实现业务附件受控入库 V1(05-28-business-attachment-governance-v1)

这个提交包含在:
2026-05-28 19:44:15 +08:00
父节点 2c067866ef
当前提交 52e5284954
共修改 25 个文件,包含 1119 行新增和 21 行删除
@@ -8,10 +8,18 @@ const multipart = require("@fastify/multipart");
const { AppError } = require("../../../src/utils/AppError");
const reimbursementRoutes = require("../../../src/routes/reimbursements");
function buildMultipartRequest({ files }) {
function buildMultipartRequest({ files, fields = {} }) {
const boundary = "----codex-reimbursement-attachment-boundary";
const segments = [];
for (const [name, value] of Object.entries(fields)) {
segments.push(
Buffer.from(
`--${boundary}\r\nContent-Disposition: form-data; name="${name}"\r\n\r\n${value}\r\n`,
),
);
}
for (const file of files) {
segments.push(
Buffer.from(
@@ -55,6 +63,16 @@ async function buildApp({ reimbursementStatus = "draft" } = {}) {
mime_type: data.mime_type,
file_size: data.file_size,
file_sha256: data.file_sha256,
governance_status: data.governance_status,
sensitivity_level: data.sensitivity_level,
attachment_type: data.attachment_type,
reviewed_by: data.reviewed_by ?? null,
reviewed_at: data.reviewed_at ?? null,
review_note: data.review_note ?? null,
archived_by: data.archived_by ?? null,
archived_at: data.archived_at ?? null,
archive_note: data.archive_note ?? null,
download_policy: data.download_policy,
storage_path: data.storage_path,
created_at: new Date("2026-05-08T08:00:00.000Z"),
uploader: {
@@ -91,6 +109,10 @@ async function buildApp({ reimbursementStatus = "draft" } = {}) {
storage_path: item.storage_path,
original_name: item.original_name,
mime_type: item.mime_type,
governance_status: item.governance_status,
sensitivity_level: item.sensitivity_level,
attachment_type: item.attachment_type,
download_policy: item.download_policy,
reimbursement_form: {
owner_id: "actor-1",
submitter_id: "actor-1",
@@ -201,6 +223,10 @@ describe("reimbursement attachment routes", () => {
expect.objectContaining({
originalName: "contract.pdf",
mimeType: "application/pdf",
governanceStatus: "approved",
sensitivityLevel: "internal",
attachmentType: "supporting_material",
downloadPolicy: "standard",
uploadedBy: expect.objectContaining({ name: "测试用户" }),
}),
);
@@ -210,6 +236,10 @@ describe("reimbursement attachment routes", () => {
data: expect.objectContaining({
action: "REIMBURSEMENT_ATTACHMENTS_UPLOADED",
target_id: reimbursementId,
extra: expect.objectContaining({
attachmentType: "supporting_material",
sensitivityLevel: "internal",
}),
}),
}),
);