โครงสร้างฐานข้อมูลและการจัดเก็บข้อมูล
ระบบใช้ Storage 3 ประเภทร่วมกัน: PostgreSQL สำหรับข้อมูลเชิงสัมพันธ์, Redis สำหรับ Cache และ local filesystem ใน LOCAL UPLOAD DIR สำหรับไฟล์รูปกับ Heatmap
โครงสร้างฐานข้อมูลและการจัดเก็บข้อมูล
ระบบใช้ Storage 3 ประเภทร่วมกัน: PostgreSQL สำหรับข้อมูลเชิงสัมพันธ์, Redis สำหรับ Cache และ local filesystem ใน LOCAL_UPLOAD_DIR สำหรับไฟล์รูปกับ Heatmap
PostgreSQL — ฐานข้อมูลหลัก
หน้าที่: เก็บข้อมูลเชิงสัมพันธ์ที่มีโครงสร้างทั้งหมดด้วย ACID Transaction
ตารางหลัก (11 ตาราง: 9 หลัก + 2 archive)
| ตาราง | คำอธิบาย |
|---|---|
| users | บัญชีผู้ใช้: email, hashed password, full name, role (user/researcher; admin แยกตาราง admins, CHECK ck_users_role), is_active, created_at, updated_at |
| admins | บัญชีผู้ดูแลระบบแยกตาราง, คอลัมน์ is_superadmin (Boolean, default False) |
| scans | รายการ Scan: id UUID, user_id, image_hash SHA-256, raw_image_url, heatmap_image_url, title, text_score, visual_score, source_score, total_risk_score (CHECK 0–100), exif_data, ocr_text, scam_keywords_found, reverse_search_results, ai_gen_probability, xai_explanation, status (CHECK 8 ค่า), progress (CHECK 0–100), created_at, completed_at (ระดับความเสี่ยงคำนวณตอนแสดงผล) |
| scam_reports | รายงาน Scam จากผู้ใช้: scan_id, category (CHECK 7 ค่า canonical), reason, platform, reference_url, allow_research_use, status (pending/reviewing/approved/rejected), admin_note, moderated_by/at (FK admins, SET NULL), version |
| consent_logs | ประวัติการยินยอม PDPA แบบตรวจสอบย้อนหลังได้: user_id (nullable, SET NULL เมื่อลบ user), system_consent, research_consent, ip_address, user_agent, created_at (สร้างตอน register; trigger ล้าง PII ตอนลบ user) |
| model_versions | Registry โมเดล: version_tag, file_path, is_active, deployed_at, artifact_checksum, framework_compatibility (onnx), metrics a_acc, m_iou, m_acc, m_dice (เปลี่ยนชื่อจาก accuracy/precision/recall โดย migration 042de00eee1b), dataset_reference, created_by (FK admins, SET NULL), status (CHECK), deployment_history |
| admin_sessions | Session/refresh-token rotation ของ admin |
| audit_log | บันทึก Append-only ของการกระทำโดย Admin: admin_id, action, entity_type, entity_id, before_state, after_state, reason, ip_address, user_agent, request_id, details, created_at |
| export_jobs | งาน export dataset: admin_id (nullable, SET NULL), status (CHECK), progress, total_rows, file_size_bytes, error_message, file_path, manifest, filter_config, expires_at (7 วัน), created_at, completed_at |
| audit_log_archive / consent_logs_archive | ที่เก็บ log เกิน retention 1 ปี (+archived_at, ไม่มี FK/trigger; ย้ายโดย scripts/archive_old_logs.py รายเดือน) |
Append-only trigger ของ audit_log
ตาราง audit_log เป็น append-only ที่ระดับฐานข้อมูล: trigger trg_prevent_audit_log_modification
(BEFORE UPDATE OR DELETE ON audit_log FOR EACH ROW) เรียกฟังก์ชัน
prevent_audit_log_modification() ซึ่ง RAISE EXCEPTION เสมอ จึงห้าม UPDATE และ DELETE
ทุกแถว (สร้างโดย migration e3844dc4110e; migration c8d9e0f1a2b3 เปิดช่องเฉพาะ DELETE
ใน transaction ที่ตั้ง SET LOCAL app.allow_audit_archive='on' ให้สคริปต์ archive ใช้)
Field ที่เกี่ยวกับ PDPA
consent จะถูกส่งผ่าน body ของ register แล้วบันทึกเป็นแถวใหม่ใน consent_logs:
- system_consent — ยินยอมให้ประมวลผลรูปภาพ (จำเป็น ถ้าไม่ยินยอมใช้แอปไม่ได้)
- research_consent — ยินยอมให้นำรูปภาพไป Train AI (ไม่บังคับ ถอนได้)
Redis — Cache Store
หน้าที่: ค้นหาภาพที่เคยวิเคราะห์แล้วด้วยความเร็วสูง เพื่อหลีกเลี่ยงการรัน AI ซ้ำ
การทำงาน
- เมื่อรับรูปภาพ API จะคำนวณ SHA-256 ของไฟล์รูป
- ใช้ Hash นั้นเป็น key ใน Redis (TTL 30 วัน)
- Cache Hit — พบ Hash ใน Redis → ใช้ผล inference ที่แคชไว้ → ส่งคืนทันที (เป้าหมาย < 3 วินาที)
- Cache Miss — ไม่พบ Hash → รัน Pipeline ครบ → เก็บใน PostgreSQL → เขียน Hash ลง Redis
Cache Invalidation
- Redis Key หมดอายุตาม TTL ที่ตั้งไว้
- เมื่อ Deploy โมเดลใหม่ (น้ำหนักใหม่) Cache entry เก่าอาจ Stale — Admin สั่ง Cache Invalidation แบบ Forced ได้
Local Filesystem Storage
หน้าที่: เก็บไฟล์รูป (normalize เป็น PNG) ที่ไม่เหมาะเก็บในฐานข้อมูล Relational
โครงสร้างการจัดเก็บ
uploads/
รูปต้นฉบับ (normalize lossless PNG)
heatmaps/
Heatmap overlay (mask-to-heatmap)
DB เก็บเฉพาะ path ของรูปต้นฉบับและ Heatmap
Access Control
- เสิร์ฟผ่าน /uploads ให้ admin portal preview ได้
การเก็บรักษาข้อมูล
- scan + ไฟล์รูป (raw/heatmap): ลบอัตโนมัติเมื่ออายุเกิน 90 วัน (
server/scripts/purge_old_scans.py, cron ทุกวัน 03:00) - audit_log/consent_logs: archive เมื่ออายุเกิน 1 ปี (
server/scripts/archive_old_logs.py, cron วันที่ 1 เวลา 04:00) - ไฟล์ export: เก็บ 7 วันแล้ว mark
expired
ประเด็นสำคัญ
- PostgreSQL คือ Source of Truth สำหรับข้อมูลที่มีโครงสร้างทั้งหมด (11 ตาราง: 9 หลัก + 2 archive)
- Redis คือ Performance Optimization — ล้างและสร้างใหม่ได้ (TTL 30 วัน)
- Local filesystem รับผิดชอบไฟล์รูปทั้งหมด ฐานข้อมูล Relational เก็บแค่ Path/URL
- PDPA Compliance บังคับที่ระดับ Storage: เก็บน้อยที่สุด, consent ผ่าน register body ไปยัง consent logs, ถอนได้