การทดสอบ 6 รอบบนเครื่องจริง (Mac, Word 16.101) พิสูจน์ว่า ms-word:ofe
ถูกเมินแบบไม่ deterministic ทุกรูปแบบ (http/https/query/ไม่มี query/
file:// — Word ไม่ยิง request ถึง server เลย เด้งหน้าเลือกไฟล์แทน)
open -a Word <local file> ใช้ได้แต่เรียกจากเว็บไม่ได้ (sandbox +
backend รัน server กลางใน production) → สรุปทางเดียวที่ deterministic
คือ download-first
- Backend: OpenLinkService (HMAC อายุสั้น ValidateOnStart) +
OpenController /api/open/{t}/{e}/v/{did}/{vid}/file.docx และ /d/{objectKey}
— ทุกอย่างอยู่ใน path ไม่มี query string (Word เมิน URL มี query),
[AllowAnonymous] ด้วยลายเซ็นแทน Bearer, stream จาก MinIO + disposition
ชื่อไทยเหมือนเดิม · download-link + generate-draft ออก open-link
แทน presigned ของ MinIO (http) · ลบ dead code presigned ทิ้ง
- Web: openDocxUrl = ดาวน์โหลดทันทีทุกครั้ง + ยิง ms-word ควบคู่แบบ
best-effort + notice "ไฟล์อยู่ Downloads" — เอา heuristic สลับแอป
ออก (โดนหน้าเลือกไฟล์ของ Word หลอกจนไม่ดาวน์โหลด)
- Spec v9.2 + ตารางทดสอบเครื่องจริงใน acceptance-review + CLAUDE.md
กฎ 13 (ms-word = best-effort เท่านั้น) + ทางเลือก helper อนาคต
- backend 86 / web 58 / add-in 66 + build ครบ; QA reviewer PASS
(1 round, minors 4 แก้ครบ)
หมายเหตุ deploy: ต้องตั้ง OpenLinks__Secret (ค่าลับจริง) และ
OpenLinks__BaseUrl (https domain ของ backend) — fail ดังตั้งแต่สตาร์ทถ้าไม่ตั้ง
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| app | ||
| public | ||
| test | ||
| .env.example | ||
| .gitignore | ||
| nuxt.config.ts | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tailwind.config.ts | ||
| tsconfig.json | ||
| vitest.config.ts | ||
Web Portal — e-Court Documents Versioning
หน้าเว็บสำหรับจัดการ template + สร้างเอกสารจาก template (ได้ .docx ที่เป็น version 1 อัตโนมัติ) + ดูรายการเอกสาร/detail + re-generate — เป็นส่วนหนึ่งของ monorepo หลัก (ดู ../README.md สำหรับภาพรวมทั้งระบบ)
สั่งรัน
npm install
npm run dev # http://localhost:5173 (ห้ามใช้ 3000 — ชนกับ add-in dev server)
npm test # Vitest — 46 ตัว
npm run build # production build (.output/)
ต้องรัน infra + backend ก่อน (docker compose + dotnet run ที่ backend) — login ผ่าน Keycloak ด้วย test user testuser / Test1234!
โครงสร้าง
app/
app.vue # shell: sticky header + navbar + skip link
assets/css/tailwind.css # design tokens (CSS variables) + @layer components (.btn/.input/.card/…)
composables/ # useAuth (PKCE), useApi (Bearer + refresh), useTheme (light/dark)
pages/ # ทุกหน้า: หน้าหลัก / templates (list/new/edit/documents) / documents (create/detail) / auth/callback
types/api.ts # DTO mirror ของ backend
utils/ # oidc, fieldValidation, fieldEditor, snapshot — pure functions ไว้ unit test
test/ # Vitest (happy-dom) — fieldValidation / fieldEditor / useTheme / snapshot
tailwind.config.ts # สี/fontSize/radius/shadow expose จาก CSS variables (rgb(var(--c-x) / <alpha-value>))
Design system + responsive
- สี/ฟอนต์/radius/shadow เป็น token ทั้งหมด — CSS variables (
:root+.dark) ในapp/assets/css/tailwind.css, derive จาก scheme ของ admincourt.go.th (primary#0000EE, elevated ครีม#FBF7EC, ฟอนต์ Sukhumvit Set → Sarabun ผ่าน Google Fonts) · dark mode พลิกที่ตัวแปร ไม่ใช้dark:utility คู่ - Component classes กลาง —
.btn*/.input/.label/.card/.table-card/.badge*/.alert*/.spinnerใน@layer components - Responsive ทุกหน้า — ตารางทุกตัว dual-render (desktop ตาราง / ต่ำกว่า
mdเป็น card list), page header stack บนมือถือ, ฟอร์ม action rowflex-col-reverse → sm:flex-row
⚠️ กติกาสำคัญ:
- แก้
tailwind.config.tsแล้วต้อง restart dev server ทุกครั้ง - CSS variables ต้องเป็น RGB triplet เว้นวรรค (
0 0 238) — ใส่ hex จะ break/opacityutilities เงียบๆ - ต้องระบุ
tailwindcss.cssPath: '~/assets/css/tailwind.css'ในnuxt.config.ts(default resolve ผิดบน Nuxt 4 → fallback ไปไฟล์ default ของ tailwindcss package แบบเงียบ — ดูกติกา #14 ของ CLAUDE.md หลัก) - Token เก็บใน memory เท่านั้น — persist ได้เฉพาะ theme (localStorage) + refresh token/PKCE verifier (sessionStorage อายุสั้น)
Config
ค่า default ชี้ dev ในพื้นที่ override ผ่าน env ได้ทั้งหมด (ดู .env.example): NUXT_PUBLIC_API_BASE_URL, NUXT_PUBLIC_KEYCLOAK_AUTHORITY, NUXT_PUBLIC_KEYCLOAK_CLIENT_ID