Refactor document versioning to extract fields from uploaded .docx files on the server side

- Removed the `fields` parameter from the version upload form, as it is now extracted from the uploaded .docx file using the `extractContentControls` function.
- Updated related types and interfaces to reflect the new structure of version fields.
- Modified the OpenAPI specification to document the changes in the versioning process.
- Adjusted tests to ensure compliance with the new behavior, including validation for the absence of the `fields` parameter.
- Implemented a new function `extractDocumentSnapshot` to handle the extraction of content controls and document properties from .docx files.
- Updated metadata and versioning services to align with the new extraction logic.
This commit is contained in:
Suphonchai Phoonsawat 2026-10-31 10:21:17 +07:00
parent bc61f0fd2e
commit cdae1ceedd
17 changed files with 380 additions and 179 deletions

View file

@ -705,7 +705,11 @@ export const openApiSpec = {
"- `versionNumber` ใน response คือเลขจริงที่ server จ่าย (ปลอดภัยแม้อัปโหลดพร้อมกัน " +
"หลาย client) — ถ้าต่างจากที่ client คาดไว้ ให้ใช้เลขจาก response เสมอ\n" +
"- ผู้อัปโหลด (userId/userName) และ templateId อ่านจาก token — " +
"**ห้ามส่ง field เหล่านี้ใน form (ส่งมา = 400)**",
"**ห้ามส่ง field เหล่านี้ใน form (ส่งมา = 400)**\n" +
"- `fields` ของ version ถูก server แกะจากไฟล์ .docx ที่อัปโหลดเอง เก็บ**ทั้งก้อนเหมือน " +
"return ของ `/api/template/extract`** (`{cc, bookmark, properties, verify}` — ผ่าน helper " +
"ตัวเดียวกัน) โดย `verify.HmacSha256` ตรวจด้วย secret ของ ticket ฝั่ง server — " +
"**ห้ามส่ง field `fields` ใน form (ส่งมา = 400)**",
security: [{ DocverBearer: [] }],
requestBody: {
required: true,
@ -730,13 +734,6 @@ export const openApiSpec = {
type: "string",
description: "GUID ที่ client generate ก่อนเรียก (เก็บไว้สืบสวน ไม่ใช่ identity)",
},
fields: {
type: "string",
description:
'JSON string ของค่า Content Control **ทุกตัว** ในเอกสาร รูปแบบ ' +
'`{ [tag]: ข้อความ }` (add-in อ่านมาตอนบันทึก version) ' +
'เช่น {"blackno":"คดีหมายเลขดำที่","detail1":"…"}',
},
message: {
type: "string",
description: "commit message ของ version (≤ 2048 ตัวอักษร)",
@ -1166,6 +1163,40 @@ export const openApiSpec = {
},
},
},
ExtractSnapshot: {
type: "object",
description:
"ก้อนข้อมูลแกะจากไฟล์ .docx — รูปเดียวกับ return ของ POST /api/template/extract " +
"(ใช้ helper ตัวเดียวกันใน lib/lib-tmpl.ts)",
properties: {
cc: {
type: "object",
description: "ค่า Content Control ทุกตัว รูปแบบ `{ [tag]: ข้อความ }`",
additionalProperties: { type: "string" },
},
bookmark: {
type: "object",
description: "ข้อความใน bookmark รูปแบบ `{ [ชื่อ bookmark]: ข้อความ }`",
additionalProperties: { type: "string" },
},
properties: {
type: "object",
description: "document properties — standard (core) / extended (app) / custom",
properties: {
standard: { type: "object", additionalProperties: { type: "string" } },
extended: { type: "object", additionalProperties: { type: "string" } },
custom: { type: "object", additionalProperties: {} },
},
},
verify: {
type: "object",
description:
"ผลตรวจ ticket ที่ stamp มากับไฟล์ — exp (วันที่ไทย +07:00) และ HmacSha256 " +
"(boolean — ตรวจด้วย secret ของ ticket ฝั่ง server)",
additionalProperties: {},
},
},
},
VersionRecord: {
type: "object",
description: "รายการ version หนึ่งตัว (GET /versions คืนเป็น array ใหม่ → เก่า)",
@ -1180,11 +1211,11 @@ export const openApiSpec = {
description: "SHA-256 hex ของไฟล์ .docx (คำนวณฝั่ง server เสมอ)",
},
fields: {
type: "object",
nullable: true,
description:
"ค่า Content Control ทุกตัวตอนอัปโหลด รูปแบบ `{ [tag]: ข้อความ }` (ไม่ส่ง = null)",
additionalProperties: { type: "string" },
"snapshot ตอนอัปโหลด — **ก้อนเดียวกับ return ของ /api/template/extract** (server " +
"แกะจากไฟล์ .docx เอง; null = version เก่าก่อน 2026-10-30)",
allOf: [{ $ref: "#/components/schemas/ExtractSnapshot" }],
},
message: { type: "string", nullable: true, description: "commit message" },
hasPdf: { type: "boolean" },