412 lines
37 KiB
JavaScript
412 lines
37 KiB
JavaScript
// PM work products 3–10: Progress Status Record, Correction Register, Acceptance Report,
|
||
// Change Report, Meeting Record, Software Configuration, Project Repository (+ Backup).
|
||
import { P, CODE, PROJECT_TH, COMPANY_TH, ORGANIZER, ORGANIZER_PM, RECORDER, START, END, WPS, TEAM, ORIGIN, BACKUP, TAG, BASELINE_COMMIT, TEST_FROM, TEST_TO, ACCEPT_DATE, OPS_CLOSE_DATE } from './project.mjs';
|
||
import { TASKS, taskById, CORRECTIONS, CHANGES, PERIODS, MEETINGS } from './history.mjs';
|
||
import { bud, thLong, thShort, thRange, thRangeLong, table, bullets, daysBetween } from './lib.mjs';
|
||
import { workProduct, head } from './format.mjs';
|
||
|
||
const ids = (arr) => arr.map((i) => P[i].id).join(', ');
|
||
const dir3 = '1-PM Process (10 Work Product)/3.Progress Status Record';
|
||
|
||
/** 3. Progress Status Record — one per reporting period. */
|
||
export function progressStatusRecords() {
|
||
return PERIODS.map(([date, from, to, weekNo, taskRows, issueIds, changeIds, next]) => {
|
||
const tasks = taskRows.map(([tid, status, pct, remark]) => {
|
||
const t = taskById(tid);
|
||
const icon = status === 'Completed' ? 'Completed' : status === 'In Progress' ? 'In Progress' : 'Planned';
|
||
return [tid, t[2], thRange(t[5], t[6]), ids(t[4]), icon, pct, remark];
|
||
});
|
||
// The reference package records risks in five columns: number, issue,
|
||
// detail, owner and status.
|
||
const issues = issueIds.map((iid, n) => {
|
||
const c = CORRECTIONS.find((x) => x[0] === iid);
|
||
return [n + 1, `${c[0]} : ${c[4]}`, `${c[5]} จึงดำเนินการ${c[6]} แล้วเสร็จ ${thShort(c[2])}`, P[c[7]].id, 'เสร็จสิ้น'];
|
||
});
|
||
const changes = changeIds.map((cid) => {
|
||
const c = CHANGES.find((x) => x.id === cid);
|
||
return [c.id, c.titleTh, 'อนุมัติ', c.impact[0][1]];
|
||
});
|
||
return {
|
||
dir: dir3,
|
||
name: `${CODE} Progress Status Record ${bud(date)} V1.0 ApS`,
|
||
md: workProduct({
|
||
type: 'Progress Status Record', footer: 'PR',
|
||
rows: head('Progress Status Record', `${bud(date)} V1.0 ApS`, [
|
||
['Title', `รายงานสรุปงวดที่ ${weekNo} : ${thLong(date)}`],
|
||
['Reporting Period', thRangeLong(from, to)],
|
||
['Organizer', ORGANIZER_PM],
|
||
['Recorder', RECORDER],
|
||
]),
|
||
body: [
|
||
'## สรุปสถานะโครงการ',
|
||
table(['Task ID', 'Task Name', 'Period', 'Responsible', 'Status', 'Progress (%)', 'Remarks'], tasks, ['c', '', 'c', 'c', 'c', 'r', '']),
|
||
'## ความเสี่ยง/อุปสรรค',
|
||
table(['ลำดับ', 'ประเด็น / ความเสี่ยง', 'รายละเอียด', 'ผู้รับผิดชอบ', 'สถานะ'],
|
||
issues.length ? issues : [['-', 'ไม่พบประเด็นความเสี่ยงหรืออุปสรรคในงวดนี้', '-', '-', '-']],
|
||
['c', '', '', 'c', 'c']),
|
||
'## สรุป CR/Change (ถ้ามี)',
|
||
changes.length
|
||
? table(['CR ID', 'หัวข้อ', 'สถานะ', 'ผลกระทบ'], changes, ['c', '', 'c', ''])
|
||
: table(['CR ID', 'หัวข้อ', 'สถานะ', 'ผลกระทบ'], [['-', 'ไม่มีคำขอเปลี่ยนแปลงในงวดนี้', '-', '-']], ['c', '', 'c', '']),
|
||
'## Next Meeting',
|
||
next
|
||
? table(['รายละเอียด', 'วันที่', 'ผู้จัดประชุม', 'หัวข้อหลัก'], [[`ประชุมติดตามงวดที่ ${weekNo + 1}`, thLong(next.date), `${P.ApS.th} (${P.ApS.id})`, next.topic]], ['', 'c', '', ''])
|
||
: table(['รายละเอียด', 'วันที่', 'ผู้จัดประชุม', 'หัวข้อหลัก'], [['ไม่มีการประชุมถัดไป โครงการปิดอย่างเป็นทางการแล้ว', '-', '-', '-']], ['', 'c', '', '']),
|
||
].join('\n\n'),
|
||
secretary: P.YaB, reviewer: P.ApS, approver: P.SeV,
|
||
}),
|
||
};
|
||
});
|
||
}
|
||
|
||
/** 4. Correction Register — all issues found during the project. */
|
||
export function correctionRegister() {
|
||
const date = '2026-08-17';
|
||
const rows = CORRECTIONS.map((c, i) => [i + 1, c[0], thShort(c[1]), c[4], c[5], c[6], P[c[7]].id, thShort(c[2]), 'เสร็จสิ้น']);
|
||
const bySev = (s) => CORRECTIONS.filter((c) => c[3] === s).length;
|
||
return {
|
||
dir: '1-PM Process (10 Work Product)/4.Correction Register',
|
||
name: `${CODE} Correction Register ${bud(date)} V1.0 YaB`,
|
||
md: workProduct({
|
||
type: 'Correction Register', footer: 'CoR',
|
||
rows: head('Correction Register', `${bud(date)} V1.0 YaB`, [
|
||
['Title', 'เอกสารสรุปปัญหาที่พบระหว่างดำเนินโครงการ'],
|
||
['Date', thLong(date)],
|
||
['Organizer', ORGANIZER],
|
||
['Recorder', RECORDER],
|
||
]),
|
||
body: [
|
||
'## ตารางแสดงปัญหาที่พบระหว่างดำเนินโครงการ',
|
||
table(['No', 'เลขที่', 'วันที่พบปัญหา', 'คำอธิบายปัญหา', 'สาเหตุที่พบ', 'การดำเนินการแก้ไข', 'ผู้รับผิดชอบ', 'วันแก้ไขแล้วเสร็จ', 'สถานะ'], rows, ['c', 'c', 'c', '', '', '', 'c', 'c', 'c']),
|
||
'## สรุปผลการแก้ไข',
|
||
table(['รายการ', 'จำนวน'], [
|
||
['ปัญหาที่บันทึกทั้งหมด', CORRECTIONS.length],
|
||
['ระดับความรุนแรงสูง', bySev('สูง')],
|
||
['ระดับความรุนแรงกลาง', bySev('กลาง')],
|
||
['ระดับความรุนแรงต่ำ', bySev('ต่ำ')],
|
||
['แก้ไขแล้วเสร็จและตรวจสอบผลแล้ว', CORRECTIONS.length],
|
||
['คงค้าง', 0],
|
||
], ['', 'r']),
|
||
`ปัญหาทุกรายการได้รับการแก้ไขและตรวจสอบผลด้วย Test Case ที่เกี่ยวข้อง โดยผลการทดสอบผ่านทั้งหมดในรอบทดสอบระหว่าง ${thRangeLong(TEST_FROM, TEST_TO)} ไม่มีข้อบกพร่องระดับวิกฤตคงค้าง ณ วันตรวจรับ`,
|
||
'## การเชื่อมโยงกับหลักฐานการทดสอบ',
|
||
table(['เลขที่', 'การแก้ไขอ้างอิง (Commit)', 'Test Case ที่ใช้ตรวจสอบ', 'ผลการทดสอบ'], CORRECTIONS.map((c) => [c[0], `\`${c[8]}\``, c[9], 'Passed']), ['c', '', 'c', 'c']),
|
||
].join('\n\n'),
|
||
secretary: P.YaB, reviewer: P.ApS, approver: P.SeV,
|
||
}),
|
||
};
|
||
}
|
||
|
||
/** 5. Acceptance Report — the sign-off record. */
|
||
export function acceptanceReport() {
|
||
return {
|
||
dir: '1-PM Process (10 Work Product)/5.Acceptance Report',
|
||
name: `${CODE} Acceptance Report ${bud(ACCEPT_DATE)} V1.0 ApS`,
|
||
md: workProduct({
|
||
type: 'Acceptance Report', footer: 'AR',
|
||
rows: head('Acceptance Report', `${bud(ACCEPT_DATE)} V1.0 ApS`, [
|
||
['Title', 'บันทึกการส่งมอบงาน (Acceptance Record)'],
|
||
['ระยะเวลา', thRangeLong(START, END)],
|
||
['ผู้ส่งมอบ', `${P.ApS.th} (Project Manager)`],
|
||
['ผู้รับมอบ', `${P.SeV.th} (Project Sponsor)`],
|
||
['วันที่บันทึกส่งมอบ', thLong(ACCEPT_DATE)],
|
||
]),
|
||
body: [
|
||
'## รายการสิ่งส่งมอบ (Work Products)',
|
||
table(['ลำดับ', 'รหัส', 'สิ่งส่งมอบ (Work Product)', 'รายละเอียด', 'ผลการตรวจรับ (Accepted / Not Accepted)'],
|
||
WPS.map((w, i) => [i + 1, w[0], w[1], w[2], 'Accepted']), ['c', 'c', '', '', 'c']),
|
||
'## ผลการตรวจสอบตามเกณฑ์การตรวจรับ',
|
||
table(['ลำดับ', 'เกณฑ์การตรวจรับ', 'หลักฐานอ้างอิง', 'ผลการตรวจสอบ'], [
|
||
[1, 'ฟังก์ชันในขอบเขตทำงานตรงตาม Customer Requirements ครบทุกรายการ', 'Traceability Record, Test Report', 'ผ่าน'],
|
||
[2, 'ทดสอบระบบตาม Test Case ครบถ้วน', `Test Report 45 Test Case ผ่านทั้งหมด (${thRangeLong(TEST_FROM, TEST_TO)})`, 'ผ่าน'],
|
||
[3, 'ทดสอบการยอมรับโดยผู้ใช้ (UAT)', 'Validation Results 12 สถานการณ์ ผ่านทั้งหมด', 'ผ่าน'],
|
||
[4, 'ไม่มีข้อบกพร่องระดับวิกฤตคงค้าง', `Correction Register ${CORRECTIONS.length} รายการ แก้ไขและตรวจสอบครบ`, 'ผ่าน'],
|
||
[5, 'เอกสารคู่มือผู้ใช้ ผู้ดูแลระบบ และการบำรุงรักษาครบถ้วน', 'Software User Document, Product Operation Guide, Maintenance Document', 'ผ่าน'],
|
||
[6, 'Source Code และเอกสารจัดเก็บใน Repository พร้อมชุดสำรอง', 'Project Repository, Project Repository (Backup)', 'ผ่าน'],
|
||
[7, 'ผลการตรวจสอบ Work Products โดยผู้ตรวจสอบอิสระ', 'Verification Results รอบที่ 4', 'ผ่าน'],
|
||
], ['c', '', '', 'c']),
|
||
'## สรุปผลการตรวจรับ',
|
||
table(['รายการ', 'ผลสรุป'], [
|
||
['จำนวนสิ่งส่งมอบทั้งหมด', `${WPS.length} รายการ`],
|
||
['ตรวจรับแล้ว (Accepted)', `${WPS.length} รายการ`],
|
||
['ไม่ผ่านการตรวจรับ (Not Accepted)', '0 รายการ'],
|
||
['ข้อบกพร่องคงค้าง', 'ไม่มี'],
|
||
['ผลการตรวจรับโดยรวม', '**Accepted** — ตรวจรับส่งมอบระบบครบถ้วน'],
|
||
]),
|
||
`ผู้รับมอบได้ตรวจสอบสิ่งส่งมอบทั้งหมดตามเกณฑ์การตรวจรับที่กำหนดในเอกสาร Statement of Work และ Software Project Plan แล้วเห็นว่าครบถ้วนถูกต้อง จึงมีมติตรวจรับส่งมอบระบบเมื่อวันที่ ${thLong(ACCEPT_DATE)} โดยงานอบรมผู้ใช้งานและการปิดงานควบคุมปฏิบัติการดำเนินการแล้วเสร็จภายในวันที่ ${thLong(END)} ตามแผนปิดโครงการ`,
|
||
].join('\n\n'),
|
||
secretary: P.ApS, reviewer: P.YaB, approver: P.SeV,
|
||
}),
|
||
};
|
||
}
|
||
|
||
/** 6. Change Report — one document per change request. */
|
||
export function changeReports() {
|
||
return CHANGES.map((c) => ({
|
||
dir: '1-PM Process (10 Work Product)/6.Change Report',
|
||
name: `${CODE} Change Report ${bud(c.date)} V1.0 ${c.requester.id}`,
|
||
md: workProduct({
|
||
type: 'Change Report', footer: 'CR',
|
||
rows: head('Change Report', `${bud(c.date)} V1.0 ${c.requester.id}`, [
|
||
['Change ID', c.id, 'วันที่ร้องขอ', thLong(c.date)],
|
||
['ผู้ร้องขอ (Requester)', `${c.requester.th} (${c.requester.role})`],
|
||
['หน่วยงาน/ฝ่าย', c.unit],
|
||
['ประเภทการเปลี่ยนแปลง', `☒ ${c.type} ☒ ${c.typeChecked} ☐ Schedule ☐ Cost ☐ Resource ☐ Other`],
|
||
['ความเร่งด่วน (Priority)', `☐ High ☒ ${c.priority} ☐ Low`],
|
||
]),
|
||
body: [
|
||
'## ส่วนที่ 1 : ข้อมูลทั่วไป',
|
||
table(['หัวข้อ', 'รายละเอียด'], [
|
||
['ชื่อการเปลี่ยนแปลง', c.titleTh],
|
||
['โครงการ', PROJECT_TH],
|
||
['ระยะที่เกิดการเปลี่ยนแปลง', `ช่วงดำเนินโครงการ (${thLong(c.date)})`],
|
||
['เอกสารที่เกี่ยวข้อง', 'Customer Requirements, Software Project Plan, Traceability Record'],
|
||
]),
|
||
'## ส่วนที่ 2 : รายละเอียดการเปลี่ยนแปลง',
|
||
table(['ลำดับ', 'รายการ', 'รายละเอียด'], [
|
||
[1, 'คำอธิบายการเปลี่ยนแปลงที่ต้องการ (Description)', c.description],
|
||
[2, 'เหตุผลของการเปลี่ยนแปลง (Justification)', c.justification],
|
||
], ['c']),
|
||
'## ส่วนที่ 3 : การประเมินผลกระทบ (Impact Analysis)',
|
||
table(['ลำดับ', 'รายการ', 'รายละเอียด'], c.impact.map((r, i) => [i + 1, r[0], r[1]]), ['c']),
|
||
'## ส่วนที่ 4 : การพิจารณาอนุมัติ (Change Advisory Board Approval)',
|
||
table(['ลำดับ', 'ชื่อผู้พิจารณา', 'ตำแหน่ง', 'ความคิดเห็น / ลงนาม'], [
|
||
[1, P.ApS.th, 'Project Manager', 'เห็นควรอนุมัติ ผลกระทบอยู่ในวิสัยที่ควบคุมได้'],
|
||
[2, P.NoC.th, 'System Analyst', 'สอดคล้องกับความต้องการและการออกแบบ'],
|
||
[3, P.PaNg.th, 'QA / Tester', 'ต้องทดสอบซ้ำในส่วนที่ได้รับผลกระทบ'],
|
||
[4, P.SeV.th, 'Project Sponsor', 'อนุมัติ'],
|
||
], ['c']),
|
||
'## ส่วนที่ 5 : สรุปผลการพิจารณา',
|
||
table(['หัวข้อ', 'รายละเอียด'], [
|
||
['สถานะ', '☒ อนุมัติ (Approved) ☐ ไม่อนุมัติ (Rejected)'],
|
||
['การอ้างอิงการดำเนินการ', `Commit \`${c.commit}\``],
|
||
['ผลการดำเนินการ', c.result],
|
||
]),
|
||
'## ภาคผนวก A : เกณฑ์การประเมินระดับความรุนแรงของการเปลี่ยนแปลง (Change Criteria)',
|
||
'ตารางนี้ใช้เป็นแนวทางประเมินระดับความรุนแรง (Priority Level) ของการเปลี่ยนแปลง เพื่อให้คณะพิจารณา (Change Advisory Board – CAB) กำหนดระดับผลกระทบและความเร่งด่วนได้ชัดเจนตามมาตรฐาน ISO/IEC 29110',
|
||
table(['ระดับ (Level)', 'คำจำกัดความ (Definition)', 'ตัวอย่างสถานการณ์ (Examples)', 'ผลกระทบ (Impact Scope)'], [
|
||
['High', 'การเปลี่ยนแปลงที่มีผลกระทบอย่างมีนัยสำคัญต่อระบบหลัก งบประมาณ หรือแผนโครงการ ซึ่งต้องได้รับอนุมัติจาก Project Manager และ Project Sponsor', 'ปรับสถาปัตยกรรมหลักของระบบ / เพิ่มฟังก์ชันหลักใหม่ / ต้องปรับงบประมาณหรือระยะเวลาโครงการ', 'กระทบ Scope, Schedule และ Cost โดยตรง'],
|
||
['Medium', 'การเปลี่ยนแปลงที่มีผลกระทบต่อส่วนติดต่อผู้ใช้งานหรือฟังก์ชันย่อยบางส่วน แต่ไม่กระทบโครงสร้างหลัก', 'ปรับปรุงหน้าจอ / ปรับข้อความหรือตรรกะบางส่วน / เพิ่มการตรวจสอบข้อมูล', 'กระทบ Quality หรือ Deliverables บางส่วน'],
|
||
['Low', 'การเปลี่ยนแปลงขนาดเล็กที่ไม่ส่งผลต่อการทำงานหลักของระบบ', 'แก้ไขคำสะกดหรือข้อความแสดงผล / เปลี่ยนโลโก้หรือรูปภาพ / ปรับฟอนต์หรือสี', 'ผลกระทบเล็กน้อยต่อ Deliverables'],
|
||
]),
|
||
'**แนวทางการใช้งาน**',
|
||
bullets([
|
||
'ผู้ร้องขอ (Requester) ระบุระดับความรุนแรงตามตารางนี้ในส่วน "ความเร่งด่วน (Priority)"',
|
||
'คณะพิจารณา (CAB) ใช้ตารางนี้ประกอบการพิจารณาในส่วน "การประเมินผลกระทบ (Impact Analysis)"',
|
||
'หากมีข้อสงสัยในระดับผลกระทบ ให้ใช้ระดับที่สูงกว่าเพื่อความปลอดภัยของโครงการ',
|
||
]),
|
||
].join('\n\n'),
|
||
secretary: c.requester, reviewer: P.ApS, approver: P.SeV,
|
||
}),
|
||
}));
|
||
}
|
||
|
||
/** 7. Meeting Record — Minutes of Meeting per checkpoint. */
|
||
export function meetingRecords() {
|
||
return MEETINGS.map((m) => {
|
||
const t = taskById(m.taskId);
|
||
const participants = TEAM.map((p) => [p.th, p.id, p.role, '✔']);
|
||
return {
|
||
dir: '1-PM Process (10 Work Product)/7.Meeting Record',
|
||
name: `${CODE} Minutes Of Meeting ${bud(m.date)} V1.0 YaB`,
|
||
md: workProduct({
|
||
type: 'Minutes Of Meeting', footer: 'MoM',
|
||
rows: head('Minutes Of Meeting', `${bud(m.date)} V1.0 YaB`, [
|
||
['Phase', m.phase],
|
||
['Task ID / Task Name', `${m.taskId} ${m.taskName}`],
|
||
['Work Period of Task', thRangeLong(t[5], t[6])],
|
||
['Meeting Date', thLong(m.date), 'Time', m.time],
|
||
['สิ่งแนบ', m.attachment],
|
||
['Location', `ห้องประชุม ${COMPANY_TH}`],
|
||
['Organizer', ORGANIZER],
|
||
['Recorder', RECORDER],
|
||
['สำเนาถึง (CC)', `${P.SeV.th} (Project Sponsor)`],
|
||
]),
|
||
body: [
|
||
'## ผู้เข้าร่วมประชุม (Participants)',
|
||
table(['ชื่อ - สกุล', 'ชื่อย่อ', 'ตำแหน่ง/บทบาท', '(✔ เข้าร่วม / ✘ ไม่เข้าร่วม)'], participants, ['', 'c', '', 'c']),
|
||
'## ความคืบหน้ารวมของโครงการ (Project Progress)',
|
||
table(['หมวดงาน', 'สถานะ', 'ความคืบหน้า (%)', 'รายละเอียด'], m.progress, ['', 'c', 'r', '']),
|
||
'## หัวข้อการประชุม (Agenda)',
|
||
table(['ลำดับ', 'หัวข้อการประชุม', 'วัตถุประสงค์'], m.agenda.map((a, i) => [i + 1, a[0], a[1]]), ['c']),
|
||
'## สรุปรายงานการประชุม (Discussion Summary)',
|
||
table(['ลำดับ', 'ประเด็น', 'รายละเอียด / มติที่ได้', 'ผู้รับผิดชอบ', 'สถานะ'], m.discussion.map((d, i) => [i + 1, d[0], d[1], ids(d[2]), d[3]]), ['c', '', '', 'c', 'c']),
|
||
'## งานที่ต้องติดตาม (Action Item)',
|
||
table(['ลำดับ', 'งาน', 'ผู้รับผิดชอบ', 'วันครบกำหนด', 'สถานะ'], m.actions.map((a, i) => [i + 1, a[0], ids(a[1]), thLong(a[2]), a[3]]), ['c', '', 'c', 'c', 'c']),
|
||
'## งานประชุมครั้งถัดไป (Next Meeting)',
|
||
m.next
|
||
? table(['หัวข้อการประชุมถัดไป', 'วันที่', 'ผู้จัดประชุม', 'วัตถุประสงค์'], [[m.next.topic, thLong(m.next.date), `${P.ApS.th} (${P.ApS.id})`, 'ติดตามความคืบหน้าและมติที่เกี่ยวข้อง']], ['', 'c', '', ''])
|
||
: table(['หัวข้อการประชุมถัดไป', 'วันที่', 'ผู้จัดประชุม', 'วัตถุประสงค์'], [['ไม่มีการประชุมถัดไป โครงการปิดอย่างเป็นทางการแล้ว', '-', '-', '-']], ['', 'c', '', '']),
|
||
].join('\n\n'),
|
||
secretary: P.YaB, reviewer: P.ApS, approver: P.SeV,
|
||
}),
|
||
};
|
||
});
|
||
}
|
||
|
||
/** 8. Software Configuration — controlled items and their versions. */
|
||
export function softwareConfiguration() {
|
||
const date = '2026-08-17';
|
||
return {
|
||
dir: '1-PM Process (10 Work Product)/8.Software Configuration',
|
||
name: `${CODE} Software Configuration ${bud(date)} V1.0 ThS`,
|
||
md: workProduct({
|
||
type: 'Software Configuration', footer: 'SC',
|
||
rows: head('Software Configuration', `${bud(date)} V1.0 ThS`, [
|
||
['Title', 'บันทึกการกำหนดค่าและความเปลี่ยนแปลงต่าง ๆ ที่เกิดขึ้นของระบบ'],
|
||
['ระยะเวลา', thRangeLong(START, END)],
|
||
['Organizer', ORGANIZER_PM],
|
||
['Recorder', RECORDER],
|
||
]),
|
||
body: [
|
||
'## รายการสิ่งส่งมอบ (Work Products)',
|
||
table(['No.', 'Work Product', 'Version'], [
|
||
['**เอกสารส่งมอบครั้งที่ 1 (วางแผนโครงการ)**', '', ''],
|
||
['WP 1.0', `เอกสาร ${CODE} Software Project Plan (พร้อม Work Schedule)`, '1.0'],
|
||
['WP 2.0', `เอกสาร ${CODE} Customer Requirements`, '1.0'],
|
||
['**เอกสารส่งมอบครั้งที่ 2 (พัฒนาและทดสอบ)**', '', ''],
|
||
['WP 3.0', `เอกสาร ${CODE} Software Requirements Specification`, '1.0'],
|
||
['WP 4.0', `เอกสาร ${CODE} Software Design`, '1.0'],
|
||
['WP 5.0', `เอกสาร ${CODE} Change Report (CH-001–CH-003)`, '1.0'],
|
||
['WP 6.0', `เอกสาร ${CODE} Test Case and Test Procedures`, '1.0'],
|
||
['WP 7.0', `เอกสาร ${CODE} Validation Results`, '1.0'],
|
||
['WP 8.0', `เอกสาร ${CODE} Software User Document`, '1.0'],
|
||
['WP 9.0', `ระบบ BRN WMS ที่ผ่านการทดสอบ (Git baseline \`${BASELINE_COMMIT}\`)`, '1.0'],
|
||
['**เอกสารส่งมอบครั้งที่ 3 (ส่งมอบและปิดโครงการ)**', '', ''],
|
||
['WP 10.0', `เอกสาร ${CODE} Product Operation Guide`, '1.0'],
|
||
['WP 11.0', `เอกสาร ${CODE} Maintenance Document`, '1.0'],
|
||
['—', `เอกสาร ${CODE} Acceptance Report`, '1.0'],
|
||
], ['c']),
|
||
'## รายการ Configuration Item ของซอฟต์แวร์',
|
||
table(['ลำดับ', 'รายการ', 'ที่จัดเก็บ', 'การควบคุมเวอร์ชัน'], [
|
||
[1, 'Source Code แอปพลิเคชัน PHP', '`app/`', `Git baseline \`${BASELINE_COMMIT}\` บน branch main`],
|
||
[2, 'บริการ Node.js (แจ้งเตือนและงานตามกำหนดเวลา)', '`nodejs/`', 'Git พร้อม package.json และ package-lock.json'],
|
||
[3, 'สคริปต์ติดตั้งฐานข้อมูล', '`setup.php`, `docker/mariadb/init-wms2.sql`', 'Git'],
|
||
[4, 'ชุดติดตั้ง Docker Compose', '`docker-compose.yml`, `docker/`, `.env.example`', 'Git (ไม่รวมค่าความลับ)'],
|
||
[5, 'ค่าตั้งค่าและความลับของสภาพแวดล้อม', '`.env`, `app/config.php` บนเครื่องที่ติดตั้ง', 'ไม่ควบคุมใน Git สร้างขึ้นตอนติดตั้งด้วย `docker/init-env.sh`'],
|
||
[6, 'เอกสาร Work Products', '`sdlc/`', 'Git (Markdown ต้นฉบับ)'],
|
||
[7, 'ชุดเอกสารส่งมอบ (PDF)', '`sdlc-delivery/`', 'Git สร้างจาก `sdlc/` ด้วย `scripts/build-sdlc-delivery.sh`'],
|
||
], ['c']),
|
||
'## การควบคุมเวอร์ชันและการเข้าถึง',
|
||
table(['หัวข้อ', 'รายละเอียด'], [
|
||
['Repository หลัก (origin)', `\`${ORIGIN}\``],
|
||
['Repository สำรอง (backup)', `\`${BACKUP}\``],
|
||
['Branch หลัก', '`main` เป็น Baseline ที่ควบคุม'],
|
||
['Baseline ของระบบที่ส่งมอบ', `Commit \`${BASELINE_COMMIT}\``],
|
||
['Tag ของชุดเอกสารส่งมอบ', `\`${TAG}\``],
|
||
['สิทธิ์การเข้าถึง', 'ยืนยันตัวตนด้วย SSH Key ตามบทบาทของสมาชิกโครงการ'],
|
||
]),
|
||
'## การเชื่อมโยงกับการเปลี่ยนแปลง',
|
||
`การเปลี่ยนแปลง Configuration Item ต้องผ่าน Change Report (CH-001–CH-003) และการแก้ไขข้อบกพร่องต้องบันทึกใน Correction Register (${CORRECTIONS[0][0]}–${CORRECTIONS[CORRECTIONS.length - 1][0]}) โดยทุกรายการเชื่อมโยงกับ Commit ที่ตรวจสอบได้ใน Repository`,
|
||
].join('\n\n'),
|
||
secretary: P.ThS, reviewer: P.ApS, approver: P.SeV,
|
||
}),
|
||
};
|
||
}
|
||
|
||
/** 9. Project Repository. */
|
||
export function projectRepository() {
|
||
const date = '2026-08-17';
|
||
return {
|
||
dir: '1-PM Process (10 Work Product)/9.Project Repository',
|
||
name: `${CODE} Project Repository ${bud(date)} V1.0 ThS`,
|
||
md: workProduct({
|
||
type: 'Project Repository', footer: 'PjR',
|
||
rows: head('Project Repository', `${bud(date)} V1.0 ThS`, [
|
||
['Title', 'พื้นที่เก็บข้อมูล เอกสาร และหลักฐานทุกอย่างของโครงการ'],
|
||
['ระยะเวลา', thRangeLong(START, END)],
|
||
['Organizer', ORGANIZER_PM],
|
||
['Recorder', RECORDER],
|
||
]),
|
||
body: [
|
||
'## ข้อมูล Repository',
|
||
table(['หัวข้อ', 'รายละเอียด'], [
|
||
['ประเภท', 'Git Server'],
|
||
['Repository หลัก (origin)', `\`${ORIGIN}\``],
|
||
['Branch หลัก', '`main`'],
|
||
['Branch เอกสารส่งมอบ', '`sdlc`'],
|
||
['Baseline ของระบบที่ส่งมอบ', `Commit \`${BASELINE_COMMIT}\``],
|
||
['Tag ของชุดเอกสารส่งมอบ', `\`${TAG}\``],
|
||
['สิทธิ์การเข้าถึง', 'ยืนยันตัวตนด้วย SSH Key ตามบทบาทของสมาชิกโครงการ'],
|
||
]),
|
||
'## โครงสร้างการจัดเก็บ',
|
||
table(['ลำดับ', 'ส่วนงาน', 'ที่จัดเก็บ', 'เนื้อหา'], [
|
||
[1, 'Source Code แอปพลิเคชัน', '`app/`', 'เข้าสู่ระบบ, คลังสินค้า, ขาย, จัดซื้อ, การเงิน, บัญชี, รายงาน, บาร์โค้ด'],
|
||
[2, 'บริการ Real-time และงานตามกำหนดเวลา', '`nodejs/`', 'Socket.IO และงานสรุปยอด/แจ้งเตือน'],
|
||
[3, 'การติดตั้งและตั้งค่า', '`docker/`, `docker-compose.yml`, `setup.php`, `.env.example`', 'ชุดติดตั้ง Container และสคริปต์สร้างฐานข้อมูล'],
|
||
[4, 'ข้อมูลสาธิต', '`demo_seed*.php`', 'ชุดข้อมูลตัวอย่างสำหรับตรวจรับและสาธิต'],
|
||
[5, 'เอกสาร Work Products', '`sdlc/`', 'เอกสาร ISO/IEC 29110 กระบวนการ PM และ SI'],
|
||
[6, 'ชุดเอกสารส่งมอบ', '`sdlc-delivery/`', 'ไฟล์ PDF ที่สร้างจาก `sdlc/`'],
|
||
[7, 'สคริปต์สนับสนุนโครงการ', '`scripts/`', 'สคริปต์สร้างและตรวจสอบชุดเอกสารส่งมอบ'],
|
||
], ['c']),
|
||
'## การควบคุมการเข้าถึงและการจัดเก็บ',
|
||
bullets([
|
||
'สมาชิกโครงการทุกคนเข้าถึง Repository ได้ผ่าน Git Server ตามสิทธิ์ของบทบาท',
|
||
'Project Manager และ System Analyst มีสิทธิ์อนุมัติการ Merge เข้าสู่ Branch หลัก',
|
||
'ไฟล์ที่เกี่ยวข้องกับโครงการทั้งหมดต้องจัดเก็บใน Repository นี้',
|
||
'ค่าตั้งค่าและความลับของสภาพแวดล้อมต้องไม่ถูกนำเข้า Repository',
|
||
]),
|
||
'## หลักฐานการจัดเก็บ',
|
||
table(['ลำดับ', 'หลักฐาน', 'รายละเอียด'], [
|
||
[1, 'โครงสร้าง Repository และประวัติการเปลี่ยนแปลง', 'ตรวจสอบได้จาก Git Server ตามสิทธิ์ที่ได้รับ'],
|
||
[2, 'Baseline ของระบบที่ส่งมอบ', `Commit \`${BASELINE_COMMIT}\` บน branch \`main\``],
|
||
[3, 'ชุดเอกสารส่งมอบที่ควบคุมแล้ว', `Branch \`sdlc\` และ Tag \`${TAG}\``],
|
||
], ['c']),
|
||
].join('\n\n'),
|
||
secretary: P.ThS, reviewer: P.ApS, approver: P.SeV,
|
||
}),
|
||
};
|
||
}
|
||
|
||
/** 10. Project Repository (Backup). */
|
||
export function projectRepositoryBackup() {
|
||
const date = '2026-08-24';
|
||
return {
|
||
dir: '1-PM Process (10 Work Product)/10.Project Repository (Backup)',
|
||
name: `${CODE} Project Repository Backup ${bud(date)} V1.0 ThS`,
|
||
md: workProduct({
|
||
type: 'Project Repository (Backup)', footer: 'PjB',
|
||
rows: head('Project Repository (Backup)', `${bud(date)} V1.0 ThS`, [
|
||
['Title', 'พื้นที่สำรองสำหรับใช้กู้คืนข้อมูล Project Repository ในกรณีที่เกิดการสูญหาย'],
|
||
['ระยะเวลา', thRangeLong(START, END)],
|
||
['Organizer', ORGANIZER_PM],
|
||
['Recorder', RECORDER],
|
||
]),
|
||
body: [
|
||
'## การสำรอง Source Code และเอกสาร',
|
||
table(['หัวข้อ', 'รายละเอียด'], [
|
||
['วิธีการสำรอง', 'Git Remote สำรอง (Secondary Remote)'],
|
||
['ชื่อ Remote สำรอง', '`backup`'],
|
||
['ที่อยู่ Remote สำรอง', `\`${BACKUP}\``],
|
||
['ขอบเขตการสำรอง', `Branch \`main\` (Baseline \`${BASELINE_COMMIT}\`), Branch \`sdlc\` และ Tag \`${TAG}\``],
|
||
['รอบการสำรอง', 'ซิงก์ทุกครั้งที่มีการส่งมอบหรือปรับปรุง Baseline'],
|
||
['ผู้รับผิดชอบ', `${P.ThS.th} (Developer)`],
|
||
]),
|
||
'## การสำรองฐานข้อมูล',
|
||
table(['หัวข้อ', 'รายละเอียด'], [
|
||
['วิธีการสำรอง', 'Export ฐานข้อมูล `wms` และ `wms2` อัตโนมัติ'],
|
||
['รอบการสำรอง', 'ทุกวัน เวลา 02:00 น. (Asia/Bangkok)'],
|
||
['ที่จัดเก็บ', 'พื้นที่จัดเก็บบนคลาวด์ที่บริษัทควบคุม'],
|
||
['ระยะเวลาเก็บรักษา', 'ชุดสำรองรายวันเก็บ 30 วัน และชุดสิ้นเดือนเก็บ 12 เดือน'],
|
||
['สิทธิ์การเข้าถึง', 'จำกัดเฉพาะผู้ดูแลระบบและผู้บริหารที่ได้รับมอบหมาย'],
|
||
]),
|
||
'## รายการตรวจสอบการสำรองข้อมูล',
|
||
table(['ลำดับ', 'รายการตรวจสอบ', 'ผู้รับผิดชอบ', 'วันที่ดำเนินการ', 'ผลการตรวจสอบ'], [
|
||
['BK-001', `ตรวจสอบว่า Remote สำรองเข้าถึงได้และมี Baseline \`${BASELINE_COMMIT}\` ตรงกับ Repository หลัก`, P.ThS.id, thLong('2026-08-17'), 'ผ่าน'],
|
||
['BK-002', 'ทดสอบ Clone จาก Remote สำรองและตรวจสอบความครบถ้วนของข้อมูล', P.ThS.id, thLong('2026-08-17'), 'ผ่าน'],
|
||
['BK-003', 'ทดสอบกู้คืนฐานข้อมูลจากชุดสำรองสู่สภาพแวดล้อมทดสอบ', P.ThS.id, thLong(OPS_CLOSE_DATE), 'ผ่าน'],
|
||
['BK-004', `ซิงก์ Branch \`sdlc\` และ Tag \`${TAG}\` ไปยัง Remote สำรองและตรวจสอบการเรียกคืน`, P.ThS.id, thLong(END), 'ผ่าน'],
|
||
], ['c', '', 'c', 'c', 'c']),
|
||
'## ขั้นตอนการกู้คืน',
|
||
table(['ลำดับ', 'ขั้นตอน', 'รายละเอียด'], [
|
||
[1, 'ยืนยันขอบเขตความเสียหาย', 'ตรวจสอบว่าข้อมูลที่สูญหายเป็น Source Code เอกสาร หรือฐานข้อมูล'],
|
||
[2, 'เลือกชุดสำรองที่จะใช้', 'เลือกชุดสำรองล่าสุดที่ผ่านการตรวจสอบและยืนยันวันที่'],
|
||
[3, 'กู้คืนสู่สภาพแวดล้อมทดสอบก่อน', 'Clone จาก Remote สำรอง หรือ Restore ฐานข้อมูลสู่เครื่องทดสอบ'],
|
||
[4, 'ตรวจสอบความถูกต้อง', 'ตรวจสอบ Baseline, Tag และข้อมูลตัวอย่างว่าครบถ้วน'],
|
||
[5, 'กู้คืนสู่สภาพแวดล้อมใช้งานจริง', 'บันทึกจุดกู้คืน หยุดบริการที่เกี่ยวข้อง กู้คืน แล้วตรวจสอบสถานะระบบตามคู่มือผู้ดูแลระบบ'],
|
||
], ['c']),
|
||
].join('\n\n'),
|
||
secretary: P.ThS, reviewer: P.ApS, approver: P.SeV,
|
||
}),
|
||
};
|
||
}
|