Merge branch 'forgejo-dev' into newfeat
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
commit
c57a75e36a
50 changed files with 2760 additions and 961 deletions
|
|
@ -33,10 +33,9 @@ export function addinTicketSecret(): string {
|
|||
}
|
||||
|
||||
/**
|
||||
* ตรวจ ticket แบบไม่สน exp (HMAC → parse) — ใช้เมื่อ route จะตัดสิน "ticket หมดอายุ
|
||||
* แต่เอกสารนี้เคยทำงานโดย uid เดียวกัน" เองผ่าน DB (requirement ขั้น 7: กลับมาทำ
|
||||
* เอกสารเดิมผ่านได้แม้ ticket หมดอายุ) — ตัวตนของผู้ถือยังยึด HMAC ของ e-Court
|
||||
* เหมือนเดิม แค่ไม่ใช้อายุ ticket เป็นเกณฑ์ตัดสิทธิ์ ณ จุดนี้
|
||||
* ตรวจ ticket แบบไม่สน exp (HMAC → parse) — route เป็นคนตัดสิน exp เองภายหลัง
|
||||
* (ลายเซ็นถูกแต่หมดอายุ = 403, contract 2026-11-04) — ตัวตนของผู้ถือยึด HMAC
|
||||
* ของ e-Court เหมือนเดิม แค่ไม่ใช้อายุ ticket เป็นเกณฑ์ตัดสิทธิ์ ณ จุดนี้
|
||||
*/
|
||||
export function verifyAddinTicketHmac(
|
||||
ticketData: string,
|
||||
|
|
@ -89,7 +88,7 @@ export type TicketTokenBodyResult =
|
|||
|
||||
/**
|
||||
* parse body ของ POST /api/documents/token ทางเข้า ticket
|
||||
* - `missing` = ไม่มี ticket มาเลย (route ตอบ 401 — คำเดียวกับตอน verify ไม่ผ่าน)
|
||||
* - `missing` = ไม่มี ticket มาเลย (route ตอบ 400 — ฟอร์แม็ตพัง, contract 2026-11-04)
|
||||
* - `invalid` = รูปผิด (route ตอบ 400 ตาม convention กัน typo เงียบ ๆ)
|
||||
*/
|
||||
export function parseTicketTokenBody(raw: unknown): TicketTokenBodyResult {
|
||||
|
|
|
|||
|
|
@ -252,22 +252,6 @@ export async function findLatestVersionForDoc(
|
|||
return row?.version ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* เอกสาร (docId) นี้เคยมี version ที่สร้างโดย userId นี้หรือยัง — ใช้เป็นหลักฐาน
|
||||
* "เคยทำงานกับเอกสารนี้" ตอนยอมรับ ticket ที่หมดอายุ (requirement ขั้น 7:
|
||||
* กลับมาทำเอกสารเดิมผ่านได้แม้ ticket หมดอายุ — ตัวตนยังยึด HMAC ของ e-Court
|
||||
* ทางเข้า /api/documents/token ของ add-in) · อ่านอย่างเดียว ไม่แตะ MinIO
|
||||
*/
|
||||
export async function hasVersionByUser(docId: string, userId: string): Promise<boolean> {
|
||||
const [row] = await db
|
||||
.select({ one: sql`1` })
|
||||
.from(documentVersions)
|
||||
.innerJoin(documents, eq(documentVersions.documentId, documents.id))
|
||||
.where(and(eq(documents.docId, docId), eq(documentVersions.userId, userId)))
|
||||
.limit(1);
|
||||
return row !== undefined;
|
||||
}
|
||||
|
||||
export type InsertVersionInput = {
|
||||
/** กำหนดเอง (ไม่ปล่อย defaultRandom) เพราะ object ใน MinIO เขียนด้วย uuid นี้ไปก่อนแล้ว */
|
||||
versionId: string;
|
||||
|
|
|
|||
291
lib/openapi.ts
291
lib/openapi.ts
|
|
@ -1,6 +1,7 @@
|
|||
// OpenAPI 3.0 spec ของ API ทดสอบทั้งหมดของ judes-note — เส้นเดียวกับที่ Swagger UI
|
||||
// แสดงผล: กลุ่ม template (DOCX Content Control) + N10 external API + docver
|
||||
// (จัด version เอกสาร)
|
||||
// (จัด version เอกสาร) + auth (ทางเข้า path สั้น /api/auth/* — alias ของ
|
||||
// /api/documents/token กับ /api/note/auth/session เพิ่ม 2026-11-05)
|
||||
// route handler GET /api/swagger (app/api/swagger/route.ts) เป็นคนเดียวที่ใช้
|
||||
// — inline เป็น JSON ลงใน HTML ตอน respond (ไม่มี endpoint spec แยก)
|
||||
//
|
||||
|
|
@ -25,7 +26,8 @@ export const openApiSpec = {
|
|||
version: "1.0.0",
|
||||
description:
|
||||
"API ทดสอบของระบบ Judge's Note — กลุ่ม Template (DOCX Content Control), " +
|
||||
"API ภายนอกสำหรับ backend e-Court (N10) และ API จัด version เอกสาร (docver)",
|
||||
"API ภายนอกสำหรับ backend e-Court (N10), API จัด version เอกสาร (docver) " +
|
||||
"และทางเข้า auth แบบ path สั้น (/api/auth/*)",
|
||||
},
|
||||
servers: [{ url: BASE_PATH, description: "origin เดียวกับหน้านี้ (basePath /docedit)" }],
|
||||
tags: [
|
||||
|
|
@ -59,6 +61,15 @@ export const openApiSpec = {
|
|||
"server-to-server ดึง annotations/bookmarks ของเอกสารที่เคยเปิดในระบบนี้ · " +
|
||||
"SSO: เส้น mint login-token สำหรับประกอบลิงก์เข้าสู่ระบบ (PLAN-SSO.md)",
|
||||
},
|
||||
{
|
||||
name: "auth",
|
||||
description:
|
||||
"ทางเข้า auth แบบ **path สั้น** `/api/auth/*` (เพิ่ม 2026-11-05) — endpoint " +
|
||||
"ก้อนเดียวกับของเดิมคนละ URL เลือกใช้ทางใดทางหนึ่งได้:\n" +
|
||||
"- `POST /api/auth/token` = `POST /api/documents/token` — ออก access_token ของกลุ่ม documents (docver)\n" +
|
||||
"- `POST /api/auth/session` = `POST /api/note/auth/session` — แลก credential ของลิงก์ e-Court " +
|
||||
"เป็น session token ของแอป note",
|
||||
},
|
||||
],
|
||||
paths: {
|
||||
"/api/template/test": {
|
||||
|
|
@ -827,23 +838,27 @@ export const openApiSpec = {
|
|||
},
|
||||
},
|
||||
},
|
||||
"/api/documents/token": {
|
||||
"/api/auth/token": {
|
||||
post: {
|
||||
tags: ["documents"],
|
||||
summary: "ขอ access_token ของกลุ่ม documents (docver)",
|
||||
tags: ["auth"],
|
||||
summary: "ขอ access_token ของกลุ่ม documents (docver) — path สั้นของ /api/documents/token",
|
||||
description:
|
||||
"ทางเข้า **path สั้น** ของ `POST /api/documents/token` — endpoint ก้อนเดียวกัน " +
|
||||
"พฤติกรรมเหมือนกันทุกประการ (เพิ่ม 2026-11-05)\n\n" +
|
||||
"ออก `access_token` (JWT HS256) ไว้เรียก endpoint อื่นของกลุ่ม documents — " +
|
||||
"token ฝัง claims `{userid, username, fid, template}` อายุตาม env " +
|
||||
"`DOCVER_TOKEN_TTL_SECONDS` (default 3600 วินาที)\n\n" +
|
||||
"`DOCVER_TOKEN_TTL_SECONDS` (default 604800 วินาที = 7 วัน — token อายุยาวแทน" +
|
||||
"ระบบ refresh/renew ของ add-in)\n\n" +
|
||||
"**ทางเข้า 2 แบบ** — เลือกตามว่าใครเป็นคนเรียก (ดูตัวอย่างใน Request body ได้ทั้งคู่):\n\n" +
|
||||
"1. **ระบบภายนอก (server-to-server)** — แนบ header `x-api-key` (ค่าจาก env " +
|
||||
"`DOCVER_API_KEY`) แล้วส่ง claims ตรง ๆ ใน body ตาม schema `TokenRequest`\n" +
|
||||
"2. **add-in ใน Word** — ไม่ต้องมี `x-api-key` ส่ง body `{ticket_data, HmacSha256}` " +
|
||||
"ตาม schema `TicketTokenRequest` (คู่ค่าที่ e-Court stamp ไว้ใน custom properties " +
|
||||
"ของไฟล์ .docx) — server ตรวจลายเซ็น HMAC-SHA256 ด้วย env `ADDIN_TICKET_SECRET` " +
|
||||
'(ไม่ตั้ง → env `SECRET` → `"super_secret"`) แล้วออก token จาก claims ที่อยู่ในตัว ticket เอง · ' +
|
||||
"**ticket หมดอายุ** ยังออกให้ต่อเมื่อเอกสารนี้ (`fid`) เคยมี version ที่สร้างโดย `uid` เดียวกัน " +
|
||||
"(ผู้ที่เคยทำงานกับเอกสารเดิมกลับมาใช้ต่อได้แม้ ticket หมดอายุ — ไม่เคยทำงาน = 401)\n\n" +
|
||||
'(ไม่ตั้ง → env `SECRET` → `"super_secret"`) แล้วออก token จาก claims ที่อยู่ในตัว ticket เอง ' +
|
||||
"(contract 2026-11-04: ฟอร์แม็ตพัง/ไม่ครบ = 400 · ลายเซ็นไม่ถูก = 401 · " +
|
||||
"**ลายเซ็นถูกแต่ ticket หมดอายุ = 403** — add-in ที่มี access_token เดิมของ `fid` " +
|
||||
"นี้ใน session ยังใช้ต่อได้ ไม่มี = ขอไฟล์ใหม่จาก e-Court)\n\n" +
|
||||
"ได้ token แล้วแนบเป็น `Authorization: Bearer <token>` กับทุก request ถัดไป",
|
||||
security: [{ ApiKeyAuth: [] }],
|
||||
requestBody: {
|
||||
|
|
@ -893,7 +908,190 @@ export const openApiSpec = {
|
|||
401: {
|
||||
description:
|
||||
"ทางเข้า x-api-key: ไม่ได้ส่ง header หรือค่าไม่ถูกต้อง (env DOCVER_API_KEY) · " +
|
||||
"ทางเข้า ticket: ticket ไม่ถูกต้อง/หมดอายุ หรือไม่ได้ส่งมา (ข้อความเดียวกันทุกสาเหตุ)",
|
||||
"ทางเข้า ticket: ลายเซ็น HMAC ไม่ถูก (ข้อความเดียวกันทุกสาเหตุ)",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: { $ref: "#/components/schemas/Error" },
|
||||
},
|
||||
},
|
||||
},
|
||||
403: {
|
||||
description:
|
||||
"เฉพาะทางเข้า ticket: ลายเซ็นถูกแต่ ticket หมดอายุ — ใช้ access_token เดิมของ " +
|
||||
"fid นี้ใน session ต่อ หรือขอไฟล์ใหม่จาก e-Court (contract 2026-11-04)",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: { $ref: "#/components/schemas/Error" },
|
||||
},
|
||||
},
|
||||
},
|
||||
500: { $ref: "#/components/responses/ServerError" },
|
||||
},
|
||||
},
|
||||
},
|
||||
"/api/auth/session": {
|
||||
post: {
|
||||
tags: ["auth"],
|
||||
summary: "แลก credential ของลิงก์ e-Court เป็น session token ของแอป note (SSO)",
|
||||
description:
|
||||
"ทางเข้า **path สั้น** ของ `POST /api/note/auth/session` — endpoint ก้อนเดียวกัน " +
|
||||
"พฤติกรรมเหมือนกันทุกประการ (เพิ่ม 2026-11-05) · flow SSO ของแอป note " +
|
||||
"(PLAN-SSO.md §3.2 ฉบับ token): ลิงก์ e-Court พา browser มาหน้า `/note` พร้อม " +
|
||||
"credential → client เรียกเส้นนี้แลกเป็น access_token เก็บ localStorage " +
|
||||
'("note-auth") แล้วแนบ `Authorization: Bearer` กับทุก API/Server Action ของแอป\n\n' +
|
||||
"- ส่ง credential **ทางเดียว**: `t` (login-token จาก `POST /api/note/auth/token`) " +
|
||||
"หรือ `ticket_data`+`HmacSha256` (คู่ค่าชุดเดียวกับที่ e-Court stamp ใน custom " +
|
||||
"properties ของไฟล์ .docx ของ add-in) — สองชุดพร้อมกัน = 400 (D12)\n" +
|
||||
"- token ที่ได้เป็นชนิด `purpose=login` อายุ 8 ชม. (28800 วินาที) — ใช้ได้กับแอป " +
|
||||
"note เท่านั้น เอาไปยิง `/api/documents/*` ของกลุ่ม docver ไม่ได้ (401)\n" +
|
||||
"- ส่ง `fileUrl` มาด้วย = ลงทะเบียนเอกสาร N8 แบบ trusted ฝั่ง server ทันที " +
|
||||
"(fid จาก credential ที่ verify แล้ว) — ล้มก็ยังได้ token พร้อม `fileError` " +
|
||||
"ให้หน้าแรกแสดงสาเหตุ · `fileUrl` ต้องผ่าน allowlist ของ N8 " +
|
||||
"(admincourt.go.th + env `EXTERNAL_FILE_HOSTS`) หรือเป็น path `/samples/…`\n" +
|
||||
"- **ทาง ticket ใน production**: secret ต้องตั้งจริง (env `ADDIN_TICKET_SECRET` " +
|
||||
'→ `SECRET`) — ค่า default `"super_secret"` ที่รู้กันทั้งระบบถูกปฏิเสธ (500)',
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: { $ref: "#/components/schemas/SessionExchangeRequest" },
|
||||
examples: {
|
||||
"ทาง JWT (param t ของลิงก์ e-Court)": {
|
||||
value: {
|
||||
t: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwdXJwb3NlIjoibG9naW4iLCJ1c2VyaWQiOiJvb20iLCJ1c2VybmFtZSI6IuC4geC4m+C4tOC5iOC4quC4lOC5iCIsImZpZCI6IkYxMjMifQ.….….…",
|
||||
fileUrl: "https://service.admincourt.go.th/uploads/F123.pdf",
|
||||
typeId: "T12",
|
||||
},
|
||||
},
|
||||
"ทาง ticket (คู่ค่าเดียวกับไฟล์ .docx ของ add-in)": {
|
||||
value: {
|
||||
ticket_data:
|
||||
'{"exp":1793067433,"fid":"T12_FD155_3s-long_ZZZ","tid":"T12","uid":"oom","uname":"สรวิชญ์"}',
|
||||
HmacSha256:
|
||||
"1dc53fbd48410845c895ddb841a8fe4ad93da413126fae9c688202e57f2baaa9",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description:
|
||||
"session token ของแอป note (พร้อม fileId ถ้าลงทะเบียน fileUrl สำเร็จ)",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: { $ref: "#/components/schemas/SessionResponse" },
|
||||
},
|
||||
},
|
||||
},
|
||||
400: { $ref: "#/components/responses/BadRequest" },
|
||||
401: {
|
||||
description:
|
||||
"credential หมดอายุหรือไม่ถูกต้อง — ทาง JWT แยก `reason: expired` (หมดอายุ) กับ " +
|
||||
"`invalid` · ทาง ticket รวมเป็น `invalid` ทั้งลายเซ็นผิดและหมดอายุ",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
allOf: [
|
||||
{ $ref: "#/components/schemas/Error" },
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
reason: {
|
||||
type: "string",
|
||||
enum: ["expired", "invalid"],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
500: { $ref: "#/components/responses/ServerError" },
|
||||
},
|
||||
},
|
||||
},
|
||||
"/api/documents/token": {
|
||||
post: {
|
||||
tags: ["documents"],
|
||||
summary: "ขอ access_token ของกลุ่ม documents (docver)",
|
||||
description:
|
||||
"ออก `access_token` (JWT HS256) ไว้เรียก endpoint อื่นของกลุ่ม documents — " +
|
||||
"token ฝัง claims `{userid, username, fid, template}` อายุตาม env " +
|
||||
"`DOCVER_TOKEN_TTL_SECONDS` (default 604800 วินาที = 7 วัน — token อายุยาวแทน" +
|
||||
"ระบบ refresh/renew ของ add-in)\n\n" +
|
||||
"**ทางเข้า 2 แบบ** — เลือกตามว่าใครเป็นคนเรียก (ดูตัวอย่างใน Request body ได้ทั้งคู่):\n\n" +
|
||||
"1. **ระบบภายนอก (server-to-server)** — แนบ header `x-api-key` (ค่าจาก env " +
|
||||
"`DOCVER_API_KEY`) แล้วส่ง claims ตรง ๆ ใน body ตาม schema `TokenRequest`\n" +
|
||||
"2. **add-in ใน Word** — ไม่ต้องมี `x-api-key` ส่ง body `{ticket_data, HmacSha256}` " +
|
||||
"ตาม schema `TicketTokenRequest` (คู่ค่าที่ e-Court stamp ไว้ใน custom properties " +
|
||||
"ของไฟล์ .docx) — server ตรวจลายเซ็น HMAC-SHA256 ด้วย env `ADDIN_TICKET_SECRET` " +
|
||||
'(ไม่ตั้ง → env `SECRET` → `"super_secret"`) แล้วออก token จาก claims ที่อยู่ในตัว ticket เอง ' +
|
||||
"(contract 2026-11-04: ฟอร์แม็ตพัง/ไม่ครบ = 400 · ลายเซ็นไม่ถูก = 401 · " +
|
||||
"**ลายเซ็นถูกแต่ ticket หมดอายุ = 403** — add-in ที่มี access_token เดิมของ `fid` " +
|
||||
"นี้ใน session ยังใช้ต่อได้ ไม่มี = ขอไฟล์ใหม่จาก e-Court)\n\n" +
|
||||
"ได้ token แล้วแนบเป็น `Authorization: Bearer <token>` กับทุก request ถัดไป",
|
||||
security: [{ ApiKeyAuth: [] }],
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
oneOf: [
|
||||
{ $ref: "#/components/schemas/TokenRequest" },
|
||||
{ $ref: "#/components/schemas/TicketTokenRequest" },
|
||||
],
|
||||
},
|
||||
examples: {
|
||||
"server-to-server ด้วย x-api-key (ครบทุก claim)": {
|
||||
value: {
|
||||
userid: "123",
|
||||
username: "Sorawit Bholsithi",
|
||||
fid: "3",
|
||||
template: "T12",
|
||||
},
|
||||
},
|
||||
"server-to-server ขั้นต่ำ (template เป็นทางเลือก)": {
|
||||
value: { userid: "123", username: "Sorawit Bholsithi", fid: "3" },
|
||||
},
|
||||
"add-in ด้วย ticket จากไฟล์ (ไม่ต้องมี x-api-key)": {
|
||||
value: {
|
||||
ticket_data:
|
||||
'{"exp":1793067433,"fid":"T12_FD155_3s-long_ZZZ","tid":"T12","uid":"oom","uname":"สรวิชญ์"}',
|
||||
HmacSha256:
|
||||
"1dc53fbd48410845c895ddb841a8fe4ad93da413126fae9c688202e57f2baaa9",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: "access_token พร้อมใช้ (แนบเป็น Authorization: Bearer ทุก request ถัดไป)",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: { $ref: "#/components/schemas/TokenResponse" },
|
||||
},
|
||||
},
|
||||
},
|
||||
400: { $ref: "#/components/responses/BadRequest" },
|
||||
401: {
|
||||
description:
|
||||
"ทางเข้า x-api-key: ไม่ได้ส่ง header หรือค่าไม่ถูกต้อง (env DOCVER_API_KEY) · " +
|
||||
"ทางเข้า ticket: ลายเซ็น HMAC ไม่ถูก (ข้อความเดียวกันทุกสาเหตุ)",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: { $ref: "#/components/schemas/Error" },
|
||||
},
|
||||
},
|
||||
},
|
||||
403: {
|
||||
description:
|
||||
"เฉพาะทางเข้า ticket: ลายเซ็นถูกแต่ ticket หมดอายุ — ใช้ access_token เดิมของ " +
|
||||
"fid นี้ใน session ต่อ หรือขอไฟล์ใหม่จาก e-Court (contract 2026-11-04)",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: { $ref: "#/components/schemas/Error" },
|
||||
|
|
@ -1085,7 +1283,7 @@ export const openApiSpec = {
|
|||
"- `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` (เฉพาะเมื่อ " +
|
||||
"`\"super_secret\"` ให้ตรงฝั่ง verify ของ server — ทาง ticket ของ /token) และ `Ed25519` (เฉพาะเมื่อ " +
|
||||
"`PRIVATE_KEY_HEX` ตั้ง) แล้วเขียน custom properties ลง**สำเนาในหน่วยความจำ** " +
|
||||
"ก่อนคืนไฟล์ — object ใน MinIO ไม่ถูกแต่ (non-destructive) และเขียนทับ stamp " +
|
||||
"เดิมของ template ได้\n" +
|
||||
|
|
@ -1268,13 +1466,80 @@ export const openApiSpec = {
|
|||
},
|
||||
TokenResponse: {
|
||||
type: "object",
|
||||
description: "access_token ของกลุ่ม documents (JWT HS256 อายุสั้น)",
|
||||
description: "access_token ของกลุ่ม documents (JWT HS256)",
|
||||
properties: {
|
||||
access_token: { type: "string", description: "JWT พร้อมใช้แนบเป็น Bearer" },
|
||||
token_type: { type: "string", example: "Bearer" },
|
||||
expires_in: {
|
||||
type: "integer",
|
||||
description: "อายุวินาที (env DOCVER_TOKEN_TTL_SECONDS, default 3600)",
|
||||
description: "อายุวินาที (env DOCVER_TOKEN_TTL_SECONDS, default 604800 = 7 วัน)",
|
||||
},
|
||||
},
|
||||
},
|
||||
SessionExchangeRequest: {
|
||||
type: "object",
|
||||
description:
|
||||
"credential ของลิงก์ e-Court ที่จะแลกเป็น session token — ส่งทางเดียว: `t` " +
|
||||
"**หรือ** `ticket_data`+`HmacSha256` (สองชุดพร้อมกัน = 400 ตาม D12) · " +
|
||||
"allowlist 5 field เป๊ะ — ส่ง field อื่น = 400",
|
||||
properties: {
|
||||
t: {
|
||||
type: "string",
|
||||
description:
|
||||
"login-token (JWT purpose=login) จาก POST /api/note/auth/token — ≤ 8192 ตัวอักษร",
|
||||
},
|
||||
ticket_data: {
|
||||
type: "string",
|
||||
description:
|
||||
"JSON string ของ ticket ชุดเดียวกับที่ e-Court stamp ในไฟล์ .docx — " +
|
||||
"≤ 2048 ตัวอักษร (ส่งตรง ๆ ไม่แก้ string — HMAC ผูกกับค่าดิบ)",
|
||||
},
|
||||
HmacSha256: {
|
||||
type: "string",
|
||||
description: "hex 64 ตัว ของ HMAC-SHA256(secret, ticket_data ดิบ) — ≤ 128 ตัวอักษร",
|
||||
},
|
||||
fileUrl: {
|
||||
type: "string",
|
||||
description:
|
||||
"URL เอกสารบน e-Court — ต้องผ่าน allowlist ของ N8 (admincourt.go.th + env " +
|
||||
"EXTERNAL_FILE_HOSTS) · ส่งมา = ลงทะเบียนเอกสารตอนแลก token (≤ 2048 ตัวอักษร)",
|
||||
},
|
||||
typeId: {
|
||||
type: "string",
|
||||
description: "รหัสกลุ่มเอกสารของ e-Court (≤ 200 ตัวอักษร)",
|
||||
},
|
||||
},
|
||||
},
|
||||
SessionResponse: {
|
||||
type: "object",
|
||||
description:
|
||||
"session ของแอป note — client เก็บใน localStorage (\"note-auth\") แล้วแนบ " +
|
||||
"Authorization: Bearer กับทุก API/Server Action ของแอป",
|
||||
properties: {
|
||||
access_token: {
|
||||
type: "string",
|
||||
description: "JWT purpose=login อายุ 8 ชม. — ใช้ได้กับแอป note เท่านั้น",
|
||||
},
|
||||
token_type: { type: "string", example: "Bearer" },
|
||||
expires_in: {
|
||||
type: "integer",
|
||||
description: "อายุวินาที (NOTE_SESSION_TTL = 28800 = 8 ชม.)",
|
||||
example: 28800,
|
||||
},
|
||||
userid: { type: "string", description: "รหัสผู้ใช้จาก credential (u_userid ของ e-Court)" },
|
||||
username: { type: "string", description: "ชื่อแสดงผลจาก credential" },
|
||||
fileId: {
|
||||
type: "string",
|
||||
format: "uuid",
|
||||
description:
|
||||
"มีเมื่อส่ง fileUrl และลงทะเบียนสำเร็จ — id ของเอกสารในระบบนี้ " +
|
||||
"(ใช้เข้าหน้าอ่าน /note/annotate/<fileId>)",
|
||||
},
|
||||
fileError: {
|
||||
type: "string",
|
||||
description:
|
||||
"มีเมื่อลงทะเบียน fileUrl ไม่สำเร็จ (ไม่ผ่าน allowlist ฯลฯ) — token ยังออกให้ " +
|
||||
"หน้าแรกแสดงสาเหตุ",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue