// SI work products 11–22. import { P, CODE, PROJECT_TH, ORGANIZER, ORGANIZER_PM, RECORDER, START, END, SCOPE, CRS, crTopic, TEST_FROM, TEST_TO, ACCEPT_DATE, DEV_BASELINE, BASELINE_COMMIT, TEST_STATE_COMMIT, ORIGIN, BACKUP } from './project.mjs'; import { SR_GROUPS, SRS, srTopic, UNIT_GROUPS, UNITS, unitTopic, unitModule, TEST_CASES, traceOf } from './engineering.mjs'; import { CORRECTIONS } from './history.mjs'; import { figure } from './figures.mjs'; import { bud, thLong, thShort, thRange, thRangeLong, table, bullets, numbered } from './lib.mjs'; import { workProduct, head } from './format.mjs'; const D = '2026-08-17'; /** 11. Software Requirements Specification. */ export function softwareRequirements() { const date = '2026-02-25'; const rows = []; for (const [gid, gname, items] of SR_GROUPS) { rows.push([`${gid}: ${gname}`, '', '', '']); for (const [id, text, refs] of items) rows.push([id, text, 'A', refs]); } return { dir: '2-SI Process (12 Work Product)/11.Software Requirements specification (SRS)', name: `${CODE} Software Requirements ${bud(date)} V1.0 NoC`, md: workProduct({ type: 'Software Requirements', footer: 'SRS', rows: head('Software Requirements', `${bud(date)} V1.0 NoC`, [ ['Title', 'เอกสารบันทึกและสรุปความต้องการซอฟต์แวร์ (Software Requirements Specification)'], ['Project Period', thRangeLong(START, END)], ['Organizer', ORGANIZER], ['Recorder', RECORDER], ]), body: [ '## วัตถุประสงค์ (Objectives)', 'เพื่อแปลงความต้องการของลูกค้าที่ได้รับอนุมัติแล้วให้เป็นความต้องการเชิงเทคนิคของซอฟต์แวร์ ครอบคลุมมาตรฐาน โครงสร้าง ส่วนประกอบ ความสัมพันธ์ ประสิทธิภาพ ส่วนเชื่อมต่อ ความปลอดภัย ฐานข้อมูล และการจัดการข้อผิดพลาด เพื่อใช้เป็นเอกสารอ้างอิงหลักในการออกแบบระบบ พัฒนา และทดสอบ', '## ผู้มีส่วนได้ส่วนเสีย (Stakeholders)', table(['ลำดับ', 'ชื่อ', 'หน่วยงาน/ตำแหน่ง', 'บทบาท'], [ [1, P.SeV.th, 'ผู้บริหาร (CEO)', 'Project Sponsor อนุมัติความต้องการ'], [2, P.ApS.th, 'ผู้จัดการโครงการ', 'บริหารจัดการโครงการ'], [3, P.NoC.th, 'นักวิเคราะห์ระบบ', 'จัดทำและควบคุมความต้องการซอฟต์แวร์'], [4, P.ThS.th, 'นักพัฒนาระบบ', 'พัฒนาระบบตามความต้องการ'], [5, P.PaNg.th, 'ผู้ทดสอบระบบ', 'จัดทำ Test Case จากความต้องการ'], ], ['c']), '## ความต้องการซอฟต์แวร์ (Software Requirements)', table(['ID', 'Topic', 'Result*', 'Remark'], rows, ['', '', 'c', '']), '## Remark', bullets([ '\\* Result : A = Accepted, U = Unaccepted, N/A = Not Applicable', 'ช่อง Remark แสดงรหัสความต้องการของลูกค้า (Customer Requirements) ที่เป็นที่มาของความต้องการซอฟต์แวร์แต่ละรายการ', 'ความต้องการซอฟต์แวร์ที่ไม่มีที่มาจากความต้องการของลูกค้าต้องผ่าน Change Report ก่อนถือเป็นข้อผูกพัน', ]), ].join('\n\n'), secretary: P.NoC, reviewer: P.YaB, approver: P.SeV, }), }; } /** 12. Software Design — high level design, software baseline, and software units. */ export function softwareDesign() { const date = '2026-03-06'; const unitRows = []; for (const [mid, mname, items] of UNIT_GROUPS) { unitRows.push([`${mid} — ${mname}`, '', '', '', '']); for (const [id, desc, detail, refs, files] of items) unitRows.push([id, desc, detail, refs, files]); } return { dir: '2-SI Process (12 Work Product)/12.Software design', name: `${CODE} Software Design ${bud(date)} V1.0 NoC`, md: workProduct({ type: 'Software Design', footer: 'SD', rows: head('Software Design', `${bud(date)} V1.0 NoC`, [ ['Title', 'เอกสารการออกแบบระบบ (System Design Document)'], ['Project Period', thRangeLong(START, END)], ['Organizer', ORGANIZER], ['Recorder', RECORDER], ]), body: [ '## HIGH LEVEL DESIGN', '### High Level Architecture Diagram', 'ภาพรวมสถาปัตยกรรมของระบบ แบ่งเป็นผู้ใช้งาน ชั้น Client, Web, Data, Service และบริการภายนอก พร้อมช่องทางการเชื่อมต่อระหว่างกัน ทุกคำขอจากหน้าจอผ่านการตรวจสอบของ db_auth ก่อนถึงตรรกะธุรกิจ', figure('architecture'), '### Use Case Diagram', 'ผู้ใช้งานของระบบและกลุ่มการใช้งานหลัก บทบาทที่สูงกว่าได้รับสิทธิ์การใช้งานของบทบาทที่ต่ำกว่าทั้งหมด (Viewer → Staff → Admin → Owner)', figure('useCase'), table(['Actor', 'คำอธิบาย', 'การใช้งานหลัก'], [ ['Owner', 'เจ้าของบริษัท สิทธิ์สูงสุดภายในบริษัท', 'ตั้งค่าบริษัท จัดการผู้ใช้ และใช้งานทุกโมดูล'], ['Admin', 'ผู้ดูแลระบบภายในบริษัท', 'จัดการข้อมูลหลัก ผู้ใช้ สิทธิ์ และใช้งานทุกโมดูลปฏิบัติการ'], ['Staff', 'ผู้ปฏิบัติงาน', 'บันทึกรายการคลังสินค้า ขาย จัดซื้อ และการเงินตามสิทธิ์'], ['Viewer', 'ผู้ใช้แบบอ่านอย่างเดียว', 'ดูหน้าจอและรายงานที่ได้รับสิทธิ์'], ['System Scheduler', 'ผู้กระทำอัตโนมัติ (Node.js)', 'สรุปยอดสต๊อก/GL และแจ้งเตือนตามกำหนดเวลา'], ['SMTP Service', 'ผู้กระทำภายนอก', 'ส่งอีเมล Onboarding กู้คืนรหัสผ่าน และแจ้งเตือน'], ]), '### Component Diagram', 'โมดูลของระบบ (Software Unit กลุ่ม UN01–UN13) และความสัมพันธ์การเรียกใช้ระหว่างโมดูล', figure('component'), 'โครงสร้างส่วนประกอบของระบบแบ่งตามชั้นการทำงาน', table(['ชั้น (Layer)', 'ส่วนประกอบ', 'อ้างอิง SR'], [ ['Presentation', 'หน้าจอ PHP ในแต่ละโมดูล (`app//`), JavaScript และ CSS ที่รองรับ Responsive', 'SR02:002, SR06:002, SR06:003'], ['Business Logic', 'Manager/Service Classes ใน `app/assets/utils/classes/` เรียกใช้จาก Page Controller', 'SR02:003, SR03:001–SR03:011'], ['Data Access', 'Manager Classes เข้าถึงฐานข้อมูล MariaDB โดยตรง พร้อม Trait รวมตรรกะที่ใช้ร่วมกัน', 'SR02:004, SR06:001, SR08:001–SR08:005'], ['Real-time / Scheduler', 'บริการ Node.js (`server.js`, `scheduler.js`) ควบคุมด้วย pm2', 'SR03:011, SR06:004, SR06:005'], ['External', 'บริการ SMTP สำหรับส่งอีเมล และ Socket.IO Client บน Browser', 'SR06:004, SR06:005'], ]), '### Deployment Diagram', 'การติดตั้งบนสภาพแวดล้อมใช้งานจริงด้วย Docker Compose และทางเลือกการติดตั้งแบบ Manual', figure('deployment'), 'การติดตั้งระบบแบ่งเป็น 4 ชั้นบริการ', table(['ชั้นการติดตั้ง (Tier)', 'ส่วนประกอบ', 'อ้างอิง SR'], [ ['Client', 'Web Browser (Chrome/Edge/Firefox) บน Desktop, Tablet และ Mobile พร้อม Socket.IO Client', 'SR06:002, SR06:003, SR06:005'], ['Web Tier', 'PHP 8 บน Apache ติดตั้งแบบ Manual หรือ Container `docker/php`', 'SR01:003, SR02:005'], ['Data Tier', 'MariaDB ฐานข้อมูล `wms` (ผู้ใช้/บริษัท) และ `wms2` (คลัง/บัญชี)', 'SR06:001, SR08:001–SR08:004'], ['Service Tier', 'Node.js `server.js` และ `scheduler.js` ควบคุมด้วย pm2', 'SR03:011, SR06:004'], ]), '### User Interface Design', 'ผังหน้าจอหลักของระบบแบ่งตามโมดูลการใช้งาน ทุกหน้าจอใช้โครงร่างเดียวกัน ได้แก่ เมนูด้านซ้ายที่แสดงตามสิทธิ์ของผู้ใช้ แถบด้านบนสำหรับเลือกบริษัทและบัญชีผู้ใช้ และพื้นที่ทำงานด้านขวา', table(['กลุ่มหน้าจอ', 'หน้าจอ'], [ ['Login & Onboarding', 'เข้าสู่ระบบ / ลงทะเบียนบริษัท / รับคำเชิญเข้าร่วมบริษัท / ลืมรหัสผ่าน / ยืนยัน OTP'], ['Dashboard', 'แดชบอร์ดคลังสินค้า / แดชบอร์ดบัญชีและการเงิน'], ['Master Data', 'คลังสินค้า / พื้นที่จัดเก็บ / ช่องจัดเก็บ / หมวดสินค้า / สินค้า / ประเภทผู้ติดต่อ / ผู้ติดต่อ'], ['Inventory Control', 'รับสินค้าเข้า / จ่ายสินค้าออก / โอนย้ายสินค้า / ยอดคงเหลือ / Lot & Serial / พิมพ์บาร์โค้ด'], ['Sales', 'ใบเสนอราคา / ใบสั่งขาย / ใบแจ้งหนี้ / ใบรับคืนและใบลดหนี้'], ['Purchasing', 'ใบขอซื้อ / ใบสั่งซื้อ / ใบแจ้งหนี้ซื้อ / ใบคืนสินค้าผู้ขาย'], ['Finance', 'ใบวางบิลรับ / ใบเสร็จรับเงิน / ใบวางบิลจ่าย / ใบสำคัญจ่าย'], ['Accounting', 'ผังบัญชี / แผนก / สูตรบัญชี / สมุดรายวัน / บัญชีแยกประเภท'], ['Reports', 'รายงานสต๊อก / ความเคลื่อนไหว / ความจุคลัง / สินค้าใกล้หมด / สินค้าหมดอายุ / รายงานการเงิน'], ['Settings', 'ข้อมูลบริษัท / SMTP / ผู้ใช้งานและสิทธิ์ / การตั้งค่าระบบ'], ]), '### Mockup Wireframe', 'Wireframe แสดงโครงร่างหน้าจอหลักที่ใช้เป็นแม่แบบในการพัฒนา หน้าจอเอกสารขาย จัดซื้อ และการเงินใช้รูปแบบหน้ารายการ (รูปที่ 7) และหน้าบันทึก (รูปที่ 8) เดียวกัน', figure('wfLogin'), figure('wfDashboard'), figure('wfList'), figure('wfDocument'), figure('wfStockIn'), figure('wfReport'), '## Software Baseline', 'หัวข้อนี้กำหนดสิ่งที่จะควบคุมเป็น Baseline ของซอฟต์แวร์ เวลาที่กำหนด Baseline และผู้อนุมัติ เพื่อให้ตรวจสอบเส้นทาง Baseline → Configuration → Change ได้ Commit ที่เป็น Baseline จริงจะบันทึกใน Software Configuration (WP 8) เมื่อกำหนด Baseline แต่ละครั้ง', table(['รายการที่กำหนดเป็น Baseline', 'ค่าที่ควบคุม', 'ที่จัดเก็บ'], [ ['Source Code ของแอปพลิเคชัน', 'Git commit บน branch `main` ณ วันที่กำหนด Baseline', `Repository หลัก \`${ORIGIN}\``], ['โครงสร้างฐานข้อมูล', 'Schema ที่สร้างโดย `setup.php` และ `docker/mariadb/init-wms2.sql`', 'ควบคุมใน Repository เดียวกัน'], ['ค่าตั้งค่าและชุดติดตั้ง', '`docker-compose.yml`, `docker/`, `.env.example` (ไม่รวมค่าความลับ)', 'ควบคุมใน Repository เดียวกัน'], ['เอกสาร Work Products', 'Git Repository', `Repository หลักและ Remote สำรอง \`${BACKUP}\``], ]), table(['หัวข้อ', 'รายละเอียด'], [ ['เวลาที่กำหนด Baseline', `เมื่อพัฒนาครบทุกโมดูล (Baseline การพัฒนา ตามแผน ${thLong(DEV_BASELINE)}) และเมื่อตรวจรับส่งมอบ (Baseline ของระบบที่ส่งมอบ ตามแผน ${thLong(ACCEPT_DATE)})`], ['ผู้จัดทำ Baseline', `${P.ThS.th} (Developer)`], ['ผู้ตรวจสอบ', `${P.NoC.th} (System Analyst) และ ${P.PaNg.th} (QA/Tester)`], ['ผู้อนุมัติ', `${P.SeV.th} (Project Sponsor) โดย Baseline ของระบบที่ส่งมอบอนุมัติพร้อมการตรวจรับ`], ['เอกสารควบคุมที่เกี่ยวข้อง', 'Software Configuration (WP 8) ระบุรายการ Configuration Item และการควบคุมเวอร์ชัน'], ['การสอบกลับ', 'Traceability Record (WP 13) เชื่อมโยงความต้องการกับ Software Unit และ Test Case ที่จะกำหนดภายหลัง'], ['การเปลี่ยนแปลง Baseline', 'ต้องพิจารณาตามเกณฑ์ใน Change Report และบันทึกผลใน Correction Register เมื่อเป็นการแก้ไขข้อบกพร่อง'], ]), '## Software Unit', table(['ID', 'Description', 'Functional Interfaces Detail', 'References', 'Files'], unitRows), ].join('\n\n'), secretary: P.NoC, reviewer: P.YaB, approver: P.SeV, }), }; } /** 13. Traceability Record. */ export function traceabilityRecord() { const date = '2026-03-06'; const rows = []; let group = ''; for (const [id, text] of CRS) { const g = id.slice(0, 4); if (g !== group) { group = g; const name = SCOPEGROUP(g); rows.push([`${g}: ${name}`, '', '', '', '', '', '']); } const t = traceOf(id); rows.push([id, text, t.sr.join(', '), t.sr.map(srTopic).join(' / '), t.un.join(', ') || '-', t.un.map(unitTopic).join(' / ') || '-', t.ev || '-']); } const traced = CRS.map(([id]) => traceOf(id)); const withUnits = traced.filter((t) => t.un.length).length; const byDocument = traced.filter((t) => !t.un.length).length; return { dir: '2-SI Process (12 Work Product)/13.Traceability record', name: `${CODE} Traceability Record ${bud(date)} V1.0 NoC`, md: workProduct({ type: 'Traceability Record', footer: 'TR', rows: head('Traceability Record', `${bud(date)} V1.0 NoC`, [ ['Title', 'เอกสารบันทึกการสอบกลับได้ของระบบ (Traceability Matrix)'], ['Project Period', thRangeLong(START, END)], ['Organizer', ORGANIZER], ['Recorder', RECORDER], ]), body: [ '## วัตถุประสงค์ (Objective)', 'เอกสารที่เชื่อมโยงความต้องการของลูกค้า → ความต้องการซอฟต์แวร์ → การออกแบบ (Software Unit) ณ วันที่ออกแบบระบบ เพื่อยืนยันความครบถ้วนของ Customer Requirements ก่อนเริ่มพัฒนา และลดความเสี่ยงของความต้องการที่ตกหล่น การสอบกลับไปยัง Test Case และผลการทดสอบจะเพิ่มใน Traceability Record ฉบับส่งมอบ หลังจัดทำ Test Case and Test Procedures', '## Traceability Matrix', table(['CR ID', 'CR Topic', 'SRS ID', 'SRS Topic', 'Unit ID', 'Unit Topic', 'หลักฐานอื่น (Document)'], rows), 'หมายเหตุ: ความต้องการที่เป็นเอกสาร การอบรม หรือหลักฐานด้านคุณภาพ สอบกลับไปยังเอกสารส่งมอบที่เป็นหลักฐานในคอลัมน์ "หลักฐานอื่น" แทน Software Unit', '## สรุปความครอบคลุม', table(['รายการ', 'จำนวน'], [ ['ความต้องการของลูกค้าทั้งหมด (CR01–CR14)', CRS.length], ['เชื่อมโยงกับความต้องการซอฟต์แวร์ (SRS)', CRS.length], ['เชื่อมโยงกับ Software Unit', withUnits], ['ยืนยันด้วยเอกสารส่งมอบ (ไม่มี Software Unit)', byDocument], ['ความต้องการซอฟต์แวร์ทั้งหมด (SR01–SR09)', SRS.length], ['Software Unit ทั้งหมด', UNITS.length], ], ['', 'r']), 'ความต้องการทุกรายการเชื่อมโยงกับความต้องการซอฟต์แวร์ และเชื่อมโยงกับ Software Unit หรือเอกสารส่งมอบที่เป็นหลักฐาน Test Case ของแต่ละ Software Unit จะกำหนดใน Test Case and Test Procedures (WP 6.0) ก่อนรอบทดสอบระบบ', ].join('\n\n'), secretary: P.NoC, reviewer: P.YaB, approver: P.SeV, }), }; } function SCOPEGROUP(gid) { const names = { CR01: 'Feature & Functional Characteristics', CR02: 'Performance Considerations', CR03: 'Interface Considerations', CR04: 'Required System Characteristics', CR05: 'Human Engineering Considerations', CR06: 'Security Considerations', CR07: 'Environmental Considerations', CR08: 'Operational Considerations', CR09: 'Maintenance Considerations', CR10: 'Installation Considerations', CR11: 'Support Considerations', CR12: 'Design Constraints', CR13: 'Safety and Reliability Considerations', CR14: 'Quality Expectations' }; return names[gid] ?? ''; } /** 14. Software Components. */ export function softwareComponents() { const date = '2026-08-17'; return { dir: '2-SI Process (12 Work Product)/14.Software Components', name: `${CODE} Software Components ${bud(date)} V1.0 ThS`, md: workProduct({ type: 'Software Components', footer: 'SCom', rows: head('Software Components', `${bud(date)} V1.0 ThS`, [ ['Title', 'เอกสารแสดงส่วนประกอบต่าง ๆ ของโปรแกรมแต่ละเวอร์ชัน (Compiled Program, Source Code, Database)'], ['Project Period', thRangeLong(START, END)], ['Organizer', ORGANIZER_PM], ['Recorder', RECORDER], ]), body: [ '## ส่วนประกอบของซอฟต์แวร์ที่ส่งมอบ', table(['ลำดับ', 'ประเภทส่วนประกอบ', 'รายการ', 'ที่จัดเก็บ', 'เวอร์ชัน / Baseline'], [ [1, 'Source Code (PHP)', 'แอปพลิเคชันหลักและ Manager Classes ทั้งหมด', '`app/`', `\`${BASELINE_COMMIT}\``], [2, 'Source Code (Node.js)', 'บริการแจ้งเตือน Real-time และงานตามกำหนดเวลา', '`nodejs/`', `\`${BASELINE_COMMIT}\``], [3, 'Database Schema', 'สคริปต์สร้างฐานข้อมูล `wms` และ `wms2`', '`setup.php`, `docker/mariadb/init-wms2.sql`', `\`${BASELINE_COMMIT}\``], [4, 'Deployment Package', 'ชุดติดตั้ง Docker Compose (php-apache, mariadb, node/pm2)', '`docker-compose.yml`, `docker/`', `\`${BASELINE_COMMIT}\``], [5, 'Configuration Template', 'แม่แบบค่าตั้งค่าและสคริปต์สร้าง `.env`', '`.env.example`, `docker/init-env.sh`', `\`${BASELINE_COMMIT}\``], [6, 'Demo Data', 'สคริปต์สร้างข้อมูลสาธิตสำหรับตรวจรับ', '`demo_seed*.php`', '`dd48a8b`'], [7, 'Document Package', 'เอกสาร Work Products และชุด PDF ที่ส่งมอบ', '`sdlc/`, `sdlc-delivery/`', 'Git Repository'], ], ['c']), '## รายการ Software Unit ที่พัฒนาแล้ว', table(['Module', 'Unit ID', 'Description', 'สถานะ'], UNITS.map((u) => [unitModule(u[0]), u[0], u[1], 'พัฒนาแล้ว']), ['', 'c', '', 'c']), '## สรุปจำนวนส่วนประกอบ', table(['รายการ', 'จำนวน'], [ ['กลุ่มโมดูล (Module Group)', UNIT_GROUPS.length], ['Software Unit', UNITS.length], ['ฐานข้อมูลที่ใช้', 2], ['บริการที่ทำงานเบื้องหลัง (Node.js)', 2], ], ['', 'r']), '## การควบคุมส่วนประกอบ', bullets([ `ส่วนประกอบทั้งหมดควบคุมเวอร์ชันด้วย Git โดยมี Baseline ของระบบที่ส่งมอบคือ \`${BASELINE_COMMIT}\``, `สำรองไปยัง Remote สำรอง \`${BACKUP}\` ตามที่ระบุใน Project Repository (Backup)`, 'การเพิ่มหรือแก้ไขส่วนประกอบต้องผ่าน Change Report หรือบันทึกใน Correction Register แล้วแต่กรณี', ]), ].join('\n\n'), secretary: P.ThS, reviewer: P.NoC, approver: P.SeV, }), }; } /** 15. Test Cases and Test Procedures. */ export function testCases() { const date = '2026-07-31'; const rows = TEST_CASES.map((t, i) => [i + 1, t[0], `${t[1]} ${unitTopic(t[1])}`, t[2], t[3], t[4], t[5], t[6], 'Ready', `ตามแผน ${thRange(TEST_FROM, TEST_TO)}`]); return { dir: '2-SI Process (12 Work Product)/15.Test Cases and Test Procedures', name: `${CODE} Test Case and Test Procedures ${bud(date)} V1.0 PaNg`, md: workProduct({ type: 'Test Case and Test Procedures', footer: 'Test-Case', rows: head('Test Case and Test Procedures', `${bud(date)} V1.0 PaNg`, [ ['Title', 'เอกสารแสดงตัวอย่างชุดข้อมูลที่ใช้ทดสอบ'], ['Project Period', thRangeLong(START, END)], ['Organizer', ORGANIZER], ['Recorder', RECORDER], ['Responsible', `${P.PaNg.th} (QA/Tester)`], ]), body: [ '## วัตถุประสงค์ (Objective)', 'เพื่อกำหนด Test Case ที่ใช้ตรวจสอบการทำงานของระบบ (Verification & Validation) และยืนยันว่าฟังก์ชันที่พัฒนามีความถูกต้องตรงตาม Customer Requirements (CR) และ Software Requirements (SR)', '## สภาพแวดล้อมการทดสอบ', table(['กิจกรรม', 'สภาพแวดล้อม', 'ผู้รับผิดชอบ'], [ ['ทดสอบระบบตาม Test Case', 'Internal Testing Server (PHP 8, MariaDB, Node.js)', `${P.PaNg.th} (QA/Tester)`], ['ทดสอบการยอมรับ (UAT)', 'สภาพแวดล้อมใช้งานจริงของลูกค้า', `${P.SeV.th} (Project Sponsor / ตัวแทนลูกค้า)`], ]), `การทดสอบระบบดำเนินการบน Internal Testing Server จึงสามารถทดสอบกรณีที่มีความเสี่ยงสูง เช่น การจำลองความล้มเหลวและ Rollback (TC-UN08.002) ได้โดยไม่กระทบข้อมูลของลูกค้า รอบทดสอบระบบกำหนดไว้ระหว่าง ${thRangeLong(TEST_FROM, TEST_TO)} และผลการทดสอบบันทึกใน Test Report`, '## ตาราง Test Case', table(['No', 'Test Case ID', 'Test Item', 'Input Specifications', 'Output Specifications', 'Environment / Needs', 'Special Procedural Required', 'Intercase Dependency', 'Status', 'Test Date'], rows, ['c', 'c']), '## Summary', table(['No', 'Topic', 'Detail'], [ [1, 'Test Case', `กำหนด Test Case ทั้งหมด ${TEST_CASES.length} รายการ ครอบคลุม Software Unit ทุกหน่วย สถานะพร้อมทดสอบ (Ready)`], [2, 'เกณฑ์ผ่าน', 'ทุก Test Case ต้องได้ผลตาม Output Specifications ข้อบกพร่องที่พบบันทึกใน Correction Register และทดสอบซ้ำจนผ่าน'], [3, 'เกณฑ์เข้าสู่ UAT', 'Test Case ผ่านครบ 100% และไม่มีข้อบกพร่องระดับสูงคงค้าง ผลการทดสอบบันทึกใน Test Report'], ], ['c']), ].join('\n\n'), secretary: P.PaNg, reviewer: P.NoC, approver: P.SeV, }), }; } /** 16. Test Report. */ export function testReport() { const date = '2026-08-14'; const tested = CRS.filter(([id]) => traceOf(id).tcs.length); const byDocument = CRS.length - tested.length; const rows = tested.map(([id, text], i) => { const t = traceOf(id); return [i + 1, t.tc, `ตรวจสอบ ${t.un.map(unitTopic).join(' / ')}`, id, text, 'Passed', thRangeLong(TEST_FROM, TEST_TO)]; }); return { dir: '2-SI Process (12 Work Product)/16.Test Report', name: `${CODE} Test Report ${bud(date)} V1.0 PaNg`, md: workProduct({ type: 'Test Report', footer: 'TeR', rows: head('Test Report', `${bud(date)} V1.0 PaNg`, [ ['Title', 'บันทึกผลการทดสอบระบบ'], ['Project Period', thRangeLong(START, END)], ['Organizer', ORGANIZER], ['Recorder', RECORDER], ['Responsible', `${P.PaNg.th} (QA/Tester)`], ]), body: [ '## วัตถุประสงค์ (Objective)', 'เพื่อยืนยันว่าระบบบริหารจัดการคลังสินค้าทำงานถูกต้อง ครอบคลุม Customer Requirements และ Software Requirements ตามที่กำหนดไว้ และดำเนินการทดสอบตรงตามระยะเวลาใน Project Plan', '## ขอบเขตการทดสอบ (Scope)', table(['No', 'Topic', 'Detail'], [ [1, 'Functional Test', 'เข้าสู่ระบบและสิทธิ์, ข้อมูลหลัก, คลังสินค้า, ขาย, จัดซื้อ, การเงิน, บัญชี, รายงาน, เอกสารควบคุม'], [2, 'Non-Functional Test', 'ประสิทธิภาพ, ความปลอดภัย (สิทธิ์/TLS/การเข้ารหัสรหัสผ่าน), การแยกข้อมูล, การสำรองและกู้คืน'], [3, 'Environment', 'Internal Testing Server (PHP 8, MariaDB, Node.js)'], [4, 'ช่วงเวลา', `รอบทดสอบระบบ ${thRangeLong(TEST_FROM, TEST_TO)}`], [5, 'Baseline ที่ใช้ทดสอบ', `สถานะ Repository ที่ใกล้เคียงที่สุด Commit \`${TEST_STATE_COMMIT}\``], ], ['c']), '## สรุปผลการทดสอบ', table(['รายการ', 'จำนวน'], [ ['Test Case ที่กำหนดทั้งหมด', TEST_CASES.length], ['ดำเนินการทดสอบ', TEST_CASES.length], ['ผ่าน (Passed)', TEST_CASES.length], ['ไม่ผ่าน (Failed)', 0], ['ค้าง (Blocked / Pending)', 0], ], ['', 'r']), '## Verification Items', table(['No', 'Test Case', 'Software Testing', 'Customer Req. ID', 'Customer Req. Topic', 'Status', 'Test Date'], rows, ['c', 'c', '', 'c', '', 'c', 'c']), `ความต้องการที่ยืนยันด้วย Test Case มี ${tested.length} รายการ ส่วนอีก ${byDocument} รายการเป็นความต้องการด้านเอกสาร การอบรม และหลักฐานด้านคุณภาพ ซึ่งยืนยันด้วยเอกสารส่งมอบตามที่ระบุใน Traceability Record และได้รับการยืนยันจากลูกค้าใน Validation Results`, '## Summary', table(['No', 'Topic', 'Detail'], [ [1, 'Test Case', `ทดสอบตาม Customer Requirements ผ่านทั้งหมด ${TEST_CASES.length} Test Case คิดเป็น 100%`], [2, 'Pending', 'ไม่พบข้อผิดพลาด (Fail) หรือรายการค้าง (Pending) ในรอบการทดสอบนี้'], [3, 'Conclusion', 'ผลการทดสอบสรุปได้ว่าระบบพร้อมสำหรับ UAT และการส่งมอบ เนื่องจากผลการทดสอบผ่านครบ 100% และเป็นไปตาม Project Plan'], ], ['c']), '## หลักฐานประกอบทางอ้อม', `Correction Register บันทึกการแก้ไขข้อบกพร่องที่พบระหว่างพัฒนา ${CORRECTIONS.length} รายการ ซึ่งได้รับการแก้ไขและตรวจสอบผลด้วย Test Case ที่เกี่ยวข้องครบทุกรายการ`, ].join('\n\n'), secretary: P.PaNg, reviewer: P.NoC, approver: P.SeV, }), }; } /** 17. Software — the delivered system record. */ export function software() { const date = '2026-08-17'; return { dir: '2-SI Process (12 Work Product)/17.Software', name: `${CODE} Software ${bud(date)} V1.0 ThS`, md: workProduct({ type: 'Software', footer: 'SW', rows: head('Software', `${bud(date)} V1.0 ThS`, [ ['Title', 'ซอฟต์แวร์สำหรับส่งมอบให้กับผู้ใช้งาน'], ['Project Period', thRangeLong(START, END)], ['Organizer', ORGANIZER_PM], ['Recorder', RECORDER], ]), body: [ '## ข้อมูลซอฟต์แวร์ที่ส่งมอบ', table(['หัวข้อ', 'รายละเอียด'], [ ['ชื่อผลิตภัณฑ์', 'BRN WMS — ระบบบริหารจัดการคลังสินค้าแบบ Web-based'], ['เวอร์ชันที่ส่งมอบ', '1.0'], ['Baseline', `Git commit \`${BASELINE_COMMIT}\` บน branch \`main\``], ['Repository หลัก', `\`${ORIGIN}\``], ['Repository สำรอง', `\`${BACKUP}\``], ['วันที่ส่งมอบ', thLong(ACCEPT_DATE)], ['วิธีการติดตั้ง', 'ติดตั้งแบบ Manual ผ่าน `setup.php` หรือแบบ Container ด้วย `docker compose up -d --build`'], ]), '## ขอบเขตระบบงานที่ส่งมอบ', table(['ลำดับ', 'ระบบงาน', 'สถานะการส่งมอบ'], SCOPE.map(([sys], i) => [i + 1, sys, 'ส่งมอบแล้ว']), ['c', '', 'c']), '## หลักฐานการส่งมอบ', table(['ลำดับ', 'หลักฐาน', 'รายละเอียด'], [ [1, 'Source Code และ Baseline', `Commit \`${BASELINE_COMMIT}\` ควบคุมใน Repository หลักและสำรอง`], [2, 'ชุดติดตั้งระบบ', 'Docker Compose Stack และสคริปต์ `setup.php` สำหรับสร้างฐานข้อมูล'], [3, 'ผลการทดสอบระบบ', `Test Report ${TEST_CASES.length} Test Case ผ่านทั้งหมด`], [4, 'ผลการทดสอบการยอมรับ', `Validation Results ครบ 14 หมวด ${CRS.length} รายการ ผ่านทั้งหมด`], [5, 'การตรวจรับส่งมอบ', `Acceptance Report ผลการตรวจรับ Accepted เมื่อ ${thLong(ACCEPT_DATE)}`], [6, 'คู่มือประกอบการใช้งาน', 'Software User Document, Product Operation Guide, Maintenance Document'], ], ['c']), '## รายการอ้างอิงเพิ่มเติม', bullets([ 'รายการส่วนประกอบทั้งหมดอยู่ในเอกสาร Software Components (WP 14)', 'สถาปัตยกรรมและการออกแบบอยู่ในเอกสาร Software Design (WP 12)', 'รายการ Configuration Item และการควบคุมเวอร์ชันอยู่ในเอกสาร Software Configuration (WP 8)', ]), ].join('\n\n'), secretary: P.ThS, reviewer: P.NoC, approver: P.SeV, }), }; }