Phase 9: version message (FR-13)
- ใส่คำอธิบายแบบ commit message ได้ทุก flow ที่สร้าง version (Save & Version / Start Versioning / generate จากเว็บ) + แสดงใน version history ทุกหน้า - backend: DocumentVersion.Message (varchar 2048) + migration AddVersionMessage + BadRequest ตรวจความยาวก่อนแตะ MinIO (กัน 500 + orphan object) - add-in: ConfirmVersionDialog เพิ่ม textarea (Start Versioning ใช้ dialog ด้วย) + แสดง message ใน VersionHistoryPanel - web: ฟอร์มสร้างเอกสาร + หน้า detail แสดง message (desktop truncate + tooltip, mobile เต็มบรรทัด) - sync เอกสารทั้งหมด: spec v5 (FR-13/AC-16) + plan Phase 9 + acceptance-review 1–16 + README + CLAUDE.md + web/README - tests: backend 52 / addin 50 / web 36 — เขียวทั้งชุด Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
b47667f918
commit
7b20f12ede
28 changed files with 928 additions and 141 deletions
|
|
@ -1,7 +1,7 @@
|
|||
# Implementation Plan: Word Versioning Add-in (Office.js + .NET 8)
|
||||
|
||||
> แผนงานสร้างระบบจาก spec: [`specs/spec-officejs.md`](../../specs/spec-officejs.md)
|
||||
> สถานะ: **Phase 0–8 เสร็จ** (backend + add-in + web portal + tests ครบชุด + ไล่ AC ครบ — รายละเอียดผล AC ทุกข้อที่ [`docs/acceptance-review.md`](../acceptance-review.md)) · เหลือยืนยันด้วยมือเฉพาะบน platform ที่ทำแทนไม่ได้: Word Online/Windows, click-through บน browser จริง, silent refresh จริง
|
||||
> สถานะ: **Phase 0–9 เสร็จ** (backend + add-in + web portal + tests ครบชุด + ไล่ AC ครบ — รายละเอียดผล AC ทุกข้อที่ [`docs/acceptance-review.md`](../acceptance-review.md)) · เหลือยืนยันด้วยมือเฉพาะบน platform ที่ทำแทนไม่ได้: Word Online/Windows, click-through บน browser จริง, silent refresh จริง
|
||||
> วันที่แผน: 2026-08-18 (ฉบับแก้ไข v2: เพิ่ม FR-9 ถึง FR-11 — ระบบ template, สร้างเอกสาร v1 ผ่านเว็บ และ field sync)
|
||||
|
||||
---
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
- หน้าจอสร้างเอกสารครั้งแรก = **เว็บแยก (standalone)** — กรอกนอก Word → ดาวน์โหลด .docx ที่ backend stamp metadata + สร้าง v1 ไว้แล้ว → เปิดใน Word แล้ว add-in รู้จักทันที
|
||||
- Template = **หลาย template + หน้าจัดการเต็มรูปแบบ** (CRUD + นิยาม field ต่อ template)
|
||||
- Field sync = **เฉพาะ fields จาก template** (ผูกกับ content controls) ไม่เก็บ full text
|
||||
- **FR-9 ถึง FR-12 เป็น requirement ที่เพิ่มภายหลัง spec เดิม** — spec ปัจจุบันเป็นฉบับ v4 (ครอบ FR-1–12 + AC-1–15: v2 เพิ่ม template/portal/field sync, v3 เพิ่มข้อจำกัดแพลตฟอร์มจากการทดสอบจริง, v4 เพิ่มรายการเอกสารต่อ template + detail + re-generate) ให้ถือ spec เป็น source of truth ของ requirements
|
||||
- **FR-9 ถึง FR-13 เป็น requirement ที่เพิ่มภายหลัง spec เดิม** — spec ปัจจุบันเป็นฉบับ v5 (ครอบ FR-1–13 + AC-1–16: v2 เพิ่ม template/portal/field sync, v3 เพิ่มข้อจำกัดแพลตฟอร์มจากการทดสอบจริง, v4 เพิ่มรายการเอกสารต่อ template + detail + re-generate, v5 เพิ่ม commit message ต่อ version) ให้ถือ spec เป็น source of truth ของ requirements
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -501,6 +501,28 @@ POST /api/documents/generate { templateId, values: { <fieldKey>: <value> } }
|
|||
|
||||
---
|
||||
|
||||
## Phase 9: Version message — FR-13 (เพิ่มทีหลัง, v5)
|
||||
|
||||
**เป้า:** ใส่ "คำอธิบาย version" แบบ git commit message ได้ทุก flow ที่สร้าง version (Save & Version, Start Versioning, สร้างจากเว็บ) + แสดงใน version history ทุกหน้า — แผนเต็มที่ [`docs/plans/version-message.md`](version-message.md)
|
||||
|
||||
- [x] Backend: `DocumentVersion.Message` (string?, varchar 2048) + `AppDbContext` config + migration `AddVersionMessage`
|
||||
- [x] Backend: `UploadVersionRequest.Message` (multipart) + `GenerateDocumentRequest.Message` (JSON) + `VersionListItem.Message` + `NormalizeMessage` + BadRequest ตรวจความยาว 2048 ทั้ง upload/generate (กัน 500 + orphan MinIO object)
|
||||
- [x] Add-in: `ConfirmVersionDialog` generalize (`title?/description?/confirmLabel?` + `onConfirm(message)`) + textarea ทางเลือก + เคลียร์ state ตาม `open` · Start Versioning ใช้ dialog ด้วย (ตัวใหม่ใน App.tsx)
|
||||
- [x] Add-in: `versionFlow` (`saveAndVersion`/`startVersioning`/`uploadCurrentFile`) + `versioningService.uploadVersion` ส่ง `message` · `VersionRecord.message` + แสดงใน `VersionHistoryPanel`
|
||||
- [x] Web: ฟอร์ม generate เพิ่ม textarea ทางเลือก + payload `message` · `VersionListItem.message` + แสดงใน history (desktop ใต้ v{N} truncate + tooltip, mobile เต็มบรรทัด)
|
||||
- [x] Tests: `VersionMessageTests` (backend) + `versionFlow.test.ts` เพิ่ม 3 กรณี (แนบ/ว่างไม่แนบ/startVersioning)
|
||||
|
||||
หมายเหตุจากการทำจริง (2026-08-20):
|
||||
- เพิ่ม param เป็น optional positional วางก่อน callback (callback-last) — test เดิมที่เรียก `saveAndVersion(id, 1)` / `startVersioning()` คอมไพล์ผ่านโดยไม่ต้องแก้
|
||||
- `ConfirmVersionDialog` ถูก mount ค้างไว้นอก phase branch ของ App — เคลียร์ textarea ด้วย `useEffect` ตาม `open` ไม่ใช่ตอน unmount
|
||||
- เลือกตรวจความยาว 2048 เป็น BadRequest เอง (ต่างจาก `Template.Description` ที่ปล่อยให้ DB reject) เพราะ Generate จะเกิด 500 **หลัง** MinIO upload แล้ว = orphan object ใน bucket
|
||||
|
||||
**DoD:** `dotnet test` + addin `npm test` + web `npm test`/`npm run build` เขียวทั้งชุด
|
||||
|
||||
> ✅ ตรวจผ่านจริง (2026-08-20): `dotnet test` **52/52** · addin `npm test` **50/50** · web `npm test` **36/36** + build ผ่าน
|
||||
|
||||
---
|
||||
|
||||
## 4. ตาราง mapping: Phase ↔ FR ↔ Acceptance Criteria
|
||||
|
||||
| Phase | FR ที่ implement | Acceptance criteria ที่ตรวจได้ |
|
||||
|
|
@ -515,6 +537,7 @@ POST /api/documents/generate { templateId, values: { <fieldKey>: <value> } }
|
|||
| 6.4 (ทีหลัง, v4) | FR-12 | AC-15 |
|
||||
| 7 | — | คุ้มกัน regression ทุก AC (รวม AC-13, 14) |
|
||||
| 8 | — | ทบทวน AC-1 ถึง AC-14 ทั้งหมด |
|
||||
| 9 (ทีหลัง, v5) | FR-13 | AC-16 |
|
||||
|
||||
**AC เพิ่มเติม (นอก spec เดิม):**
|
||||
- **AC-11:** upload template .docx ที่มี content controls → ระบบ detect fields อัตโนมัติ + บันทึก field definitions ได้
|
||||
|
|
@ -522,6 +545,7 @@ POST /api/documents/generate { templateId, values: { <fieldKey>: <value> } }
|
|||
- **AC-13:** แก้ค่าใน content control ที่ Word แล้วกด Save & Version → field value ใน DB เปลี่ยนตาม + snapshot ต่อ version ถูกเก็บ
|
||||
- **AC-14:** ลบ content control ออกจาก Word แล้วกด Save & Version → flow ยังสำเร็จ ค่าเดิมของ field นั้นคงอยู่ (mark missing) ไม่ error
|
||||
- **AC-15:** (v4) หน้ารายการเอกสารของ template + หน้า detail (ค่าทุก field + version history ขยายเห็นค่าต่อ version + ดาวน์โหลด) + re-generate ได้เอกสารใหม่ v1 โดยเอกสารต้นทางไม่มี version ใหม่ — รายละเอียดตาม FR-12
|
||||
- **AC-16:** (v5) พิมพ์คำอธิบายตอนสร้าง version ได้ทุก flow (Save & Version, Start Versioning, สร้างจากเว็บ) → ข้อความถูกเก็บกับ version นั้นใน DB และแสดงใน version history ทุกหน้า · เว้นว่างได้ — รายละเอียดตาม FR-13
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -554,14 +578,14 @@ docker compose up -d
|
|||
cd backend/WordVersioning.Api
|
||||
dotnet run # รัน + swagger ที่ http://localhost:5xxx
|
||||
dotnet ef migrations add <Name>
|
||||
cd .. && dotnet test # integration tests (42 ตัว) — ต้องมี Docker รันอยู่ (Testcontainers ยก infra เอง ~1 นาที)
|
||||
cd .. && dotnet test # integration tests (52 ตัว) — ต้องมี Docker รันอยู่ (Testcontainers ยก infra เอง ~1 นาที)
|
||||
|
||||
# add-in (https://localhost:3000)
|
||||
cd addin
|
||||
npm install
|
||||
npm run build # webpack build
|
||||
npm start # dev server — sideload ผ่าน manifest นี้
|
||||
npm test # jest (47 ตัว)
|
||||
npm test # jest (50 ตัว)
|
||||
npx office-addin-dev-certs install # ครั้งแรกครั้งเดียว เพื่อให้ https localhost ใช้ได้
|
||||
|
||||
# web portal (http://localhost:5173 — ห้ามใช้ 3000 เพราะชน add-in)
|
||||
|
|
|
|||
97
docs/plans/version-message.md
Normal file
97
docs/plans/version-message.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# Version Message (commit message) — FR-13 / AC-16 / Spec v5
|
||||
|
||||
## Context
|
||||
|
||||
ผู้ใช้ต้องการให้ใส่ "ข้อความอธิบาย" ตอนสร้าง version ใหม่ได้ เหมือน git commit message — เก็บกับแต่ละ version และแสดงใน version history ทุกหน้า ขอบเขต (ยืนยันกับผู้ใช้แล้ว): **ทุก flow ที่สร้าง version** = add-in Save & Version + add-in Start Versioning (เพิ่ม dialog ใหม่) + ฟอร์ม generate บน web
|
||||
|
||||
**ข้อตกลง fixed:**
|
||||
- Field ชื่อ `message` — nullable string, max 2048, normalize `IsNullOrWhiteSpace → null` + `.Trim()` (นโยบายเดียวกับ `Template.Description` เป๊ะ)
|
||||
- Optional ทุกที่ ไม่บังคับกรอก
|
||||
- **Non-goal: ไม่ฝังลง docx** (custom properties / Custom XML part) — backend คือ source of truth (กติกา #5) และเลี่ยง parse-compat กับไฟล์เก่า (`XmlVersionEntry` ไม่แตะ)
|
||||
- ตามกติกา repo: **แก้ spec ก่อน** แล้ว sync plan
|
||||
|
||||
## ขั้นที่ 0 — บันทึกแผน + แก้เอกสาร requirement ก่อน
|
||||
|
||||
1. บันทึกแผนนี้ที่ `docs/plans/version-message.md` (ธรรมเนียมเดิม)
|
||||
2. **[specs/spec-officejs.md](specs/spec-officejs.md)**: เพิ่ม changelog v5 บรรทัดบนสุด · `### FR-13: คำอธิบายต่อ version — commit message (เพิ่มเติม v5)` ต่อท้าย section 6 (หลัง FR-12) ตาม format เดิม — ระบุ field `message` + ทั้ง 2 endpoint + นโยบาย null/trim + แสดงผลทุก history + Start Versioning ได้ dialog · section 7 `DocumentVersion` POCO เพิ่ม `public string? Message { get; set; }` · section 10 เพิ่ม AC-16 (v5) · section 11 เพิ่ม task items `(v5)` ทั้ง 3 list
|
||||
3. **[docs/plans/officejs-implementation-plan.md](docs/plans/officejs-implementation-plan.md)**: เพิ่ม `## Phase 9: Version message — FR-13 (เพิ่มทีหลัง, v5)` + checklist + แถวตาราง mapping `| 9 (v5) | FR-13 | AC-16 |`
|
||||
4. **[docs/acceptance-review.md](docs/acceptance-review.md)**: 1–15 → 1–16 + section AC-16 (🔶 ส่วน dialog ใน Word ต้องยืนยันมือ)
|
||||
|
||||
## ขั้นที่ 1 — Backend (`backend/WordVersioning.Api`)
|
||||
|
||||
1. [Models/DocumentVersion.cs](backend/WordVersioning.Api/Models/DocumentVersion.cs): `public string? Message { get; set; }` (+ doc comment FR-13)
|
||||
2. [Data/AppDbContext.cs](backend/WordVersioning.Api/Data/AppDbContext.cs): ใน block DocumentVersion เพิ่ม `entity.Property(x => x.Message).HasMaxLength(2048);` (มิเรอร์ Template.Description)
|
||||
3. Migration: `dotnet ef migrations add AddVersionMessage` → expect `AddColumn<string>("Message", "DocumentVersions", nullable, maxLength 2048)` (tests รัน MigrateAsync อยู่แล้ว = migration ถูก exercise)
|
||||
4. [Models/VersionDtos.cs](backend/WordVersioning.Api/Models/VersionDtos.cs): `UploadVersionRequest.Message` (string? หลัง Fields) · `GenerateDocumentRequest.Message` (string? หลัง Values) · `VersionListItem` เพิ่ม `string? Message` ท้าย record
|
||||
5. [Controllers/DocumentsController.cs](backend/WordVersioning.Api/Controllers/DocumentsController.cs):
|
||||
- เพิ่ม `MaxVersionMessageLength = 2048` + `NormalizeMessage()` helper (static private — มี pattern `ParseSnapshot`/`IsUniqueViolation` อยู่แล้ว)
|
||||
- **ตัดสินใจ: ใส่ BadRequest check ความยาว** (ต่างจาก Template.Description ที่ไม่มี) เพราะ: ถ้าไม่เช็ค = 500 จาก DB และใน Generate จะเกิด 500 **หลัง** MinIO upload แล้ว = orphan object ใน bucket โดยเปล่า + UploadVersion เป็น action ที่ validate เองด้วยข้อความไทยอยู่แล้ว
|
||||
- UploadVersion: normalize + check หลัง validation ของ fields → `Message = message` ใน `new DocumentVersion` ใน retry loop (ทุกรอบได้ค่าเดียวกัน)
|
||||
- Generate: normalize + check **ก่อน** ทำ MinIO/template IO → `Message = message` ใน v1 initializer
|
||||
- GetVersions: เพิ่ม `v.Message` ใน projection + `, r.Message` ตอน construct `VersionListItem`
|
||||
- Rollback path ไม่ต้องแตะเพิ่ม (MinIO fail → Remove ทั้ง row อยู่แล้ว / Generate detach ก่อน SaveChanges)
|
||||
|
||||
## ขั้นที่ 2 — Add-in (`addin`) — Fluent UI v9
|
||||
|
||||
1. [ConfirmVersionDialog.tsx](addin/src/taskpane/components/ConfirmVersionDialog.tsx) — generalize ด้วย optional props (ไม่สร้าง component ใหม่): `title?`, `description?`, `confirmLabel?` + **`onConfirm: (message: string) => void`**; เพิ่ม `Field`+`Textarea` (label "คำอธิบาย version (ไม่บังคับ)", placeholder "เช่น แก้ไขข้อ 3 สัญญาจ้าง", maxLength 2048, rows 3, resize vertical, disabled={busy}); local state `message` + **`useEffect` เคลียร์เมื่อ `!open`** (FC ถูก mount ค้างไว้ — ห้ามพึ่ง remount)
|
||||
2. [versionFlow.ts](addin/src/services/versionFlow.ts) — optional positional param วางก่อน callback (callback-last): `uploadCurrentFile(documentId, clientVersionId, fields, message?)` · `startVersioning(message?, onProgress?)` · `saveAndVersion(documentId, latestVersionNumber, message?, onProgress?)` — test เดิม 5 ตัวเรียก 2 args / 0 args คอมไพล์ผ่านไม่ต้องแก้
|
||||
3. [versioningService.ts](addin/src/services/versioningService.ts) `uploadVersion` — เพิ่ม `message?` ท้าย signature + `const trimmed = message?.trim(); if (trimmed) form.append("message", trimmed)` (มิเรอร์ guard ของ fields)
|
||||
4. [versionRecord.ts](addin/src/models/versionRecord.ts) — `VersionRecord` เพิ่ม `message: string | null`
|
||||
5. [VersionHistoryPanel.tsx](addin/src/taskpane/components/VersionHistoryPanel.tsx) — แสดง `version.message` ใต้บรรทัด "โดย …" (แบบเต็ม, `pre-wrap`, muted เล็ก) — เพิ่ม style `messageRow`
|
||||
6. [App.tsx](addin/src/taskpane/components/App.tsx) — `handleSaveAndVersion(message)` / `handleStartVersioning(message)` ส่งต่อ; state `startConfirmOpen`; ปุ่ม Start Versioning เปลี่ยนเป็นเปิด dialog; render `ConfirmVersionDialog` ตัวที่สอง (title "เริ่มติดตามเอกสารนี้?", confirmLabel "เริ่มติดตาม (version 1)")
|
||||
|
||||
## ขั้นที่ 3 — Web (`web`)
|
||||
|
||||
1. [documents/create/[templateId].vue](web/app/pages/documents/create/[templateId].vue) — `const message = ref('')`; textarea ทางเลือก (`label`/`input` class, rows 2, maxlength 2048) หลัง field loop; payload เพิ่ม `message: message.value.trim() || null`; `resetForm` เคลียร์; **re-generate ไม่ prefill message** (เอกสารใหม่ได้ข้อความใหม่ — ใส่ comment กำกับ)
|
||||
2. [types/api.ts](web/app/types/api.ts) — `VersionListItem` เพิ่ม `message: string | null`
|
||||
3. [documents/[documentId].vue](web/app/pages/documents/[documentId].vue) — **ไม่เพิ่มคอลัมน์ใหม่** (colspan="4" ใน expanded row + คอลัมน์ action จะบีบ): desktop แสดงใต้ `v{N}` เป็น `truncate text-xs text-muted` + `:title` tooltip; mobile card แสดงเต็ม `break-words`
|
||||
|
||||
## ขั้นที่ 4 — Tests
|
||||
|
||||
**Backend — ไฟล์ใหม่ `VersionMessageTests.cs`** (ตาม pattern `UploadVersionTests` — `VersionForm`, `fixture.CreateDb()`, `AsNoTracking`):
|
||||
1. `Upload_WithMessage_PersistsRow_AndEchoesInHistory`
|
||||
2. `[Theory] Upload_BlankOrMissingMessage_StoredAsNull` (null / "" / " ")
|
||||
3. `Upload_TrimsSurroundingWhitespace`
|
||||
4. `Upload_OversizeMessage_Returns400_NoSideEffect` (2049 ตัว, ไม่มี row หลงเหลือ)
|
||||
5. `Upload_MessageExactly2048_Succeeds` (boundary)
|
||||
6. `SecondUpload_KeepsPerVersionMessages` (v1=A, v2=B → history [B,A])
|
||||
7. `Generate_WithMessage_CreatesV1WithMessage`
|
||||
8. `Generate_OversizeMessage_Returns400` (เช็คว่า 400 เกิดก่อน MinIO)
|
||||
|
||||
แก้ helper: `TestDtos.cs` — `VersionItem` เพิ่ม `string? Message`, `VersionForm(..., string? message = null)`; `TestFlow.GenerateDocumentAsync(..., string? message = null)`
|
||||
|
||||
**Add-in — `versionFlow.test.ts`**: เพิ่ม 3 test — `form.get("message")` หลัง `saveAndVersion(id, 1, "…")`, whitespace → null, `startVersioning("…")` แนบ v1 (test เดิมไม่ต้องแก้)
|
||||
|
||||
**Web**: type-only — ไม่มี component test ตาม convention (เช็คด้วย build)
|
||||
|
||||
## Verification
|
||||
|
||||
```
|
||||
# ลำดับ: docs → backend → add-in → web
|
||||
cd backend/WordVersioning.Api && dotnet ef migrations add AddVersionMessage
|
||||
cd backend && dotnet test --filter VersionMessageTests # ต้องมี Docker (Testcontainers)
|
||||
cd backend && dotnet test # ทั้งชุด
|
||||
cd addin && npm run build && npm test
|
||||
cd web && npm run build && npm test
|
||||
```
|
||||
|
||||
Manual E2E (หลัง `docker compose up -d` + backend + `npm run dev`/`npm start`):
|
||||
1. Web generate พร้อม message → หน้า detail แสดงใต้ v1 (desktop + mobile card); ไม่กรอก → ไม่แสดง
|
||||
2. Re-generate จากเอกสารที่มี message → textarea ว่าง
|
||||
3. Add-in: untracked → Start Versioning เปิด dialog → พิมพ์ message → v1 + panel แสดง
|
||||
4. Add-in: Save & Version พร้อม message → history refresh แสดง
|
||||
5. เปิด dialog → พิมพ์ → ยกเลิก → เปิดใหม่ → textarea ต้องว่าง
|
||||
6. Word sideload caveat: ห้าม `cp` ทับ manifest ใน wef (symlink), kill dev server เก่าก่อน `npm start`
|
||||
|
||||
## Risks / gotchas
|
||||
|
||||
- **Param เพิ่มท้าย + callback-last** = test เดิมคอมไพล์ผ่าน (verify แล้วว่าเรียก 2/0 args)
|
||||
- **เคลียร์ dialog state ด้วย useEffect ตาม `open`** — อย่าพึ่ง unmount
|
||||
- Postgres varchar นับเป็น characters (ไทย 3 bytes/char ไม่มีปัญหา); JS maxLength กับ C# `.Length` นับ UTF-16 code units เหมือนกัน
|
||||
- `GenerateDocumentRequest.Message` เป็น plain string — JSON ส่ง type ผิดได้ 400 อัตโนมัติจาก [ApiController] (body อังกฤษ — ยอมรับได้)
|
||||
- AC-16 ส่วน dialog/textarea ใน Word webview ต้องยืนยันมือ (🔶 ใน acceptance-review)
|
||||
- อย่าลืมอัปเดตตัวเลข test count ใน docs (47/42/36) หลังรันจริง
|
||||
|
||||
## สถานะ: ✅ implement เสร็จ (2026-08-20)
|
||||
|
||||
ผลรันจริงทั้งชุด: backend `dotnet test` **52/52** · addin `npm test` **50/50** + build + lint + manifest validate ผ่าน · web `npm test` **36/36** + build ผ่าน — รายละเอียด checkbox Phase 9 + หมายเหตุจากการทำจริงอยู่ที่ [officejs-implementation-plan.md](officejs-implementation-plan.md#phase-9-version-message--fr-13-เพิ่มทีหลัง-v5) · ผล AC-16 ที่ [acceptance-review.md](../acceptance-review.md) · เหลือยืนยันด้วยมือเฉพาะ dialog/textarea ใน Word จริง
|
||||
|
|
@ -186,3 +186,9 @@ Desktop เป็นตารางปกติ (`hidden md:block table-card`)
|
|||
- Dark ครีม→เทาอุ่น: saturation เกิน ~15% จะเลี่ยน — ค่าที่เลือก desaturate แล้ว; shadow มองไม่เห็นบนพื้นดำ (border token เป็นตัวแบ่ง elevation ใน dark)
|
||||
- ตารางครีมที่ text-sm อาจแน่น — fallback บรรทัดเดียว: `table-card` → `bg-surface`
|
||||
- ลำดับสำคัญ: tokens/config → component classes → .vue edits
|
||||
|
||||
## หมายเหตุจากการทำจริง (2026-08-20)
|
||||
|
||||
- ✅ **implement ครบทั้ง 12 ไฟล์ + verification ผ่านทั้งหมด** — web `npm test` 36/36 เขียวทั้งก่อน/หลัง · `npm run build` ผ่าน · smoke test production server ยืนยัน fonts link, `lang="th"`, sticky header + token classes, FOUC script ครบ · audit grep palette เดิม (`slate/sky/red/emerald/amber-*`) = **0 เหลือ** · `dark:` variants (เดิม 209 จุด) = **0 เหลือ**
|
||||
- 🐛 **บั๊กแฝงที่เจอระหว่างทำ (สำคัญ):** `@nuxtjs/tailwindcss` resolve default cssPath แบบ relative ต่อ rootDir → บน Nuxt 4 (srcDir = `app/`) หา `app/assets/css/tailwind.css` ไม่เจอและ **fallback ไปไฟล์ default ของ tailwindcss package เงียบๆ** (build ผ่าน แต่ token/component classes หายทั้งหมด) — ก่อนหน้านี้ไม่มีใครเจอเพราะไฟล์เดิมมีเนื้อหา 3 directives เหมือน fallback เป๊ะ · แก้ด้วย `tailwindcss: { cssPath: '~/assets/css/tailwind.css' }` ใน nuxt.config.ts (บันทึกเป็นกติกา #14 ใน CLAUDE.md แล้ว)
|
||||
- smoke test เครื่องมือ: `PORT=5174 node .output/server/index.mjs` + curl ตรวจ HTML — ใช้ซ้ำได้เมื่อแก้ shell/global
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue