S3 - Activity Report & Course Registration (PRC) - Data Dictionary (Target Design)¶
TARGET DESIGN — ไม่ใช่ schema ปัจจุบัน
ทุกตาราง/ทุกคอลัมน์ (สร้างจาก schema.sql ซึ่งเป็น single source of truth) · ภาพรวม + Traceability · Schema JSON
มาตรฐานทุกตาราง: PK = int IDENTITY(1,1) เว้นแต่ตาราง log = bigint IDENTITY(1,1) · ข้อความไทย = nvarchar / โค้ด/enum = varchar · audit CreatedAt/CreatedBy/UpdatedAt/UpdatedBy (CreatedBy/UpdatedBy เป็น int FK → PRC.AppUser) · soft delete IsDeleted เฉพาะตาราง business · append-only log ไม่มี Updated*/IsDeleted
Authorization รวมศูนย์
Auth = thin mirror — ไม่มีคอลัมน์ password · identity มาจาก SSO กลางผ่าน JWT · PRC.AppUser/PRC.RoleAssignment/PRC.Role เก็บแค่ mirror ของผู้ใช้/บทบาท/การมอบสิทธิ์
1.1 Lookups (master/reference)¶
Province¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| ProvinceId | int | PK, IDENTITY, NOT NULL | |
| Code | varchar(10) | NOT NULL, UNIQUE | รหัสย่อจังหวัด ('BKK','CMI') |
| NameTh | nvarchar(150) | NOT NULL | ชื่อจังหวัดภาษาไทย |
| NameEn | nvarchar(150) | ชื่อจังหวัดภาษาอังกฤษ | |
| Region | nvarchar(50) | ภูมิภาค (เหนือ/อีสาน/กลาง/ใต้) | |
| MapX | decimal(6,2) | พิกัด X บน SVG silhouette (heatmap) | |
| MapY | decimal(6,2) | พิกัด Y บน SVG silhouette (heatmap) | |
| Sequence | int | DEFAULT 0, NOT NULL | ลำดับแสดง |
| IsActive | bit | DEFAULT 1, NOT NULL | สถานะใช้งาน |
MemberType¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| MemberTypeId | int | PK, IDENTITY, NOT NULL | |
| Code | varchar(30) | NOT NULL, UNIQUE | GOV/BUSINESS/YOUTH/TEACHER/CITIZEN |
| NameTh | nvarchar(150) | NOT NULL | 'เจ้าหน้าที่รัฐ','ภาคธุรกิจ','เยาวชน','ครู/บุคลากรการศึกษา','ประชาชน' |
| Sequence | int | DEFAULT 0, NOT NULL | |
| IsActive | bit | DEFAULT 1, NOT NULL |
KnowledgeType¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| KnowledgeTypeId | int | PK, IDENTITY, NOT NULL | |
| Code | varchar(30) | NOT NULL, UNIQUE | ARTICLE/VIDEO/INFOGRAPHIC/SOCIAL/SEMINAR |
| NameTh | nvarchar(150) | NOT NULL | 'บทความ','วิดีโอ','Infographic','สื่อสังคมออนไลน์','การอบรม/สัมมนา' |
| Sequence | int | DEFAULT 0, NOT NULL | |
| IsActive | bit | DEFAULT 1, NOT NULL |
OrgUnit¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| OrgUnitId | int | PK, IDENTITY, NOT NULL | |
| Code | varchar(50) | UNIQUE | รหัสกอง ('KSS','KPS') |
| NameTh | nvarchar(300) | NOT NULL | ชื่อหน่วยงาน |
| ParentOrgUnitId | int | กองแม่ (self-ref) | |
| IsInternal | bit | DEFAULT 1, NOT NULL | ภายในกรมฯ vs ภายนอก |
| IsActive | bit | DEFAULT 1, NOT NULL |
Foreign Keys: ParentOrgUnitId → PRC.OrgUnit(OrgUnitId)
Role¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| RoleId | int | PK, IDENTITY, NOT NULL | |
| Code | varchar(30) | NOT NULL, UNIQUE | ADMIN/OFFICER_KSS/OFFICER_OTHER/TRAINER/VIEWER/CITIZEN |
| NameTh | nvarchar(150) | NOT NULL | ป้ายชื่อบทบาท |
| Description | nvarchar(500) | คำอธิบายสิทธิ์ | |
| Sequence | int | DEFAULT 0, NOT NULL | |
| IsActive | bit | DEFAULT 1, NOT NULL |
1.2 Identity / Auth (thin mirror)¶
AppUser¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| AppUserId | int | PK, IDENTITY, NOT NULL | |
| ExternalSubject | varchar(255) | NOT NULL, UNIQUE | OIDC 'sub' / Keycloak UUID / AD sAMAccountName / ThaiD pairwise |
| AuthSource | varchar(20) | DEFAULT 'AD', NOT NULL, CHECK IN ('AD','KEYCLOAK','THAID') | AD / KEYCLOAK / THAID |
| Username | nvarchar(255) | mirrors SSO username (unique เมื่อ not null — ดู IX section) | |
| DisplayName | nvarchar(200) | NOT NULL | ชื่อ-สกุลแสดงผล |
| nvarchar(150) | อีเมล (จาก token claim) | ||
| Phone | varchar(30) | เบอร์ติดต่อ | |
| OrgUnitId | int | สังกัด (data-scoping default) | |
| TrainerId | int | ถ้า user เป็นวิทยากร -> ผูก Trainer (TRAINER-sees-own) | |
| MemberId | int | ถ้า user เป็น CITIZEN/ศิษย์เก่า -> ผูก Member | |
| IsActive | bit | DEFAULT 1, NOT NULL | active flag |
| LastLoginAt | datetime2 | ||
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: OrgUnitId → PRC.OrgUnit(OrgUnitId); TrainerId → PRC.Trainer(TrainerId); MemberId → PRC.Member(MemberId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
RoleAssignment¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| RoleAssignmentId | int | PK, IDENTITY, NOT NULL | |
| AppUserId | int | NOT NULL, UNIQUE (AppUserId, RoleId) | |
| RoleId | int | NOT NULL, UNIQUE (AppUserId, RoleId) | |
| GrantedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| GrantedBy | int | ADMIN ผู้มอบสิทธิ์ | |
| IsActive | bit | DEFAULT 1, NOT NULL |
Foreign Keys: AppUserId → PRC.AppUser(AppUserId); RoleId → PRC.Role(RoleId); GrantedBy → PRC.AppUser(AppUserId)
1.3 Course Catalog¶
Course¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| CourseId | int | PK, IDENTITY, NOT NULL | |
| CourseCode | varchar(40) | NOT NULL, UNIQUE | รหัสหลักสูตร human-facing ('HR-LDR-2569') |
| Title | nvarchar(500) | NOT NULL | ชื่อหลักสูตร |
| Category | varchar(20) | NOT NULL, CHECK IN ('EXECUTIVE','PROJECT') | EXECUTIVE / PROJECT (REQ-009) |
| Level | varchar(20) | NOT NULL, CHECK IN ('BASIC','INTER','ADV') | BASIC / INTER / ADV = ต้น/กลาง/สูง (REQ-013) |
| Hours | int | DEFAULT 0, NOT NULL | จำนวนชั่วโมง |
| Mode | varchar(20) | NOT NULL, CHECK IN ('ONSITE','ONLINE','HYBRID') | ONSITE / ONLINE / HYBRID (REQ-012) |
| ProvinceId | int | จังหวัดจัดอบรม (heatmap) | |
| OnsiteVenue | nvarchar(500) | สถานที่จริง (ONSITE/HYBRID) | |
| OnlineUrl | nvarchar(1000) | URL ห้องออนไลน์ (ONLINE/HYBRID; เก็บคู่ onsite ได้ — REQ-012) | |
| Status | varchar(20) | DEFAULT 'DRAFT', NOT NULL, CHECK IN ('DRAFT','OPEN','NEAR_FULL','CLOSED','PUBLISHED') | DRAFT/OPEN/NEAR_FULL/CLOSED/PUBLISHED |
| IsDraft | bit | DEFAULT 1, NOT NULL | ฉบับร่าง (draft/publish — REQ-008) |
| TargetCount | int | DEFAULT 0, NOT NULL | จำนวนเป้าหมาย |
| EnrolledCount | int | DEFAULT 0, NOT NULL | จำนวนที่ลงทะเบียนแล้ว (denormalized counter) |
| OpenAt | date | วันเปิดรับสมัคร | |
| CloseAt | date | วันปิดรับสมัคร | |
| StartAt | date | วันเริ่มอบรม | |
| CoverColor | varchar(20) | สีปก (#hex) | |
| TrainerId | int | วิทยากรหลัก | |
| Objective | nvarchar(max) | วัตถุประสงค์ | |
| HasCert | bit | DEFAULT 0, NOT NULL | ออกประกาศนียบัตรหรือไม่ |
| IsDeleted | bit | DEFAULT 0, NOT NULL | |
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: ProvinceId → PRC.Province(ProvinceId); TrainerId → PRC.Trainer(TrainerId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
ProjectCourse¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| ProjectCourseId | int | PK, IDENTITY, NOT NULL | |
| ProjectId | int | NOT NULL, UNIQUE (ProjectId, CourseId) | |
| CourseId | int | NOT NULL, UNIQUE (ProjectId, CourseId) | |
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int |
Foreign Keys: ProjectId → PRC.Project(ProjectId); CourseId → PRC.Course(CourseId); CreatedBy → PRC.AppUser(AppUserId)
CoursePrerequisite¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| CoursePrerequisiteId | int | PK, IDENTITY, NOT NULL | |
| CourseId | int | NOT NULL, UNIQUE (CourseId, PrerequisiteCourseId) | หลักสูตรที่มีเงื่อนไข |
| PrerequisiteCourseId | int | NOT NULL, UNIQUE (CourseId, PrerequisiteCourseId), CHECK (CourseId <> PrerequisiteCourseId) | หลักสูตรที่ต้องผ่านก่อน |
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int |
Foreign Keys: CourseId → PRC.Course(CourseId); PrerequisiteCourseId → PRC.Course(CourseId); CreatedBy → PRC.AppUser(AppUserId)
1.4 Project / Budget¶
Project¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| ProjectId | int | PK, IDENTITY, NOT NULL | |
| ProjectCode | varchar(40) | NOT NULL, UNIQUE | 'PJ-2569-01' (human-facing) |
| Name | nvarchar(500) | NOT NULL | ชื่อโครงการ |
| Budget | decimal(15,2) | DEFAULT 0, NOT NULL | งบประมาณตั้งต้น |
| Spent | decimal(15,2) | DEFAULT 0, NOT NULL | ใช้จ่ายแล้ว (denormalized) |
| TargetCount | int | DEFAULT 0, NOT NULL | เป้าหมายผู้เข้าอบรม |
| EnrolledCount | int | DEFAULT 0, NOT NULL | ลงทะเบียนแล้ว (denormalized) |
| OwnerName | nvarchar(200) | ชื่อผู้รับผิดชอบ (demo free text) | |
| OwnerUserId | int | ผู้รับผิดชอบ (ถ้า map ได้) | |
| Status | varchar(20) | DEFAULT 'ACTIVE', NOT NULL, CHECK IN ('ACTIVE','CLOSED','SUSPENDED') | ACTIVE/CLOSED/SUSPENDED |
| IsDeleted | bit | DEFAULT 0, NOT NULL | 2-step delete (soft) |
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: OwnerUserId → PRC.AppUser(AppUserId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
BudgetCalculation¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| BudgetCalculationId | int | PK, IDENTITY, NOT NULL | |
| ProjectId | int | NOT NULL | |
| CourseCost | decimal(15,2) | DEFAULT 0, NOT NULL | ค่าใช้จ่ายโครงการ |
| AdminCost | decimal(15,2) | DEFAULT 0, NOT NULL | ค่าใช้จ่ายบริหาร |
| HeadCount | int | NOT NULL, CHECK (HeadCount > 0) | จำนวนผู้เข้าอบรม (ต้อง > 0) |
| TotalCost | decimal(15,2) | NOT NULL | = CourseCost + AdminCost |
| PerHeadCost | decimal(15,2) | NOT NULL | = TotalCost / HeadCount (snapshot, คำนวณที่ app) |
| CalculatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | เวลาที่กดยืนยัน |
| ConfirmedBy | int | ผู้กดยืนยัน | |
| Note | nvarchar(500) | ||
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: ProjectId → PRC.Project(ProjectId); ConfirmedBy → PRC.AppUser(AppUserId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
1.5 Trainer¶
Trainer¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| TrainerId | int | PK, IDENTITY, NOT NULL | |
| Name | nvarchar(200) | NOT NULL | ชื่อ-สกุล |
| OrgUnitId | int | สังกัด | |
| OrgText | nvarchar(300) | สังกัด (free text fallback) | |
| Education | nvarchar(500) | วุฒิการศึกษา | |
| Phone | varchar(40) | ||
| LineId | varchar(100) | LINE | |
| TotalHours | int | DEFAULT 0, NOT NULL | ชั่วโมงสอนสะสม (denormalized) |
| CourseCount | int | DEFAULT 0, NOT NULL | จำนวนหลักสูตร (denormalized) |
| BadgeColor | varchar(20) | สี avatar | |
| SelfEditEnabled | bit | DEFAULT 0, NOT NULL | อนุญาตให้แก้ไขข้อมูลตนเอง |
| HasPendingEdit | bit | DEFAULT 0, NOT NULL | มีคำขอแก้ไขรออนุมัติ |
| AppUserId | int | บัญชีผู้ใช้ของวิทยากร (TRAINER-sees-own) | |
| IsDeleted | bit | DEFAULT 0, NOT NULL | |
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: OrgUnitId → PRC.OrgUnit(OrgUnitId); AppUserId → PRC.AppUser(AppUserId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
TrainerSpecialty¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| TrainerSpecialtyId | int | PK, IDENTITY, NOT NULL | |
| TrainerId | int | NOT NULL, UNIQUE (TrainerId, Specialty) | |
| Specialty | nvarchar(200) | NOT NULL, UNIQUE (TrainerId, Specialty) | สาขาเชี่ยวชาญ (free-form skill tag) |
Foreign Keys: TrainerId → PRC.Trainer(TrainerId)
TrainerEditRequest¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| TrainerEditRequestId | int | PK, IDENTITY, NOT NULL | |
| TrainerId | int | NOT NULL | |
| ProposedJson | nvarchar(max) | ข้อมูลที่ขอแก้ (JSON diff/snapshot) | |
| Status | varchar(20) | DEFAULT 'PENDING', NOT NULL, CHECK IN ('PENDING','APPROVED','REJECTED') | PENDING/APPROVED/REJECTED |
| RequestedBy | int | ผู้ยื่นคำขอ | |
| RequestedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| ReviewedBy | int | ADMIN ผู้พิจารณา | |
| ReviewedAt | datetime2 | ||
| ReviewNote | nvarchar(max) | ||
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: TrainerId → PRC.Trainer(TrainerId); RequestedBy → PRC.AppUser(AppUserId); ReviewedBy → PRC.AppUser(AppUserId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
1.6 Member / Alumni¶
Member¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| MemberId | int | PK, IDENTITY, NOT NULL | |
| Name | nvarchar(200) | NOT NULL | ชื่อ-สกุล |
| MemberTypeId | int | NOT NULL | ประเภท |
| OrgUnitId | int | สังกัด | |
| OrgText | nvarchar(300) | สังกัด (free text) | |
| ProvinceId | int | จังหวัด | |
| Tel | varchar(40) | ||
| nvarchar(150) | |||
| JoinedAt | date | วันที่เข้าร่วม | |
| IsDeleted | bit | DEFAULT 0, NOT NULL | soft-delete (REQ-PRC-002) |
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: MemberTypeId → PRC.MemberType(MemberTypeId); OrgUnitId → PRC.OrgUnit(OrgUnitId); ProvinceId → PRC.Province(ProvinceId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
Enrollment¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| EnrollmentId | int | PK, IDENTITY, NOT NULL | |
| MemberId | int | NOT NULL, UNIQUE (MemberId, CourseId, BatchId) | |
| CourseId | int | NOT NULL, UNIQUE (MemberId, CourseId, BatchId) | |
| BatchId | int | UNIQUE (MemberId, CourseId, BatchId) | รุ่นที่เข้า (REQ-013) |
| EnrolledAt | date | ||
| IsDeleted | bit | DEFAULT 0, NOT NULL | |
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: MemberId → PRC.Member(MemberId); CourseId → PRC.Course(CourseId); BatchId → PRC.Batch(BatchId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
1.7 Registration & Approval¶
Registration¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| RegistrationId | int | PK, IDENTITY, NOT NULL | |
| RegistrationNo | varchar(40) | NOT NULL, UNIQUE | 'REG-2569-1801' (human-facing) |
| CourseId | int | NOT NULL | |
| ApplicantName | nvarchar(200) | NOT NULL | ชื่อผู้สมัคร (อาจยังไม่ใช่ Member) |
| MemberTypeId | int | ประเภทผู้สมัคร | |
| MemberId | int | ผูก Member (หลังอนุมัติ/ถ้ามี) | |
| nvarchar(150) | อีเมลติดต่อ | ||
| Channel | varchar(20) | DEFAULT 'WEB_PORTAL', NOT NULL, CHECK IN ('WEB_PORTAL','WALKIN','EMAIL','PHONE') | WEB_PORTAL/WALKIN/EMAIL/PHONE |
| Status | varchar(20) | DEFAULT 'PENDING', NOT NULL, CHECK IN ('PENDING','APPROVED','REJECTED','NEEDS_FIX') | PENDING/APPROVED/REJECTED/NEEDS_FIX |
| HasDocs | bit | DEFAULT 0, NOT NULL | แนบเอกสารครบ |
| EmailSent | bit | DEFAULT 0, NOT NULL | ส่งอีเมลแจ้งผลแล้ว (denormalized) |
| SubmittedAt | date | NOT NULL | วันยื่น |
| ReviewedBy | int | OFFICER_KSS ผู้พิจารณา | |
| ReviewedAt | datetime2 | ||
| ReviewNote | nvarchar(max) | เหตุผลปฏิเสธ/ขอแก้ไข | |
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: CourseId → PRC.Course(CourseId); MemberTypeId → PRC.MemberType(MemberTypeId); MemberId → PRC.Member(MemberId); ReviewedBy → PRC.AppUser(AppUserId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
1.8 Batch¶
Batch¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| BatchId | int | PK, IDENTITY, NOT NULL | |
| CourseId | int | NOT NULL, UNIQUE (CourseId, BatchNo) | |
| BatchNo | int | NOT NULL, UNIQUE (CourseId, BatchNo) | เลขรุ่น |
| YearBE | int | NOT NULL | ปี พ.ศ. (label ตาม demo — ดู cross-cutting) |
| StartAt | date | วันเริ่มรุ่น | |
| EndAt | date | วันจบรุ่น | |
| TargetCount | int | DEFAULT 0, NOT NULL | เป้าหมาย |
| CompletedCount | int | DEFAULT 0, NOT NULL | จำนวนผ่าน (denormalized) |
| IsDeleted | bit | DEFAULT 0, NOT NULL | |
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: CourseId → PRC.Course(CourseId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
1.9 Certificate¶
Certificate¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| CertificateId | int | PK, IDENTITY, NOT NULL | |
| CertificateNo | varchar(40) | NOT NULL, UNIQUE | 'CT-2569-0001' |
| CourseId | int | NOT NULL | |
| MemberId | int | NOT NULL | |
| BatchId | int | รุ่น | |
| RecipientName | nvarchar(200) | NOT NULL | ชื่อบนใบ (snapshot) |
| Score | int | CHECK (Score IS NULL OR Score BETWEEN 0 AND 100) | คะแนน 0-100 |
| Result | varchar(20) | NOT NULL, CHECK IN ('PASS','FAIL') | PASS/FAIL (ผ่านเกณฑ์/ไม่ผ่านเกณฑ์) |
| IssuedAt | date | วันออก (NULL ถ้ายังไม่ออก/FAIL) | |
| IsOriginalIssued | bit | DEFAULT 0, NOT NULL | ออกฉบับต้นฉบับแล้ว |
| ReprintCount | int | DEFAULT 0, NOT NULL | จำนวนพิมพ์ซ้ำ (>0 => watermark 'สำเนา') |
| IsDeleted | bit | DEFAULT 0, NOT NULL | |
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: CourseId → PRC.Course(CourseId); MemberId → PRC.Member(MemberId); BatchId → PRC.Batch(BatchId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
CertificatePrintLog¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| Id | bigint | PK, IDENTITY, NOT NULL | |
| CertificateId | int | NOT NULL | |
| PrintType | varchar(20) | NOT NULL, CHECK IN ('ORIGINAL','COPY') | ORIGINAL/COPY (ต้นฉบับ/สำเนา) |
| HasWatermark | bit | DEFAULT 0, NOT NULL | ประทับลายน้ำ 'สำเนา' (COPY => 1) |
| PrintedBy | int | ||
| PrintedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL |
Foreign Keys: CertificateId → PRC.Certificate(CertificateId); PrintedBy → PRC.AppUser(AppUserId)
1.10 Equipment¶
Equipment¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| EquipmentId | int | PK, IDENTITY, NOT NULL | |
| EquipmentCode | varchar(40) | NOT NULL, UNIQUE | 'RLPD-PROJ-001' |
| Name | nvarchar(500) | NOT NULL | ชื่อครุภัณฑ์ |
| ResponsibleName | nvarchar(200) | ผู้รับผิดชอบ (demo free text) | |
| ResponsibleUserId | int | ผู้รับผิดชอบ (ถ้า map) | |
| Status | varchar(20) | DEFAULT 'ACTIVE', NOT NULL, CHECK IN ('ACTIVE','RETURNED','DAMAGED','REPLACING') | ACTIVE/RETURNED/DAMAGED/REPLACING (ใช้งาน/ส่งคืน/ชำรุด/อยู่ระหว่างทดแทน) |
| AcquiredAt | date | NOT NULL | วันได้มา (ใช้คำนวณอายุ 5 ปี) |
| Value | decimal(15,2) | มูลค่า | |
| IsDeleted | bit | DEFAULT 0, NOT NULL | |
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: ResponsibleUserId → PRC.AppUser(AppUserId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
EquipmentOwnershipHistory¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| Id | bigint | PK, IDENTITY, NOT NULL | |
| EquipmentId | int | NOT NULL | |
| FromResponsible | nvarchar(200) | ผู้รับผิดชอบเดิม | |
| ToResponsible | nvarchar(200) | ผู้รับผิดชอบใหม่ | |
| FromUserId | int | ||
| ToUserId | int | ||
| ChangedBy | int | ||
| ChangedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| Note | nvarchar(500) |
Foreign Keys: EquipmentId → PRC.Equipment(EquipmentId); FromUserId → PRC.AppUser(AppUserId); ToUserId → PRC.AppUser(AppUserId); ChangedBy → PRC.AppUser(AppUserId)
1.11 Knowledge Dissemination¶
KnowledgeReport¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| KnowledgeReportId | int | PK, IDENTITY, NOT NULL | |
| KnowledgeTypeId | int | NOT NULL | ประเภทสื่อ |
| Title | nvarchar(500) | NOT NULL | ชื่อเรื่อง |
| ItemCount | int | DEFAULT 1, NOT NULL | จำนวนชิ้น |
| ByName | nvarchar(300) | ผู้จัดทำ | |
| OrgUnitId | int | หน่วยงาน | |
| OrgText | nvarchar(300) | หน่วยงาน (free text) | |
| ProvinceId | int | จังหวัด (อาจ '-') | |
| ReportDate | date | วันที่ | |
| Link | nvarchar(1000) | ลิงก์ | |
| Status | varchar(20) | DEFAULT 'PENDING', NOT NULL, CHECK IN ('PENDING','APPROVED','NEEDS_FIX') | PENDING/APPROVED/NEEDS_FIX (รอแก้ไข/อนุมัติแล้ว) |
| FlagNote | nvarchar(max) | หมายเหตุที่ ADMIN flag | |
| FlaggedBy | int | ADMIN ผู้ flag | |
| SubmittedBy | int | OFFICER_OTHER (data-scoping: sees-own) | |
| IsDeleted | bit | DEFAULT 0, NOT NULL | |
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: KnowledgeTypeId → PRC.KnowledgeType(KnowledgeTypeId); OrgUnitId → PRC.OrgUnit(OrgUnitId); ProvinceId → PRC.Province(ProvinceId); SubmittedBy → PRC.AppUser(AppUserId); FlaggedBy → PRC.AppUser(AppUserId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
1.12 Notification / Email¶
EmailNotification¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| EmailNotificationId | int | PK, IDENTITY, NOT NULL | |
| RegistrationId | int | NOT NULL | |
| ToAddress | nvarchar(150) | NOT NULL | ผู้รับ |
| Subject | nvarchar(500) | NOT NULL | หัวเรื่อง |
| Body | nvarchar(max) | เนื้อหา | |
| Status | varchar(20) | DEFAULT 'PENDING', NOT NULL, CHECK IN ('PENDING','SENT','FAILED','BOUNCED') | PENDING/SENT/FAILED/BOUNCED |
| RetryCount | int | DEFAULT 0, NOT NULL, CHECK (RetryCount >= 0 AND RetryCount <= MaxRetry) | จำนวน retry (0..MaxRetry) |
| MaxRetry | int | DEFAULT 3, NOT NULL | เพดาน retry (retry 3x) |
| LastAttemptAt | datetime2 | ||
| SentAt | datetime2 | เวลาส่งสำเร็จ (NULL ถ้ายังไม่สำเร็จ/bounced) | |
| NextRetryAt | datetime2 | กำหนด retry ครั้งถัดไป (backoff) | |
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| CreatedBy | int | ||
| UpdatedAt | datetime2 | ||
| UpdatedBy | int |
Foreign Keys: RegistrationId → PRC.Registration(RegistrationId); CreatedBy → PRC.AppUser(AppUserId); UpdatedBy → PRC.AppUser(AppUserId)
EmailAttempt¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| Id | bigint | PK, IDENTITY, NOT NULL | |
| EmailNotificationId | int | NOT NULL | |
| AttemptNo | int | NOT NULL | ครั้งที่ 1..3 |
| Status | varchar(20) | NOT NULL, CHECK IN ('SENT','FAILED','BOUNCED') | SENT/FAILED/BOUNCED |
| ErrorMessage | nvarchar(max) | ข้อความ error จาก SMTP | |
| AttemptedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL |
Foreign Keys: EmailNotificationId → PRC.EmailNotification(EmailNotificationId)
1.13 Audit¶
AuditLog¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| Id | bigint | PK, IDENTITY, NOT NULL | |
| ActorUserId | int | ผู้กระทำ (NULL = system) | |
| ActorName | nvarchar(200) | ชื่อผู้กระทำ (denormalized snapshot; 'system') | |
| ActorRole | varchar(30) | บทบาทขณะกระทำ (denormalized) | |
| Action | nvarchar(300) | NOT NULL | การกระทำ (Thai free text) |
| EntityType | varchar(50) | 'TRAINER','PROJECT','CERTIFICATE','REGISTRATION','EQUIPMENT','EMAIL','DASHBOARD' | |
| EntityId | varchar(50) | id/code ของ target (รับได้ทั้ง int และ business code) | |
| Detail | nvarchar(max) | รายละเอียด/JSON | |
| ClientIp | varchar(50) | ||
| CreatedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL |
Foreign Keys: ActorUserId → PRC.AppUser(AppUserId)
1.14 File Attachment (polymorphic)¶
Attachment¶
| Column | Data Type | Constraints | Description |
|---|---|---|---|
| AttachmentId | int | PK, IDENTITY, NOT NULL | |
| OwnerEntityType | varchar(50) | NOT NULL, CHECK IN ('COURSE','PROJECT','TRAINER','REGISTRATION','KNOWLEDGE_REPORT','MEMBER') | COURSE/PROJECT/TRAINER/REGISTRATION/KNOWLEDGE_REPORT/MEMBER |
| OwnerEntityId | int | NOT NULL | running id ของ entity เจ้าของ (polymorphic, ไม่มี DB-level FK) |
| FileName | nvarchar(255) | NOT NULL | ชื่อไฟล์ที่จัดเก็บ |
| OriginalName | nvarchar(255) | NOT NULL | ชื่อไฟล์ต้นฉบับ |
| MimeType | varchar(150) | NOT NULL | ชนิด MIME |
| Extension | varchar(20) | NOT NULL, CHECK IN ('doc','docx','xls','xlsx','ppt','pdf','jpeg') | doc/docx/xls/xlsx/ppt/pdf/jpeg |
| FileSize | bigint | NOT NULL, CHECK (FileSize <= 52428800) | ขนาด byte (<= 50MB) |
| Sha256 | varchar(64) | checksum สำหรับ dedupe/integrity | |
| StoragePath | nvarchar(1000) | NOT NULL | path/key ที่เก็บไฟล์ |
| UploadedAt | datetime2 | DEFAULT SYSUTCDATETIME(), NOT NULL | |
| UploadedBy | int | ||
| IsDeleted | bit | DEFAULT 0, NOT NULL |
Foreign Keys: UploadedBy → PRC.AppUser(AppUserId)