[ { "id": "R-021", "suite": "Mockup workspace: Sitemap / Page flow / Screen Listing", "date": "2026-10-31T11:21:44+07:00", "summary": "Mockup browser 43 ข้อ + regression 70/25/9 รวม 147 ข้อผ่าน พร้อม Go/race/vet และ artifact validation", "groups": [ { "name": "แบบหน้าจอและเส้นทาง", "audience": "ba", "purpose": "ตรวจหน้าจออ้างอิงร่วมกันและไม่ตีความ mapping ร่างเป็นข้อยืนยัน", "cases": [ { "name": "Screen Listing มี 164 screen IDs และ proposal references 6 ภาพ พร้อม detail/variants/provenance/component links", "status": "pass" }, { "name": "Sitemap ใช้ภาพ shape เรียงบนลงล่าง จำกัดความกว้างแถว และกรอง Module/Channel โดยไม่ลบข้อมูลที่ซ่อน", "status": "pass" }, { "name": "Page flow เลือกครบ 162 Use cases และรักษา Decision/label/เส้นทางจาก canonical source", "status": "pass" }, { "name": "W-41 แสดง A01 สร้างบัญชี A05 แนบหลักฐาน และทางข้ามผู้ปกครอง พร้อมภาพ state ของผลลัพธ์", "status": "pass" }, { "name": "หน้าจอเดิมใช้หลาย occurrence ได้ แต่ละ occurrence เปลี่ยน state และ mapping แยกกัน", "status": "pass" }, { "name": "Editor และ detail แสดงผลได้บนมือถือ พร้อม grid/zoom/label/arrow editing", "status": "pass" } ] }, { "name": "ข้อมูลและการบันทึกร่วม", "audience": "tech", "purpose": "ตรวจ catalog/API/storage และไม่รบกวนเครื่องมือเดิม", "cases": [ { "name": "ตรวจ 170 screen records, 990 preview variants, 6 component contracts/previews และ 162 flow mappings", "status": "pass" }, { "name": "go test -race -count=1 ./... และ go vet ./... ผ่าน รวม catalog/reference validation ทุก flow", "status": "pass" }, { "name": "Same-origin write, invalid references, path/symlink confinement และ concurrent stale saves ถูกตรวจ", "status": "pass" }, { "name": "Saved graph ไม่ถูกแทนที่เมื่อ source เปลี่ยน และ JSON เสียไม่ถูก reset เงียบ", "status": "pass" }, { "name": "Save/Restore เก็บ revision snapshots และปฏิเสธ stale save โดยคง local edits", "status": "pass" }, { "name": "mockups-check.mjs ผ่าน 43 assertions; Use cases 70; workflow review 25; task briefs 9", "status": "pass" }, { "name": "ตรวจ GET บน 8099 ครบเมนู/guide/catalog/drafts และไม่มี real mockup graph ถูกสร้างโดย tests", "status": "pass" } ] } ], "command": "python3 mockups/tools/build_catalog.py --check; cd tracker && go test -race -count=1 ./... && go vet ./...; Playwright mockups-check/usecases-check/workflow-review-check/task-brief-check บน temporary data", "passed": 147, "failed": 0, "skipped": 0, "notes": "147 คือ browser assertions 43+70+25+9; Go/data checks เพิ่มแยกกัน ทดสอบเขียนเฉพาะ /tmp/tnsu-mockup-final/data ไม่ approve Use cases จริง" }, { "id": "R-020", "suite": "ทบทวน Use cases และ canonical decision diagrams", "date": "2026-10-31T02:59:35+07:00", "summary": "ตรวจครบ 162 กรณี/47 decisions พร้อม browser 95 assertions โดยใช้ temporary data เท่านั้น", "groups": [ { "name": "พฤติกรรมและขอบเขต", "audience": "ba", "purpose": "ตรวจข้อเสนอทางเลือกและไม่ข้ามเงื่อนไขที่มีผลต่อผู้เรียน", "cases": [ { "name": "ผลตรวจครบ 162 ID และหมายเหตุสอดคล้องกับ canonical/generated catalog", "status": "pass" }, { "name": "W-41 ข้ามข้อมูลผู้ปกครองเมื่อไม่จำเป็นได้จริง ไม่บังคับ Parent Portal ทุกคน", "status": "pass" }, { "name": "W-77 ส่งเอกสารเพิ่มกลับไปตรวจใหม่ และทางปฏิเสธไม่ไปผลสำเร็จ", "status": "pass" }, { "name": "W-147 ต่อสัญญา/ย้ายห้องไม่ผ่านคืนมัดจำแบบย้ายออก", "status": "pass" }, { "name": "W-14 มีเส้นฉุกเฉินแยกก่อนสายอนุมัติปกติ; W-96 รอ EC ไม่ปิด milestone", "status": "pass" }, { "name": "W-163 ยืนยันซ้ำแล้วข้ามการหมดสิทธิ์ และไม่ตอบไม่เท่ากับสละโดยอัตโนมัติ", "status": "pass" } ] }, { "name": "โครงสร้าง แผนภาพและการถดถอย", "audience": "tech", "purpose": "รักษาความสอดคล้องของต้นฉบับ ภาพ และ approval/history", "cases": [ { "name": "go test -race -count=1 ./... และ go vet ./... ผ่าน", "status": "pass" }, { "name": "ทุกขั้นทั้ง 162 use cases เข้าถึงได้ ไม่มี dangling edge/dead end และมีทางถึง terminal outcome", "status": "pass" }, { "name": "เงื่อนไข workflow ที่เปลี่ยนทำ approval stale โดยไม่เขียนทับ saved diagram", "status": "pass" }, { "name": "สร้าง generated catalog ซ้ำได้ผลเหมือนเดิมทั้ง 37 ไฟล์", "status": "pass" }, { "name": "usecases-check.mjs ผ่าน 70 assertions รวม grid zoom export PNG และ revision/approval", "status": "pass" }, { "name": "workflow-review-check.mjs ผ่าน 25 assertions รวม branch labels, reset, saved revision, fit และ mobile", "status": "pass" }, { "name": "ตรวจหน้า 8099 แบบอ่านอย่างเดียวแสดง canonical draft รุ่นใหม่โดยไม่สร้าง approval จริง", "status": "pass" } ] } ], "command": "python3 docs/agent/tools/check_use_case_review.py; cd tracker && go test -race -count=1 ./... && go vet ./...; Playwright usecases-check.mjs + workflow-review-check.mjs บน temporary server", "passed": 95, "failed": 0, "skipped": 0, "notes": "95 คือ browser assertions (70+25); Go และ data checks ตรวจเพิ่มแยกกัน การรันทดสอบก่อนหน้าพบ pointer นอก viewport และแก้ให้ scroll canvas ก่อนลากแล้วรันครบผ่าน ดู P-013" }, { "id": "R-019", "suite": "ปิดงานจัดทำ Role/Security Matrix ฉบับร่าง", "date": "2026-10-31T02:19:03+07:00", "summary": "ตรวจหลักฐานฉบับร่างและเปลี่ยนสถานะ Done เฉพาะ T-201/T-202 โดยคงรายการรอ BA/Security ยืนยัน", "groups": [ { "name": "สถานะและหลักฐาน", "audience": "both", "purpose": "ปิดงาน Agent ที่เสร็จแล้วโดยไม่อนุมัติข้อกำหนดแทนผู้ตรวจ", "cases": [ { "name": "Role/Security Matrix draft v0.1 มีไฟล์และหัวข้อครบตาม checkpoint C-004", "status": "pass" }, { "name": "เปลี่ยนเป็น Done เฉพาะ T-201/T-202 และเวลา finished อ้างอิง C-004", "status": "pass" }, { "name": "ข้อมูล review และ task อื่นทุก field คงเดิม", "status": "pass" }, { "name": "go test -count=1 ./... ผ่าน", "status": "pass" } ] } ], "command": "ตรวจ artifacts/status diff และ cd tracker && go test -count=1 ./...", "passed": 4, "failed": 0, "skipped": 0, "notes": "Done คือจัดทำฉบับร่างเสร็จ ไม่ใช่ยืนยัน business/security requirements; review.todo คงไว้", "failures": [] }, { "id": "R-018", "suite": "ตรวจส่งมอบงานที่ Reviewed แล้ว", "date": "2026-10-31T02:12:41+07:00", "summary": "Go race/vet ผ่าน Browser 70+9 รวม 79 assertions ผ่าน ใช้ข้อมูลชั่วคราวเพื่อปิดชุดงาน T-408–T-417", "groups": [ { "name": "Use cases และ diagram", "audience": "both", "purpose": "ตรวจฟีเจอร์ที่ผ่านรีวิวทั้งชุดก่อนเก็บ Git", "cases": [ { "name": "ตารางแบ่ง module/tabs/filter/collapse และ editor ทั้งชุดผ่าน 70 assertions", "status": "pass" }, { "name": "Save/revision history/rollback และ approval invalidation ทำงานครบ", "status": "pass" }, { "name": "PNG ส่งออกครบและ background White/Transparent ถูกต้องจริง", "status": "pass" }, { "name": "UI review panels, dark mode, mobile และ unsaved edits ผ่าน", "status": "pass" } ] }, { "name": "Task briefs และคุณภาพโค้ด", "audience": "both", "purpose": "รักษาผลรีวิวและรายละเอียดงานที่ตรวจแล้ว", "cases": [ { "name": "Task briefs ผ่าน 9 assertions รวม T-303 และคำถาม 39 ข้อ", "status": "pass" }, { "name": "Go test -race -count=1 ./... ผ่าน", "status": "pass" }, { "name": "go vet ./... ผ่าน", "status": "pass" }, { "name": "JSON ทุกไฟล์ JavaScript syntax และ git diff --check ผ่าน", "status": "pass" }, { "name": "สถานะ T-408–T-417 ยังเป็น Reviewed และไม่มี Reject/Hold ค้าง", "status": "pass" } ] } ], "command": "cd tracker && go test -race -count=1 ./... && go vet ./...; node tracker/e2e/usecases-check.mjs ; node tracker/e2e/task-brief-check.mjs ", "passed": 79, "failed": 0, "skipped": 0, "notes": "79 คือจำนวน browser assertions; Go suite ตรวจแยก ไม่มีการอนุมัติหรือแก้ diagram จริงใน repository", "failures": [] }, { "id": "R-017", "suite": "Task briefs และ stakeholder questions", "date": "2026-10-30T21:19:31+07:00", "summary": "Go race/vet ผ่าน และ browser read-only 9 ข้อผ่าน ครอบคลุม task brief, T-303, questions, mobile และ SQL Server decision", "groups": [ { "name": "ความครบถ้วนของแผนงาน", "audience": "ba", "purpose": "ให้ task อ่านแล้วเริ่มงานและรู้ว่าจะถามใครได้", "cases": [ { "name": "งานรอดำเนินการ 13 งานแสดงรายละเอียด outputs และคำถาม 39 ข้อ", "status": "pass" }, { "name": "T-303 แสดงคำถาม hosting 5 ข้อ และสถานะยังรอข้อมูล", "status": "pass" }, { "name": "คำถามระบุผู้ที่ควรตอบและผลต่อการตัดสินใจ", "status": "pass" }, { "name": "dependencies เป็นลิงก์กดไปงานที่เกี่ยวข้องได้", "status": "pass" }, { "name": "ผู้รับผิดชอบที่เสนอมีป้ายรอยืนยัน ไม่ถูกตั้งเป็นผู้ได้รับมอบหมายจริง", "status": "pass" }, { "name": "คำถามบนมือถือโหมดมืดไม่ทำให้หน้าล้น", "status": "pass" }, { "name": "summary T-302 แสดงผลเลือก SQL Server ที่ยืนยันแล้ว", "status": "pass" }, { "name": "งานเสร็จแล้วมีบริบทให้อ่านโดยยังรักษาสถานะเดิม", "status": "pass" } ] }, { "name": "โครงสร้างข้อมูลและการแสดงผล", "audience": "tech", "purpose": "คง review history และไม่บันทึกข้อสรุปที่ไม่มีคำตอบ", "cases": [ { "name": "Go test -race -count=1 ./... และ go vet ./... ผ่าน", "status": "pass" }, { "name": "รหัสคำถามไม่ซ้ำ dependencies อ้างอิง task ที่มีจริง และคำถาม answered ต้องมี answer", "status": "pass" }, { "name": "SSR Task แสดง description/deliverables/questions/ผู้ตอบครบ พร้อม escape ข้อความ", "status": "pass" }, { "name": "refs ทุกไฟล์ของ task ที่เติมรายละเอียดมีอยู่จริง", "status": "pass" }, { "name": "Browser read-only 9 assertions ผ่าน ไม่เปลี่ยนข้อมูล/ผลรีวิว", "status": "pass" } ] } ], "command": "cd tracker && go test -race -count=1 ./...; go vet ./...; node e2e/task-brief-check.mjs ", "passed": 9, "failed": 0, "skipped": 0, "notes": "passed 9 คือ browser assertions; งาน hosting/data model/scope ยังคง todo ตามเดิม การเติม brief ไม่ใช่การปิดงานเหล่านั้น", "failures": [] }, { "id": "R-016", "suite": "Review panels UI และ PNG export", "date": "2026-10-30T21:08:18+07:00", "summary": "Browser 70 ข้อผ่าน รวมไฟล์ PNG จริง และ UI Approval/History ทั้งจอเล็กและโหมดมืด", "groups": [ { "name": "Review panels", "audience": "ba", "purpose": "อ่านสถานะและประวัติได้ง่าย", "cases": [ { "name": "Approval ที่อนุมัติแล้วแสดงผู้ตรวจและหมายเหตุแทนฟอร์มว่าง", "status": "pass" }, { "name": "Revision history มี empty state และ Current version ที่ชัดเจน", "status": "pass" }, { "name": "Refresh ประวัติล้มเหลวแล้วยังเก็บรายการเดิมไว้", "status": "pass" }, { "name": "Review panels บนมือถือไม่ทำให้หน้าล้น และ screenshot สว่าง/มืดอ่านได้", "status": "pass" } ] }, { "name": "PNG export และ regression", "audience": "tech", "purpose": "ส่งออกได้ครบและรักษาความโปร่งใสจริง", "cases": [ { "name": "เปิด Export PNG dialog และเลือกพื้นหลังได้", "status": "pass" }, { "name": "PNG พื้นหลัง White มี pixel มุมเป็น RGBA 255,255,255,255", "status": "pass" }, { "name": "PNG Transparent มี alpha channel ที่มุมเท่ากับ 0", "status": "pass" }, { "name": "ขนาด PNG ตรงกับ full graph bounds แม้ซูม viewport", "status": "pass" }, { "name": "Browser regression ทั้ง 70 ข้อผ่าน และ JavaScript syntax ถูกต้อง", "status": "pass" } ] } ], "command": "node tracker/e2e/usecases-check.mjs ", "passed": 70, "failed": 0, "skipped": 0, "notes": "ทดสอบการ Save/Approve เฉพาะ /tmp; ตรวจ PNG ที่ดาวน์โหลดจริง ไม่ใช้ screenshot แทนการส่งออก", "failures": [] }, { "id": "R-015", "suite": "Horizontal workflow, revision history, approval และ module groups", "date": "2026-10-30T20:44:48+07:00", "summary": "Browser 59 ข้อผ่าน Go race suite และ vet ผ่าน ทดสอบการเขียน/Approve เฉพาะข้อมูล /tmp", "groups": [ { "name": "Workflow และรายการ Use cases", "audience": "ba", "purpose": "จัดและค้นหากระบวนการได้ง่าย พร้อมตรวจยืนยันเป็นราย Use case", "cases": [ { "name": "ร่างใหม่ไหลซ้ายไปขวาและเว้นช่องตามขนาด shape", "status": "pass" }, { "name": "Arrange horizontally เก็บ shape/connection เดิมครบและ Undo คืนตำแหน่งได้", "status": "pass" }, { "name": "Toolbar ใช้ปุ่มอังกฤษที่ชัดเจน", "status": "pass" }, { "name": "กลุ่ม Module แสดงชื่อเต็ม หุบ/ขยาย และ Expand all / Collapse all ได้", "status": "pass" }, { "name": "หุบ Module แล้ว reload ยังจำสถานะ ใช้กับ channel tabs และ filters ได้", "status": "pass" }, { "name": "Approve เก็บชื่อ เวลา หมายเหตุ และแสดงสถานะในตาราง", "status": "pass" }, { "name": "แก้/Save/Restore แล้วสถานะอนุมัติต้องยืนยันใหม่และไม่ล้าง approval history", "status": "pass" }, { "name": "Restore คืนเนื้อหาจาก revision เดิมเป็น revision ใหม่ เก็บ intermediate revisions ครบ", "status": "pass" } ] }, { "name": "ความถูกต้องและ concurrent edits", "audience": "tech", "purpose": "ไม่ทับงาน ไม่ยืนยันข้อมูลที่ยังไม่ได้ตรวจ และไม่ลบประวัติ", "cases": [ { "name": "Go test -race -count=1 ./... และ go vet ./... ผ่าน", "status": "pass" }, { "name": "ทุก snapshot และ current graph เขียน atomic และอ่านกลับหลังสร้าง store ใหม่ได้", "status": "pass" }, { "name": "การ Save พร้อมกันยอมรับครั้งเดียวและเก็บ history ถูกต้อง", "status": "pass" }, { "name": "stale restore / stale source / stale diagram approval ถูกปฏิเสธ", "status": "pass" }, { "name": "CSRF และ approval ที่ไม่มีชื่อหรือไม่ยืนยันถูกปฏิเสธ", "status": "pass" }, { "name": "ไฟล์เดิมที่ยังไม่มี history ถูกเก็บ revision เดิมก่อนบันทึกถัดไป", "status": "pass" }, { "name": "Approve ร่างเริ่มต้นจะ Save layout เป็น revision 1 ก่อนและบันทึกการยืนยัน", "status": "pass" }, { "name": "Browser regression ครบ 59 ข้อไม่พบ JavaScript exceptions", "status": "pass" } ] } ], "command": "cd tracker && go test -race -count=1 ./...; go vet ./...; node e2e/usecases-check.mjs ", "passed": 59, "failed": 0, "skipped": 0, "notes": "59 คือจำนวน browser assertions; tests ของ approval ไม่เคยเขียนข้อมูลจริงใน repo", "failures": [] }, { "id": "R-014", "suite": "Use cases tabs / full descriptions / Ctrl-wheel และ Overview order", "date": "2026-10-30T20:14:46+07:00", "summary": "Browser regression ผ่าน 41 ข้อ พร้อม Go race suite และ vet ผ่าน ตรวจหน้า 8099 แบบอ่านอย่างเดียวผ่าน", "groups": [ { "name": "การอ่านและค้นหา Use cases", "audience": "ba", "purpose": "อ่านรายการตามช่องทางและอ่านเนื้อหา diagram ครบ", "cases": [ { "name": "แท็บทั้งหมด Frontend Backoffice และ Integration ใช้ร่วมกับ filters ได้", "status": "pass" }, { "name": "ตารางแสดงยาวลงมาตามหน้าโดยไม่มีความสูงจำกัด", "status": "pass" }, { "name": "description จากต้นฉบับแสดงครบ ตัดเป็นบรรทัดสั้น และร่างใหม่ไม่ซ้อนกัน", "status": "pass" }, { "name": "description ยาวหลายบรรทัดอยู่ภายใน Start End Process และ Decision ครบทุกตัวอักษร", "status": "pass" }, { "name": "Current Task อยู่ก่อน Milestone ทั้งหมดบนหน้าภาพรวมจริงพอร์ต 8099", "status": "pass" } ] }, { "name": "การซูมและ regression", "audience": "tech", "purpose": "ตรวจการทำงานร่วมกับ editor และการเก็บข้อมูลเดิม", "cases": [ { "name": "Ctrl + scroll ขึ้นซูมเข้า ลงซูมออก โดยรักษาพิกัดใต้เมาส์", "status": "pass" }, { "name": "dropdown แสดงสเกลตรงและไม่เปลี่ยนระดับ zoom ของ browser", "status": "pass" }, { "name": "scroll ไม่กด Ctrl ยังคง pan และ zoom/pan ไม่ทำให้ข้อมูลมีสถานะยังไม่บันทึก", "status": "pass" }, { "name": "Integration ต้องมีชื่อระบบที่ระบุ ไม่อนุมานจากขั้นตอนระบบทั่วไป", "status": "pass" }, { "name": "Browser ทั้ง 41 ข้อผ่าน รวมกริด เส้นหักมุม สองผู้ใช้ SSE save/reload และมือถือ", "status": "pass" }, { "name": "Go test -race -count=1 ./... และ go vet ./... ผ่าน", "status": "pass" } ] } ], "command": "cd tracker && go test -race -count=1 ./...; go vet ./...; node e2e/usecases-check.mjs ; main read-only smoke", "passed": 41, "failed": 0, "skipped": 0, "notes": "passed 41 หมายถึง browser regression; ยังตรวจ main 8099 แบบอ่านอย่างเดียวและ Go suite แยกต่างหาก", "failures": [] }, { "id": "R-013", "suite": "Diagram Snap to grid และเส้นเชื่อมหักมุม", "date": "2026-10-30T20:04:29+07:00", "summary": "Browser ผ่าน 24 ข้อหลังปรับ Snap to grid และเส้น orthogonal บนข้อมูล /tmp", "groups": [ { "name": "การจัดตำแหน่งและเส้นเชื่อม", "audience": "both", "purpose": "จัด diagram ให้อยู่แนวเดียวกันและอ่านทางเดินของเส้นได้ง่าย", "cases": [ { "name": "ลาก shape แล้วพิกัดขยับตรงกริด 20 หน่วย", "status": "pass" }, { "name": "ทุกช่วงของเส้นเชื่อมเป็นแนวนอนหรือแนวตั้ง หักมุม 90°", "status": "pass" }, { "name": "shape ที่เพิ่มและพิกัดหลังลากยังตรงกริดหลังบันทึกและเปิดใหม่", "status": "pass" }, { "name": "Regression browser ทั้ง 24 ข้อผ่าน รวม Fit/กึ่งกลาง ซูม ลากเส้น สองผู้ใช้ SSE undo/redo โหมดมืดและมือถือ", "status": "pass" } ] } ], "command": "node tracker/e2e/usecases-check.mjs ", "passed": 24, "failed": 0, "skipped": 0, "notes": "การลากทดสอบใช้จุดที่ไม่อยู่กึ่งกลางระหว่างสองช่องกริด เพื่อไม่ผูก assertion กับทศนิยมจาก SVG zoom", "failures": [] }, { "id": "R-012", "suite": "Use cases Table view และ Diagram editor", "date": "2026-10-30T20:00:07+07:00", "summary": "Go suite พร้อม race detector และ go vet ผ่าน Browser ผ่าน 23 ข้อบนข้อมูลสำเนา รวมการจัดกึ่งกลางและ Fit ทั้งหมดตามคำขอล่าสุด", "groups": [ { "name": "Catalog และการแสดงผล", "audience": "ba", "purpose": "ใช้ Use cases เดิมเพื่ออ่านและแก้ workflow ได้สะดวก", "cases": [ { "name": "ตารางแสดงครบ 162 Use cases และกรอง Module / คำค้นหาได้", "status": "pass" }, { "name": "Diagram ฉบับร่างเก็บขั้นตอนต้นฉบับครบและมีข้อมูลผู้เกี่ยวข้อง", "status": "pass" }, { "name": "เปิด diagram แล้วเห็นทุก shape อยู่กึ่งกลางทั้งสองแนว", "status": "pass" }, { "name": "ผู้ใช้ซูมเข้าและกลับมาดูพอดีทั้งหมดได้", "status": "pass" }, { "name": "เพิ่ม shape 4 แบบ แก้ข้อความ และลาก shape กับเส้นเชื่อมได้", "status": "pass" }, { "name": "แก้ข้อความและหัวลูกศรต้น–ปลายของเส้นเชื่อมได้", "status": "pass" }, { "name": "ลบ shape พร้อมเส้นที่เกี่ยวข้อง และ undo/redo คืนได้", "status": "pass" }, { "name": "ข้อมูลบันทึกส่วนกลางยังอยู่หลังเปิดใหม่ โหมดมืดและจอมือถือใช้งานได้", "status": "pass" } ] }, { "name": "ความถูกต้องและการบันทึก", "audience": "tech", "purpose": "รักษาข้อมูลและไม่ทับงานของผู้ใช้อื่น", "cases": [ { "name": "Go test -race -count=1 ./... ผ่านทุก test รวม SSE", "status": "pass" }, { "name": "go vet ./... และ JavaScript syntax check ผ่าน", "status": "pass" }, { "name": "ปฏิเสธ CSRF รหัสไม่รู้จัก JSON ผิดรูปแบบ ข้อมูลเกินขนาด shape/เส้นไม่ถูกต้อง และ revision เก่า", "status": "pass" }, { "name": "บันทึกแล้วอ่านกลับได้ และรองรับวงจรกับ canvas ว่าง", "status": "pass" }, { "name": "ทดสอบสองผู้ใช้จริง: บันทึกเวอร์ชันเก่าไม่ทับงานอีกคนและเก็บข้อความในหน้าจอไว้", "status": "pass" }, { "name": "SSE จริงไม่ล้าง diagram ที่ยังไม่บันทึก", "status": "pass" }, { "name": "Browser ทดสอบ 23 ข้อผ่านและไม่พบ JavaScript exception", "status": "pass" } ] } ], "command": "cd tracker && go test -race -count=1 ./...; go vet ./...; node e2e/usecases-check.mjs ", "passed": 23, "failed": 0, "skipped": 0, "notes": "passed 23 คือ browser assertions; Go suite ผ่านทุกข้อด้วย ใช้ Playwright ที่มีอยู่แล้ว ไม่ได้เพิ่ม dependency ให้ tracker ทดสอบการเขียนบนข้อมูล /tmp เท่านั้น", "failures": [] }, { "id": "R-011", "suite": "Tracker โหลดช้าเมื่อเปิดหลาย tab", "date": "2026-10-30", "summary": "ตรวจว่า tab ที่ไม่ได้ดูคืนช่องเชื่อมต่อ, กลับมาแล้ว live update ทำงานต่อ และ CSS/JS โหลดจาก cache ผ่านทุกข้อ", "groups": [ { "name": "Server", "audience": "tech", "purpose": "ยืนยันว่า server ไม่ใช่ต้นเหตุ", "cases": [ { "name": "ทุกหน้าตอบภายใน 2 ms บนเครื่อง และ 5–25 ms ผ่าน tailnet", "status": "pass" }, { "name": "CSS/JS ที่มี ?v ตรงกับ build ได้ Cache-Control immutable, ไม่มีหรือไม่ตรงได้ no-cache", "status": "pass", "detail": "TestStaticCaching" }, { "name": "go test ทั้งหมด", "status": "pass", "detail": "27 ผ่าน" } ] }, { "name": "Browser (E2E)", "audience": "ba", "purpose": "เปิดหลาย tab แล้วไม่ช้า", "cases": [ { "name": "tab ที่ถูกซ่อนปิดการเชื่อมต่อ live update", "status": "pass", "detail": "การเชื่อมต่อลดลง 1" }, { "name": "กลับมาที่ tab แล้วป้ายเป็น \"อัปเดตแบบเรียลไทม์\" อีกครั้ง", "status": "pass" }, { "name": "เปิดหน้าที่สองแล้ว CSS/JS มาจาก cache ทั้งหมด", "status": "pass" }, { "name": "Live update ยังทำงาน (live-check บนข้อมูลสำเนา)", "status": "pass", "detail": "32 → 33 task โดยไม่ reload" }, { "name": "Timeline (timeline-check)", "status": "pass", "detail": "9 ข้อ" } ] } ] }, { "id": "R-010", "suite": "Timeline เต็มจอและเส้นแบ่ง", "date": "2026-10-30", "summary": "ตรวจว่า Timeline ใช้พื้นที่เต็มจอ, chart ยืดถึงขอบขวา, ลากเส้นแบ่งได้และจำค่า, ย่อ/ขยายแถวได้ และตำแหน่งแถบยังถูกต้องหลังเปลี่ยนเป็น % ผ่านทุกข้อ", "groups": [ { "name": "Timeline layout", "audience": "tech", "purpose": "ตำแหน่งแถบยังถูกต้องหลังเปลี่ยนจาก px เป็น %", "cases": [ { "name": "Task 1 วันกว้าง 1 หน่วยพอดี และความกว้างขั้นต่ำ = จำนวนหน่วย × 44 px", "status": "pass" }, { "name": "Task ที่ยังเปิดอยู่ยืดถึงเส้นตอนนี้", "status": "pass" }, { "name": "แถบ Epic ครอบทุก task ข้างใน", "status": "pass" }, { "name": "go test ทั้งหมด", "status": "pass", "detail": "26 ผ่าน" } ] }, { "name": "Full width (E2E)", "audience": "ba", "purpose": "chart ใช้พื้นที่จอได้เต็ม", "cases": [ { "name": "หน้า Timeline กว้างถึงขอบ browser", "status": "pass", "detail": "main 1348 + เมนู 252 = 1600 px" }, { "name": "chart ยืดถึงขอบขวา ไม่มีที่ว่าง", "status": "pass" } ] }, { "name": "เส้นแบ่งรายละเอียด / chart (E2E)", "audience": "ba", "purpose": "ปรับความกว้างช่องรายละเอียดได้ตามต้องการ", "cases": [ { "name": "ลากที่หัวตารางแล้วช่องรายละเอียดกว้างขึ้น", "status": "pass", "detail": "380 → 540 px" }, { "name": "ลากที่ขอบแถวแล้วช่องรายละเอียดแคบลง", "status": "pass", "detail": "540 → 440 px" }, { "name": "กดลูกศรขวาแล้วขยับ 20 px", "status": "pass" }, { "name": "reload แล้วจำความกว้างไว้", "status": "pass" }, { "name": "กด Home แล้วกลับค่าเดิม", "status": "pass", "detail": "380 px" } ] }, { "name": "ย่อ / ขยาย (E2E)", "audience": "ba", "purpose": "ซ่อนแถวข้างใน Milestone / Epic ได้จริง", "cases": [ { "name": "กดย่อ Epic แล้ว task ข้างในหายจากจอ", "status": "pass", "detail": "32 → 25 แถว (7 task)" }, { "name": "กดขยายแล้วกลับมาครบ", "status": "pass" } ] } ] }, { "id": "R-009", "suite": "Timeline (Gantt chart)", "date": "2026-10-30", "summary": "ตรวจหน้า Timeline: คำนวณช่วงเวลาและตำแหน่งแถบถูกต้องทุกระดับเวลา, ย่อ/ขยาย, เลื่อนไปที่ตอนนี้ และ Live update ไม่ทำให้ตำแหน่ง scroll หาย ผ่านทุกข้อ", "groups": [ { "name": "Timeline layout", "audience": "ba", "purpose": "ความยาวของแถบตรงกับเวลาที่ใช้จริง", "cases": [ { "name": "Task 1 วันกว้าง 1 วันพอดีในมุมมองวัน", "status": "pass", "detail": "44 px" }, { "name": "Task ที่ In Progress / Wait for review ยืดถึงตอนนี้", "status": "pass" }, { "name": "แผน (start → due) แสดงเป็นกรอบเส้นประ", "status": "pass" }, { "name": "Task ที่ไม่มีวันขึ้นว่า \"ยังไม่ได้กำหนดวัน\" และนับเป็น Unscheduled", "status": "pass" }, { "name": "แถบ Epic / Milestone ครอบทุก task ข้างใน และแสดง % ที่เสร็จ", "status": "pass" }, { "name": "Milestone target แสดงเป็น ◆", "status": "pass" } ] }, { "name": "Scales (Hour / Day / Week)", "audience": "both", "purpose": "สลับระดับเวลาได้และหน้าไม่หนักเกินไป", "cases": [ { "name": "ทั้ง 3 scale เปิดได้ (HTTP 200) และ scale ที่ไม่รู้จักกลับเป็น Day", "status": "pass" }, { "name": "Week เริ่มวันจันทร์", "status": "pass" }, { "name": "Hour view จำกัด 21 วันรอบตอนนี้เมื่อแผนยาว", "status": "pass" }, { "name": "Minimum span: Day 21 วัน, Week 12 สัปดาห์, Hour 48 ชม. ไม่ให้ chart แคบเกินไป", "status": "pass" } ] }, { "name": "Interaction (E2E)", "audience": "both", "purpose": "ใช้งานใน browser จริง", "cases": [ { "name": "เปิดหน้าแล้วเส้น \"ตอนนี้\" อยู่ในจอ", "status": "pass" }, { "name": "ย่อ Milestone แล้วซ่อนแถวลูกทั้งหมด และจำค่าหลัง reload", "status": "pass" }, { "name": "Live update ไม่ทำให้ตำแหน่ง scroll แนวนอนหาย", "status": "pass", "detail": "120 → 120 px ในมุมมองชั่วโมง" }, { "name": "Light / Dark / Mobile แสดงผลถูกต้อง", "status": "pass" } ] } ], "command": "go test -count=1 -v ./... ; timeline browser check", "passed": 30, "failed": 0, "skipped": 0, "duration": "0.3s (go test) + 20s (E2E)", "notes": "go test: 26 ผล (20 test + 6 subtest), E2E timeline 4 checks" }, { "id": "R-008", "suite": "File viewer, Reviewed status และ Done สีเขียว", "date": "2026-10-30", "summary": "ตรวจว่าไฟล์แนบเปิดเป็นหน้า HTML ในแท็บใหม่ได้ และปลอดภัย, สถานะ Reviewed ทำงานตามที่ตกลง และทุก flow เดิมยังผ่านหลังเปลี่ยน ผ่านทุกข้อ", "groups": [ { "name": "File viewer (refs)", "audience": "ba", "purpose": "กดไฟล์แนบแล้วเปิดเป็นหน้าที่อ่านง่ายในแท็บใหม่", "cases": [ { "name": "Refs ในหน้า Wait for review เปิด /files/... ในแท็บใหม่", "status": "pass" }, { "name": "Role Matrix แสดงเป็น HTML: 10 ตาราง, 115 แถว, TOC 13 หัวข้อ", "status": "pass" }, { "name": "Row filter: พิมพ์ \"การเงิน\" แล้วเหลือแถวที่เกี่ยวข้อง", "status": "pass", "detail": "พบ 2 แถว" }, { "name": "Anchor link ไปหัวข้อถูกจุด", "status": "pass", "detail": "#3-approval-authority-matrix" }, { "name": "Mermaid diagram render ครบ", "status": "pass", "detail": "13 จาก 13 diagram ใน 05-workflows.md" }, { "name": "Path ใน code span ของข้อความรีวิวกดเปิดไฟล์ได้", "status": "pass" }, { "name": "โฟลเดอร์แสดงรายการไฟล์ และ /files/tracker redirect ไป /files/tracker/", "status": "pass" } ] }, { "name": "Security (file viewer)", "audience": "tech", "purpose": "ตัวเปิดไฟล์ต้องไม่เปิดอะไรนอก repo", "cases": [ { "name": "Path traversal (../ และ %2e%2e) ได้ 404 หลัง clean path", "status": "pass" }, { "name": ".git และไฟล์ซ่อนเปิดไม่ได้", "status": "pass" }, { "name": "Symlink ที่ชี้ออกนอก repo เปิดไม่ได้ (EvalSymlinks + prefix check)", "status": "pass" }, { "name": "Text ที่ไม่ใช่ path ใน repo ไม่ถูกทำเป็นลิงก์", "status": "pass" } ] }, { "name": "Markdown renderer", "audience": "tech", "purpose": "เอกสารใน docs/ แสดงครบเหมือนบน GitLab", "cases": [ { "name": "Pipe table รวม escaped pipe และ code ในช่อง", "status": "pass" }, { "name": "Heading ID แบบ GitHub รองรับภาษาไทย", "status": "pass" }, { "name": "ยังตัด