Phase 10: field editor (FR-14)

เพิ่ม editor ต่อ template field — ผู้ดูแลเลือกรูปแบบช่องกรอกในฟอร์มสร้างเอกสารได้:
text → textbox/textarea, number/date → control ตาม type (presentation metadata
ล้วน — validation ยังยึด Type, ค่า field เป็น string ทั้ง flow, ไม่แตะ generate/sync/add-in)

- Backend: TemplateField.Editor (nullable, null = default ของ type) +
  migration AddTemplateFieldEditor + validate ตาม type ใน PUT templates
  (ค่าไม่รู้จัก/ไม่เข้ากับ type → 400, normalize-on-write, API คืน resolved เสมอ)
- Web: util fieldEditor.ts + editor select หน้าแก้ template (desktop+mobile,
  ซ่อนเมื่อ type มีทางเดียว) + ฟอร์มสร้างเอกสาร render ตาม editor +
  แก้ prefill re-generate ของ field date จาก ISO timestamp เต็ม (input[type=date]
  รับเฉพาะ yyyy-MM-dd เดิมแสดงว่าง)
- Docs: spec v6 (FR-14/AC-17) + plan Phase 10 + sub-plan field-editor.md +
  acceptance-review AC-17 + README/CLAUDE.md
- Tests: backend 60/60 (FieldEditorTests ใหม่ 8 กรณี) · web 46/46 + build ผ่าน

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Suphonchai Phoonsawat 2026-08-22 09:17:15 +07:00
parent 7b20f12ede
commit 9bb4a48c00
23 changed files with 865 additions and 45 deletions

View file

@ -1,10 +1,10 @@
# ตรวจ Acceptance Criteria 1–16 (Phase 8 + 9)
# ตรวจ Acceptance Criteria 1–17 (Phase 8 + 9 + 10)
> วันที่ตรวจ: 2026-08-20 · อ้างอิง AC จาก [`specs/spec-officejs.md`](../specs/spec-officejs.md) ส่วน 10
> วันที่ตรวจ: 2026-08-20 (AC 1–16) · 2026-08-22 (AC-17) · อ้างอิง AC จาก [`specs/spec-officejs.md`](../specs/spec-officejs.md) ส่วน 10
>
> สัญลักษณ์: ✅ ผ่าน (มี automated test คุ้ม) · 🖐️ ผ่านจากการทดสอบด้วยมือ · 🔶 ผ่านบางส่วน/รอยืนยันด้วยมือบน platform ที่เหลือ · ❌ ไม่ผ่าน
สรุปรวม: **AC ทั้ง 16 ข้อผ่านในระดับที่ตรวจอัตโนมัติได้ครบ** (backend ครอบทุก flow ด้วย integration tests บน PostgreSQL + MinIO + Keycloak จริงผ่าน Testcontainers) — ส่วนที่เหลือคือการยืนยันด้วยมือบน browser/Word จริง (โดยเฉพาะ Word Online + Windows) ตามรายการท้ายเอกสาร
สรุปรวม: **AC ทั้ง 17 ข้อผ่านในระดับที่ตรวจอัตโนมัติได้ครบ** (backend ครอบทุก flow ด้วย integration tests บน PostgreSQL + MinIO + Keycloak จริงผ่าน Testcontainers) — ส่วนที่เหลือคือการยืนยันด้วยมือบน browser/Word จริง (โดยเฉพาะ Word Online + Windows) ตามรายการท้ายเอกสาร
## ผลทีละข้อ
@ -71,13 +71,18 @@
- ✅ Web: `VersionListItem.message` + build ผ่าน (type-only ตาม convention ไม่มี component test)
- 🔶 dialog + textarea ใน task pane (Save & Version / Start Versioning) และการแสดงใน `VersionHistoryPanel` ต้องยืนยันด้วยมือบน Word จริง
### AC-17 — (v6) admin เลือก editor ต่อ field ได้ (text → textbox/textarea) → ฟอร์มสร้างเอกสารใช้ control ตาม editor · number/date ใช้ control ตาม type · editor ผิด → 400 · ไม่ส่ง → default — ✅ (backend + web unit) + 🔶 (browser รอมือ)
- ✅ `FieldEditorTests` (backend): PUT editor=textarea → persist + echo · ไม่ส่ง → resolve default ตาม type + DB เก็บ null · ส่งค่า = default → normalize เป็น null · editor ไม่รู้จัก → 400 · ไม่เข้ากับ type (3 คู่) → 400 · tag ใหม่จาก replace ได้ default
- ✅ `fieldEditor.spec.ts` (web): `defaultEditor`/`resolveEditor`/`editorOptions`/`dateInputValue` (prefill re-generate ของ field date จาก timestamp เต็ม)
- 🔶 Click-through บน browser: admin editor select (desktop + mobile) · ฟอร์มสร้างเอกสาร render textarea/number/date ตาม editor
## ชุด test ที่คุ้ม AC (สรุป)
| ชุด | จำนวน | ครอบ |
|---|---|---|
| backend integration (Testcontainers: Postgres + MinIO + Keycloak จริง) | 52 | AC-3, 5, 6, 7 (backend), 8, 11–16 |
| backend integration (Testcontainers: Postgres + MinIO + Keycloak จริง) | 60 | AC-3, 5, 6, 7 (backend), 8, 11–17 |
| addin unit (Jest) | 50 | AC-2, 4, 7 (client flow), 9, 10, 16 (ส่วน form) |
| web unit (Vitest) | 36 | AC-11/12 (validation ฝั่งฟอร์ม), theme, snapshot rendering |
| web unit (Vitest) | 46 | AC-11/12 (validation ฝั่งฟอร์ม), theme, snapshot rendering, AC-17 (ส่วน editor util) |
## ปัญหาที่เจอระหว่างไล่ AC (และการแก้)
@ -97,3 +102,4 @@
- [ ] Click-through บน browser: สร้าง/แก้ template → สร้างเอกสาร → ดาวน์โหลด → เปิดใน Word ยืนยัน add-in เห็น v1 ทันที (AC-11, 12) + ดาวน์โหลด version ผ่าน presigned link บน Mac อีกครั้ง (AC-8)
- [ ] Theme toggle จำค่าหลัง reload บน browser จริง (Phase 6 DoD ที่เหลือ)
- [ ] (v5) ใน Word จริง: textarea ใน dialog ของทั้ง Save & Version และ Start Versioning + ข้อความโชว์ใน `VersionHistoryPanel` (AC-16) · และบน browser: ฟอร์มสร้างเอกสารพร้อม message + แสดงใน history ทั้ง desktop/mobille
- [ ] (v6) บน browser: หน้าแก้ template เลือก editor `textarea` (desktop + mobile) · ฟอร์มสร้างเอกสาร render textarea/ช่องตัวเลข/date picker ตาม editor · re-generate เอกสารที่ field date เก็บ timestamp เต็มแล้วช่อง date แสดงวันที่ถูกต้อง (AC-17)

View file

@ -0,0 +1,83 @@
# Field Editor — FR-14 / AC-17 / Spec v6
## Context
ฟอร์มสร้างเอกสารบนเว็บ (FR-10) render ทุก field เป็น `<input>` บรรทัดเดียว — field ข้อความยาว (เช่น รายละเอียดคดี, ที่อยู่) กรอกในช่องแคบไม่สะดวก ผู้ใช้ต้องการให้ผู้ดูแลเลือก **editor (รูปแบบช่องกรอก) ต่อ field** ได้ ขอบเขต (ยืนยันกับผู้ใช้แล้ว): **ไม่เพิ่ม dropdown/checkbox** — แค่:
- `text` → `textbox` (default) หรือ `textarea`
- `number` → `number` (ช่องตัวเลข — ทางเดียว)
- `date` → `date` (date picker — ทางเดียว)
**ข้อตกลง fixed:**
- `Editor` เป็น **presentation metadata แยกจาก `Type`** — validation ของค่า field (generate/sync) ยึด `Type` เท่านั้น ค่า field เป็น string ทั้ง flow (กติกา #5/#6)
- คอลัมน์ **nullable ไม่ backfill** — `null` = "default ของ Type" (มิเรอร์ pattern `AddVersionMessage`) ทำให้ path auto-detect (POST create / PUT file) ไม่ต้องแต่
- **Normalize-on-write**: ค่าที่ resolve แล้วเท่ากับ default → เก็บ `null` (DB ไม่มีค่า default ซ้ำซ้อน อนาคตเปลี่ยน default มีผลทุก row) · API คืนค่า resolved เสมอ
- UI admin **ซ่อน select เมื่อ type มี editor ทางเดียว** (แสดง `—` muted แทน select หลอก) — backend ยัง validate ค่า `number`/`date` ให้ (round-trip ปลอดภัย)
- **Non-goal:** ไม่แตะ add-in (ไม่มี UI แก้ค่า field) · ไม่แตะ `DocumentFieldItem`/หน้า detail (display-only) · ไม่แตะ docx/generate path
- ตามกติกา repo: **แก้ spec ก่อน** แล้ว sync plan
## ขั้นที่ 0 — บันทึกแผน + แก้เอกสาร requirement ก่อน
1. บันทึกแผนนี้ที่ `docs/plans/field-editor.md` (ธรรมเนียมเดิม)
2. **[specs/spec-officejs.md](../../specs/spec-officejs.md)**: changelog v6 บรรทัดบนสุด · FR-9 bullet admin config เพิ่ม `editor (FR-14)` · `### FR-14: Field editor` หลัง FR-13 · section 7 `TemplateField` POCO เพิ่ม `public string? Editor { get; set; }` · section 10 เพิ่ม AC-17 (v6) · section 11 เพิ่ม task items `(v6)` ทั้ง backend + web list
3. **[docs/plans/officejs-implementation-plan.md](officejs-implementation-plan.md)**: header ข้อตกลง v5→v6 · `## Phase 10: Field editor — FR-14 (เพิ่มทีหลัง, v6)` + checklist + แถว mapping `| 10 (ทีหลัง, v6) | FR-14 | AC-17 |` + AC-17 ในรายการ AC เพิ่มเติม
4. **[docs/acceptance-review.md](../acceptance-review.md)**: "AC ทั้ง 16 ข้อ" → 17 + section AC-17 (🔶 browser click-through)
## ขั้นที่ 1 — Backend (`backend/WordVersioning.Api`)
1. [Models/TemplateField.cs](../../backend/WordVersioning.Api/Models/TemplateField.cs): `public string? Editor { get; set; }` หลัง `Type` + static `EditorsByType` (`text → [textbox, textarea]`, `number → [number]`, `date → [date]`) + `DefaultEditor(type)` (unknown type → `"textbox"`)
2. [Data/AppDbContext.cs](../../backend/WordVersioning.Api/Data/AppDbContext.cs): ใน block TemplateField เพิ่ม `entity.Property(x => x.Editor).HasMaxLength(16);` (มิเรอร์ Type)
3. Migration: `dotnet ef migrations add AddTemplateFieldEditor` → expect `AddColumn<string>("Editor", "TemplateFields", nullable, maxLength 16)` เดี่ยว ไม่ backfill (pattern เดียวกับ `AddVersionMessage`)
4. [Models/TemplateDtos.cs](../../backend/WordVersioning.Api/Models/TemplateDtos.cs): `TemplateFieldDefinition.Editor` (string? หลัง Type — ไม่ส่ง/ว่าง = default) · `TemplateFieldDto` แทรก `string Editor` หลัง `Type` (คืนค่า resolved เสมอ)
5. [Controllers/TemplatesController.cs](../../backend/WordVersioning.Api/Controllers/TemplatesController.cs):
- `Update` field loop หลัง type check: resolve null/whitespace → `DefaultEditor(def.Type)` · ไม่อยู่ใน `EditorsByType[def.Type]` → 400 ข้อความไทย (ครอบทั้งค่าไม่รู้จักและไม่เข้ากับ type) · persist normalize-on-write: `row.Editor = editor == DefaultEditor(def.Type) ? null : editor`
- `Create`/`ReplaceFile`: **ไม่แตะ** (Editor null = default ถูกต้องอยู่แล้ว)
- `FieldDtos`: `Editor = f.Editor ?? TemplateField.DefaultEditor(f.Type)` (จุด resolve เดียว)
6. **ไม่แตะ** `DocumentsController` (validation ยึด Type), `VersionDtos.cs`, docx path, add-in
## ขั้นที่ 2 — Web (`web`)
1. [types/api.ts](../../web/app/types/api.ts): `export type FieldEditor = 'textbox' | 'textarea' | 'number' | 'date'` · `TemplateFieldDto` เพิ่ม `editor: FieldEditor | string` หลัง `type` (string-tolerant เหมือน `type`)
2. **สร้าง `app/utils/fieldEditor.ts`** (pure util auto-import เหมือน `fieldValidation`): `EDITORS_BY_TYPE` · `defaultEditor(type)` · `editorOptions(type)` (text = 2 ตัว, number/date = 1 ตัว) · `resolveEditor(field)` (valid-for-type → ตัวมันเอง, null/unknown/incompatible → default — degrade อ่อนโยน) · `dateInputValue(value)` (ISO timestamp → `yyyy-MM-dd` 10 หลักแรก, อื่นๆ คงเดิม)
3. [templates/[id]/edit.vue](../../web/app/pages/templates/[id]/edit.vue): payload mapping เพิ่ม `editor: f.editor` · type `<select>` ทั้ง 2 ที่ เพิ่ม `@change="f.editor = defaultEditor(f.type)"` · editor select แสดงเฉพาะ `editorOptions(f.type).length > 1` (mobile card + desktop `<th>/<td>`) ไม่งั้น `—` muted · hint ไทยใต้ subtitle
4. [documents/create/[templateId].vue](../../web/app/pages/documents/create/[templateId].vue): field loop แทน ternary ด้วย `resolveEditor(f)` switch — `textarea` → `<textarea rows="4">` · `number` → input number step any (preserve) · `date` → input date (preserve) · else textbox · prefill `?from=` ของ field editor `date` ผ่าน `dateInputValue` (input[type=date] รับเฉพาะ yyyy-MM-dd — ค่า timestamp เต็มจาก Word sync ทำให้ช่องแสดงว่าง)
5. [templates/new.vue](../../web/app/pages/templates/new.vue): copy ปุ่มลิงก์ `label/type/required` → `label/type/editor/required`
## ขั้นที่ 3 — Tests
**Backend — ไฟล์ใหม่ `FieldEditorTests.cs`** (pattern `VersionMessageTests` — `fixture.CreateDb()` + `AsNoTracking` + ใช้ `TemplateTests.CreateDefaultTemplateAsync`):
1. `Update_TextFieldEditorTextarea_PersistsAndEchoed` (response + DB row = "textarea")
2. `Update_OmittedEditor_ResolvesDefaultPerType_StoresNull` (text/number/date → echo textbox/number/date, DB null ทั้งหมด)
3. `Update_EditorEqualToDefault_NormalizedToNull` (ส่ง "textbox" ชัดๆ → echo "textbox", DB null)
4. `Update_UnknownEditor_Returns400`
5. `[Theory] Update_EditorIncompatibleWithType_Returns400` ((number,"textarea"), (text,"date"), (date,"textbox"))
6. `ReplaceFile_AddedTagGetsDefaultEditor` (echo "textbox", DB null)
Mirror DTO: `TestDtos.cs` `TemplateFieldItem` เพิ่ม `string Editor` · extend `TemplateTests` — `Create_DetectsAllSdtTags_WithDefaults` assert `Editor == "textbox"` + `Update_SavesFieldDefinitions_AndMetadata` เพิ่ม editor ใน payload
**Web — สร้าง `test/fieldEditor.spec.ts`**: `defaultEditor` ทุก type + unknown · `resolveEditor` (explicit/undefined/incompatible/string-tolerant) · `editorOptions` (text=2, number/date=1) · `dateInputValue` (timestamp→date, plain คงเดิม, ค่าอื่นคงเดิม) · `fieldValidation.spec.ts` ไม่แตะ
## Verification
```
# ลำดับ: docs → backend → web
cd backend/WordVersioning.Api && dotnet ef migrations add AddTemplateFieldEditor # ตรวจ Up/Down
cd backend && dotnet test --filter FullyQualifiedName~FieldEditorTests # ต้องมี Docker (Testcontainers)
cd backend && dotnet test
cd web && npx vitest run test/fieldEditor.spec.ts && npm test && npm run build
```
Manual E2E (หลัง `docker compose up -d` + backend + `npm run dev`):
1. หน้าแก้ template: field type `text` → เลือก editor `textarea` ได้ · type `number`/`date` → แสดง `—` · เปลี่ยน type จาก text เป็น number → editor กลับเป็น default
2. ฟอร์มสร้างเอกสาร: field textarea → กว้างหลายบรรทัด · number → ช่องตัวเลข · date → date picker (ตามเดิม)
3. Re-generate เอกสารที่ field date เก็บ timestamp เต็ม → ช่อง date ต้องแสดงวันที่ ไม่ใช่ว่างเปล่า
## Risks / gotchas
- `TemplateFieldDto` เป็น positional record — แทรก `Editor` หลัง `Type` กระทบจุด construct เดียว (`FieldDtos`) + test mirror (`TestDtos.TemplateFieldItem`) — ตรวจ compile
- Validation editor ต้องมาหลัง type check (allow-list keyed ตาม type — ลำดับใน loop เดิมรับประกันอยู่แล้ว)
- editor select ใช้ label `editor` lowercase ตาม convention `label`/`type`/`required` ของหน้า — option แสดง raw value เหมือน type select
- อย่าลืมอัปเดตตัวเลข test count ใน docs (52/36) หลังรันจริง
## สถานะ: ✅ implement เสร็จ (2026-08-22)
ผลรันจริงทั้งชุด: backend `dotnet test` **60/60** (เพิ่ม `FieldEditorTests` 8 กรณี) · web `npm test` **46/46** + build ผ่าน (เพิ่ม `fieldEditor.spec.ts` 10 กรณี) · addin ไม่ถูกแตะ (50/50 คงเดิม) — รายละเอียด checkbox Phase 10 + หมายเหตุจากการทำจริงอยู่ที่ [officejs-implementation-plan.md](officejs-implementation-plan.md) · ผล AC-17 ที่ [acceptance-review.md](../acceptance-review.md) · เหลือยืนยันด้วยมือ: browser click-through ของ admin select + textarea/date rendering ในฟอร์มสร้างเอกสาร

View file

@ -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–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 จริง
> สถานะ: **Phase 0–10 เสร็จ** (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-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
- **FR-9 ถึง FR-14 เป็น requirement ที่เพิ่มภายหลัง spec เดิม** — spec ปัจจุบันเป็นฉบับ v6 (ครอบ FR-1–14 + AC-1–17: v2 เพิ่ม template/portal/field sync, v3 เพิ่มข้อจำกัดแพลตฟอร์มจากการทดสอบจริง, v4 เพิ่มรายการเอกสารต่อ template + detail + re-generate, v5 เพิ่ม commit message ต่อ version, v6 เพิ่ม editor ต่อ field) ให้ถือ spec เป็น source of truth ของ requirements
---
@ -523,6 +523,27 @@ POST /api/documents/generate { templateId, values: { <fieldKey>: <value> } }
---
## Phase 10: Field editor — FR-14 (เพิ่มทีหลัง, v6)
**เป้า:** ผู้ดูแลเลือกรูปแบบช่องกรอก (editor) ต่อ field ได้ — `text` เลือก `textbox`/`textarea` ได้, `number`/`date` ใช้ control ตาม type — เป็น presentation metadata ล้วน (ค่า field เป็น string ทั้ง flow, validation ยึด `Type` เท่านั้น) — แผนเต็มที่ [`docs/plans/field-editor.md`](field-editor.md)
- [x] Backend: `TemplateField.Editor` (string?, varchar 16 — null = default ของ Type) + `EditorsByType`/`DefaultEditor` + `AppDbContext` config + migration `AddTemplateFieldEditor` (nullable column เดี่ยว ไม่ backfill)
- [x] Backend: `TemplateFieldDefinition.Editor` (ทางเลือก — ไม่ส่ง/ว่าง = default) + validate ตาม type (ไม่รู้จัก/ไม่เข้ากับ type → 400) + normalize-on-write (ค่า = default → เก็บ null) + `TemplateFieldDto.Editor` คืนค่า resolved เสมอ
- [x] Web: util `fieldEditor.ts` (`EDITORS_BY_TYPE`/`defaultEditor`/`editorOptions`/`resolveEditor`/`dateInputValue`) + `FieldEditor` type ใน `api.ts`
- [x] Web: หน้าแก้ field definitions เพิ่ม editor select (แสดงเฉพาะ type `text` ที่มีทางเลือก >1, number/date แสดง `—`) + reset editor เป็น default เมื่อเปลี่ยน type + payload `editor`
- [x] Web: ฟอร์มสร้างเอกสาร render ตาม `resolveEditor` (textarea/number/date/textbox — preserve number/date control เดิม) + prefill re-generate ของ field date ผ่าน `dateInputValue` (input[type=date] รับเฉพาะ yyyy-MM-dd)
- [x] Tests: `FieldEditorTests` (backend 6 กรณี) + `fieldEditor.spec.ts` (web) + extend `TemplateTests` default/echo
หมายเหตุจากการทำจริง (2026-08-22):
- `applyDetail` ของ edit.vue resolve editor ตอนโหลด (`{ ...f, editor: resolveEditor(f) }`) — ฟอร์มถือค่า valid เสมอแม้ API เก่า/ค่าหลุด
- `@change` ของ type select อ่านค่าจาก `e.target` ตรงๆ (`onTypeChange`) ไม่พึ่งลำดับ handler ของ v-model
**DoD:** `dotnet test` + web `npm test`/`npm run build` เขียวทั้งชุด · generate/field sync path ไม่เปลี่ยนพฤติกรรม
> ✅ ตรวจผ่านจริง (2026-08-22): `dotnet test` **60/60** · web `npm test` **46/46** + build ผ่าน · addin ไม่ถูกแตะ (50/50 คงเดิม)
---
## 4. ตาราง mapping: Phase ↔ FR ↔ Acceptance Criteria
| Phase | FR ที่ implement | Acceptance criteria ที่ตรวจได้ |
@ -538,6 +559,7 @@ POST /api/documents/generate { templateId, values: { <fieldKey>: <value> } }
| 7 | — | คุ้มกัน regression ทุก AC (รวม AC-13, 14) |
| 8 | — | ทบทวน AC-1 ถึง AC-14 ทั้งหมด |
| 9 (ทีหลัง, v5) | FR-13 | AC-16 |
| 10 (ทีหลัง, v6) | FR-14 | AC-17 |
**AC เพิ่มเติม (นอก spec เดิม):**
- **AC-11:** upload template .docx ที่มี content controls → ระบบ detect fields อัตโนมัติ + บันทึก field definitions ได้
@ -546,6 +568,7 @@ POST /api/documents/generate { templateId, values: { <fieldKey>: <value> } }
- **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
- **AC-17:** (v6) admin เลือก editor ของ field type `text` เป็น `textarea` ได้ → ฟอร์มสร้างเอกสารแสดงเป็น textarea · number/date ใช้ control ตาม type · editor ไม่ถูกต้อง → 400 · ไม่ส่ง → default ของ type · ค่า field และการ generate ไม่เปลี่ยน — รายละเอียดตาม FR-14
---
@ -578,7 +601,7 @@ docker compose up -d
cd backend/WordVersioning.Api
dotnet run # รัน + swagger ที่ http://localhost:5xxx
dotnet ef migrations add <Name>
cd .. && dotnet test # integration tests (52 ตัว) — ต้องมี Docker รันอยู่ (Testcontainers ยก infra เอง ~1 นาที)
cd .. && dotnet test # integration tests (60 ตัว) — ต้องมี Docker รันอยู่ (Testcontainers ยก infra เอง ~1 นาที)
# add-in (https://localhost:3000)
cd addin
@ -592,5 +615,5 @@ npx office-addin-dev-certs install # ครั้งแรกครั้ง
cd web
npm install
npm run dev
npm test # vitest (36 ตัว)
npm test # vitest (46 ตัว)
```