ข้ามไปที่เนื้อหา

S2 — Proactive Justice Operation System (PJOS) — ER Diagram (Target Design)

TARGET DESIGN

ความสัมพันธ์ตาม schema.sql (FK ทุกเส้นถูกประกาศจริงใน DDL — solid line) · เป็น greenfield design modeled จาก mockup repos/pjos/fe — ยังไม่ลงฐานข้อมูลจริง · ดู data_dict.md และ index.md

ทุกตาราง business มี audit columns CreatedBy/UpdatedBy (int FK → AppUser) — ละไว้ในไดอะแกรมเพื่อความชัด วาดเฉพาะ FK เชิงความหมาย (ownership / actor) · audit/soft-delete ละไว้ทั้งหมด · รายการ FK ครบถ้วนอยู่ที่ตารางสรุปท้ายเอกสาร

ไดอะแกรมแยกตาม domain — ตารางที่เป็นสะพานข้าม domain (Case, AppUser, Province, RightsArea) จะปรากฏมากกว่าหนึ่งบล็อก

Auth & Identity (thin SSO mirror via S9 Portal)

erDiagram
    Province ||--o{ AppUser        : "ProvinceId"
    AppUser  ||--o{ RoleAssignment : "AppUserId"
    Role     ||--o{ RoleAssignment : "RoleId"
    Province ||--o{ RoleAssignment : "ProvinceId (scope)"
    AppUser  ||--o{ RoleAssignment : "GrantedBy"
    AppUser  ||--o| OfficerProfile : "AppUserId"
    Unit     ||--o{ OfficerProfile : "UnitId"
    AppUser  ||--o{ PermissionLog  : "TargetUserId"

AppUser เป็น mirror จาก SSO ของ S9 Web Portal (ไม่มี password) · OfficerProfile เก็บ Capacity/Unit ของเจ้าหน้าที่ผู้รับเคส (workload คำนวณจาก CaseAssignment) · PermissionLog append-only บันทึก GRANT/CHANGE/REVOKE/REASSIGN (บังคับเหตุผล)

Intake → Case core (รับเรื่อง → เคส → ผู้เสียหาย → มอบหมาย → แจ้งสิทธิ)

erDiagram
    Channel             ||--o{ IntakeRecord    : "ChannelId"
    IntakeRecord        ||--o| Case            : "ConfirmedCaseId"
    Case                ||--o{ IntakeRecord    : "MatchedCaseId (dedup)"

    Channel             ||--o{ Case            : "ChannelId"
    Province            ||--o{ Case            : "ProvinceId"
    HelpType            ||--o{ Case            : "HelpTypeId"
    OffenseBase         ||--o{ Case            : "OffenseBaseId"
    PoliceStation       ||--o{ Case            : "PoliceStationId"
    HelpType            ||--o{ HelpType        : "ParentHelpTypeId"

    Case                ||--o{ CaseVictim      : "CaseId"
    VulnerableGroup     ||--o{ CaseVictim      : "VulnerableGroupId"
    Case                ||--o{ CaseAssignment  : "CaseId"
    AppUser             ||--o{ CaseAssignment  : "AssigneeUserId / AssignedBy"
    Case                ||--o{ CaseRightsCheck : "CaseId"
    RightsChecklistItem ||--o{ CaseRightsCheck : "RightsChecklistItemId"

IntakeRecord = 4 ช่องทางรับเข้า + dedup (REQ-001) → ยืนยันแล้วสร้าง Case · CaseVictim ถือมิติประชากร (เพศ/อายุ/กลุ่มเปราะบาง) + media consent (CR-5) — รองรับ multi-victim + รายงาน "จำนวนราย" · CaseAssignment = multi-assignee + ประวัติ (IsCurrent)

Outreach Reports + Trigger Gate + Plan + Approval (การจัดการรายกรณี)

erDiagram
    Case            ||--o{ OutreachReport  : "CaseId"
    Case            ||--o{ CaseTrigger     : "CaseId"
    RightsArea      ||--o{ CaseTrigger     : "RightsAreaId"
    RightsArea      ||--o{ RightsAreaItem  : "RightsAreaId"

    Case            ||--o{ AssistancePlan  : "CaseId"
    AssistancePlan  ||--o{ PlanItem        : "AssistancePlanId"
    RightsArea      ||--o{ PlanItem        : "RightsAreaId"
    RightsAreaItem  ||--o{ PlanItem        : "RightsAreaItemId"

    OutreachReport  ||--o{ ApprovalAction  : "OwnerEntityId (OutreachReport)"
    AssistancePlan  ||--o{ ApprovalAction  : "OwnerEntityId (AssistancePlan version)"
    AppUser         ||--o{ ApprovalAction  : "ApproverUserId"

CaseTrigger = gate 4 ด้าน (ต้องการ/ไม่ต้องการ, REQ-005) · RightsAreaItem = รายการย่อย admin CRUD (CR-4) · AssistancePlan versioned (1 แถว/Version, IsCurrent) · ApprovalAction เป็น polymorphic (OwnerEntityType = OutreachReport/AssistancePlan) ชี้ Version เฉพาะ → รองรับ loop-back + version history (REQ-006) · ลำดับขั้น config ที่ ApprovalStep

Implementation / Referral / Termination (ผลดำเนินการ → ส่งต่อ → ยุติโปรแกรม)

erDiagram
    Case            ||--o{ ImplementationResult : "CaseId"
    PlanItem        ||--o{ ImplementationResult : "PlanItemId"
    AppUser         ||--o{ ImplementationResult : "PerformedByUserId"

    Case            ||--o{ Referral            : "CaseId"
    Unit            ||--o{ Referral            : "TargetUnitId"
    AppUser         ||--o{ Referral            : "SentBy"

    Case            ||--o{ ProgramTermination  : "CaseId"
    AppUser         ||--o{ ProgramTermination  : "RequestedBy / DecidedBy"

ImplementationResult = บันทึกผล Rich Text + ผลภาคสนาม + สถานะการยุติแผน (DONE/NOT_DONE/UNABLE) + แนบหลักฐานบังคับ (REQ-007) · Referral ส่งต่อ S1/S4/S6 (Web Service) หรือภายนอก (Manual) เก็บ ExternalRefId (REQ-008) · ProgramTermination = ขอยุติ→พิจารณา (ผอ.)→ออกจากโปรแกรม

Cross-cutting (แนบไฟล์ / แจ้งเตือน / ประวัติสถานะ / audit)

erDiagram
    Case     ||--o{ CaseStatusHistory : "CaseId"
    AppUser  ||--o{ CaseStatusHistory : "ChangedBy"
    AppUser  ||--o{ Notification      : "RecipientUserId"

Attachment (polymorphic, OwnerEntityType/OwnerEntityId) แนบได้ทุก entity — ไม่วาดเส้น FK (รูปภาพหลักฐาน ≥50MB) · CaseStatusHistory append-only รองรับ tracking + audit · AuditLog/PermissionLog append-only (รวม Action='VIEW_PII' ตาม PDPA) · SystemConfig/ApprovalStep = config (ไม่มี FK เชิงความหมาย)

สรุป FK ทั้งหมด (รวม audit CreatedBy/UpdatedBy)

ทุกตาราง business มี CreatedBy/UpdatedByPJOS.AppUser(AppUserId) (nullable — รองรับ system/sync rows) นอกเหนือจาก FK เชิงความหมายที่วาดด้านบน · ดู Section 2 ของ schema.sql สำหรับรายการ ALTER TABLE ... ADD CONSTRAINT FK_* ครบทุกเส้น (40+ FK)

ตาราง FK เชิงความหมายหลัก
AppUser → Province
RoleAssignment → AppUser, Role, Province, AppUser(GrantedBy)
OfficerProfile → AppUser, Unit
HelpType → HelpType(Parent, self-ref)
PoliceStation → Province
RightsAreaItem → RightsArea
IntakeRecord → Channel, Province, Case(Matched), Case(Confirmed)
Case → Channel, IntakeRecord, Province, HelpType, OffenseBase, PoliceStation
CaseVictim → Case, VulnerableGroup
CaseAssignment → Case, AppUser(Assignee), AppUser(AssignedBy)
CaseRightsCheck → Case, RightsChecklistItem
OutreachReport → Case
CaseTrigger → Case, RightsArea
AssistancePlan → Case
PlanItem → AssistancePlan, RightsArea, RightsAreaItem
ApprovalAction → AppUser(Approver) ; polymorphic → OutreachReport / AssistancePlan
ImplementationResult → Case, PlanItem, AppUser(PerformedBy)
Referral → Case, Unit, AppUser(SentBy)
ProgramTermination → Case, AppUser(RequestedBy/DecidedBy)
Notification → AppUser(Recipient)
CaseStatusHistory → Case, AppUser(ChangedBy)
PermissionLog → AppUser(Target)
Attachment polymorphic (OwnerEntityType/OwnerEntityId — ไม่มี FK)