Merge branch 'forgejo-dev' into working
All checks were successful
Deploy eCourt Note Web to Server / Validate Database Schema (Drizzle) (push) Successful in 4s
Deploy eCourt Note Web to Server / Build Web Docker Image (push) Successful in 1m12s
Deploy eCourt Note Web to Server / Deploy eCourt Note Web to Server (push) Successful in 4s
Deploy eCourt Note Web to Server / Notify Deployment Status (push) Successful in 1s
All checks were successful
Deploy eCourt Note Web to Server / Validate Database Schema (Drizzle) (push) Successful in 4s
Deploy eCourt Note Web to Server / Build Web Docker Image (push) Successful in 1m12s
Deploy eCourt Note Web to Server / Deploy eCourt Note Web to Server (push) Successful in 4s
Deploy eCourt Note Web to Server / Notify Deployment Status (push) Successful in 1s
Resolve CLAUDE.md: คำอธิบาย lib/document-versioning.ts เอาของ forgejo-dev (field `fields` ถอดออก 2026-10-30) ส่วน lib/docver-token.ts เอาของ working (purpose login / verifyDocverLoginToken — โค้ดฝั่ง forgejo-dev มีครบแล้ว แค่คำอธิบายล้าหลัง) Verify: npx tsc --noEmit ผ่าน · vitest 23 files / 338 tests ผ่าน Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
commit
a288e5643c
31 changed files with 1445 additions and 278 deletions
161
lib/openapi.ts
161
lib/openapi.ts
|
|
@ -363,7 +363,9 @@ export const openApiSpec = {
|
|||
tags: ["template"],
|
||||
summary: "ดาวน์โหลดเอกสาร DOCX ผ่าน Query Parameters (GET) ใช้เพื่อเป็นตัวอย่างจะถูกเอาออกในภายหลัง",
|
||||
description:
|
||||
"รับค่า fid, tid, uid, uname จาก Query Parameter อ่านข้อมูล JSON ประจำไฟล์ fid จาก TMPL_PATH แล้วส่งไปประมวลผลต่อที่ /api/template/generate เพื่อสร้างและคืนค่าเป็นไฟล์ DOCX stream ใช้เพื่อเป็นตัวอย่างสำหรับนักพัฒนา ต้องนำออกก่อน production",
|
||||
"รับค่า fid, tid, uid, uname จาก Query Parameter "+
|
||||
"ตรวจสอบรุ่นล่าสุดใน /api/document/latest ถ้าไม่พบ ต้องหาจากฐานข้อมูลแล้วส่งไปประมวลผลต่อที่ /api/template/generate "+
|
||||
"เพื่อสร้างและคืนค่าเป็นไฟล์ DOCX stream ใช้เพื่อเป็นตัวอย่างสำหรับนักพัฒนาเท่านั้น ไม่มีการตรวจสอบ user session ต้องนำออกก่อน production",
|
||||
parameters: [
|
||||
{
|
||||
name: "fid",
|
||||
|
|
@ -462,9 +464,10 @@ export const openApiSpec = {
|
|||
tags: ["template"],
|
||||
summary: "ดาวน์โหลดเอกสาร DOCX ผ่าน HTML Form / Multipart Form Data (POST) เป็นตัวอย่างเท่านั้น จะถูกเอาออกในภายหลัง",
|
||||
description:
|
||||
"รับค่า fid, tid, uid, uname จาก Multipart Form Data หรือ Form-urlencoded อ่านข้อมูล JSON และประมวลผลสร้างไฟล์ DOCX stream คืนกลับไป "+
|
||||
"จะเรียก generate ในเบื้องหลัง ใช้เพื่อเป็นตัวอย่างสำหรับนักพัฒนา ต้องนำออกก่อน production",
|
||||
requestBody: {
|
||||
"รับค่า fid, tid, uid, uname จาก Multipart Form Data หรือ Form-urlencoded "+
|
||||
"ตรวจสอบรุ่นล่าสุดใน /api/document/latest ถ้าไม่พบ ต้องหาจากฐานข้อมูลแล้วส่งไปประมวลผลต่อที่ /api/template/generate "+
|
||||
"เพื่อสร้างและคืนค่าเป็นไฟล์ DOCX stream ใช้เพื่อเป็นตัวอย่างสำหรับนักพัฒนาเท่านั้น ไม่มีการตรวจสอบ user session ต้องนำออกก่อน production",
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
"multipart/form-data": {
|
||||
|
|
@ -774,7 +777,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,
|
||||
|
|
@ -799,13 +806,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 ตัวอักษร)",
|
||||
|
|
@ -930,6 +930,100 @@ export const openApiSpec = {
|
|||
},
|
||||
},
|
||||
},
|
||||
"/api/documents/latest": {
|
||||
get: {
|
||||
tags: ["documents"],
|
||||
summary:
|
||||
"ดาวน์โหลดไฟล์ของ version ล่าสุด (docx พร้อม stamp ticket ใหม่ / pdf ตรง ๆ)",
|
||||
description:
|
||||
"ให้ backend e-Court ดึงไฟล์ **version ล่าสุด** ของเอกสารกลับไปเปิดให้ผู้ใช้ " +
|
||||
"(server-to-server — ไม่ใช้ Bearer token)\n\n" +
|
||||
"- **auth**: header `x-api-key` เทียบ env `DOCVER_API_KEY` **หรือ** " +
|
||||
"`EXTERNAL_API_KEY` ตัวใดตัวหนึ่ง (ต่างจาก /token ที่รับ DOCVER_API_KEY " +
|
||||
"อย่างเดียว) · ทั้งคู่ไม่ตั้ง = 401 fail closed\n" +
|
||||
"- เอกสารถูกระบุด้วย `fid` **ใน ticket_data** (ไม่ใช่ token)\n" +
|
||||
"- `type=pdf` → คืนไบต์ pdf ตรง ๆ (version ล่าสุดไม่มีสำเนา PDF = 404)\n" +
|
||||
"- `type=docx` → server เติม `exp` ใหม่ (now + `TICKET_SEC` default 300 วิ) + " +
|
||||
"คำนวณ `HmacSha256` (secret ตาม chain `ADDIN_TICKET_SECRET` → `SECRET` → " +
|
||||
"`\"super_secret\"` ให้ตรงฝั่ง verify ของ add-in) และ `Ed25519` (เฉพาะเมื่อ " +
|
||||
"`PRIVATE_KEY_HEX` ตั้ง) แล้วเขียน custom properties ลง**สำเนาในหน่วยความจำ** " +
|
||||
"ก่อนคืนไฟล์ — object ใน MinIO ไม่ถูกแต่ (non-destructive) และเขียนทับ stamp " +
|
||||
"เดิมของ template ได้\n" +
|
||||
"- **ticket_data บังคับ `fid` + `uid` + `uname`** (`tid` optional · `exp` ถ้าส่ง " +
|
||||
"ต้องเป็นจำนวนเต็ม แต่จะถูกเติมใหม่เสมอ) เพราะ parser ฝั่ง add-in บังคับทั้งสาม — " +
|
||||
"⚠️ `uid` ต้องเป็น*รหัส*ผู้ใช้ (ไม่ใช่ชื่อ) และต้องส่ง `uname` (ชื่อแสดงผล)\n" +
|
||||
"- ticket_data หลังเติม exp ยาวเกิน 255 ตัวอักษร = 400 (ข้อจำกัด custom property " +
|
||||
"ของ Word)",
|
||||
security: [{ ApiKeyAuth: [] }],
|
||||
parameters: [
|
||||
{
|
||||
name: "type",
|
||||
in: "query",
|
||||
required: true,
|
||||
schema: { type: "string", enum: ["docx", "pdf"] },
|
||||
description: "ชนิดไฟล์ที่จะดาวน์โหลด (บังคับระบุ — ไม่มีค่า default)",
|
||||
},
|
||||
{
|
||||
name: "ticket_data",
|
||||
in: "query",
|
||||
required: true,
|
||||
schema: { type: "string" },
|
||||
description:
|
||||
"JSON string ของ ticket เช่น " +
|
||||
"`{\"fid\":\"DOC-2569-0001\",\"uid\":\"123\",\"uname\":\"สมชาย ใจดี\"}` " +
|
||||
"(ต้อง URL-encode — ใช้ URLSearchParams ของฝั่งเรียกก็ได้)",
|
||||
example:
|
||||
"{\"fid\":\"DOC-2569-0001\",\"uid\":\"123\",\"uname\":\"สมชาย ใจดี\"}",
|
||||
},
|
||||
],
|
||||
responses: {
|
||||
200: {
|
||||
description:
|
||||
"ไบต์ของไฟล์ (docx = ผ่านการ stamp ticket ใหม่ · pdf = ตรงจาก version ล่าสุด)",
|
||||
headers: {
|
||||
"Content-Disposition": {
|
||||
description: "attachment พร้อมชื่อไฟล์ของ version (ชื่อไทยผ่าน filename*)",
|
||||
schema: { type: "string" },
|
||||
},
|
||||
"Cache-Control": {
|
||||
description: "no-store — ไฟล์ผูกกับ ticket/exp ของ request นั้น",
|
||||
schema: { type: "string" },
|
||||
},
|
||||
},
|
||||
content: {
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
|
||||
schema: { type: "string", format: "binary" },
|
||||
},
|
||||
"application/pdf": {
|
||||
schema: { type: "string", format: "binary" },
|
||||
},
|
||||
},
|
||||
},
|
||||
400: { $ref: "#/components/responses/BadRequest" },
|
||||
401: {
|
||||
description:
|
||||
"x-api-key ไม่ตรงทั้ง DOCVER_API_KEY และ EXTERNAL_API_KEY หรือทั้งคู่ไม่ตั้งค่า " +
|
||||
"(ไม่ใส่ header กับ key ผิดได้ข้อความเดียวกัน)",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: { $ref: "#/components/schemas/Error" },
|
||||
},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description:
|
||||
"ไม่พบเอกสารนี้ในระบบ (ยังไม่เคยอัปโหลด version) หรือ type=pdf แต่ version " +
|
||||
"ล่าสุดไม่มีสำเนา PDF",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: { $ref: "#/components/schemas/Error" },
|
||||
},
|
||||
},
|
||||
},
|
||||
500: { $ref: "#/components/responses/ServerError" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
securitySchemes: {
|
||||
|
|
@ -940,7 +1034,8 @@ export const openApiSpec = {
|
|||
description:
|
||||
"x-api-key ของ N10 = env EXTERNAL_API_KEY · ของการขอ token กลุ่ม documents = env " +
|
||||
"DOCVER_API_KEY (คนละค่ากับของ N10 — กดปุ่ม Authorize ใส่ครั้งเดียวแล้วใช้ได้ทุก " +
|
||||
"request ของกลุ่มที่ key ตรง)",
|
||||
"request ของกลุ่มที่ key ตรง) · GET /api/documents/latest พิเศษ: รับได้ทั้งสองค่า " +
|
||||
"(DOCVER_API_KEY **หรือ** EXTERNAL_API_KEY ตัวใดตัวหนึ่งตรง = ผ่าน)",
|
||||
},
|
||||
DocverBearer: {
|
||||
type: "http",
|
||||
|
|
@ -1235,6 +1330,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 ใหม่ → เก่า)",
|
||||
|
|
@ -1249,11 +1378,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" },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue