Private Docs

AMLO Screening — Open Items

สิ่งที่ต้องตัดสินใจก่อนเขียนโค้ด, ช่องโหว่ที่ต้องปิดก่อน go-live, ขอบบนของความ stale, การแบ่งเฟส และรายการที่ยังต้องไปยืนยันกับ IaC/env

อัปเดต: 2026-08-18

อ่านหลัง Architecture และ Scenarios หน้านี้คือสิ่งที่ ยังไม่ถูกตัดสิน และสิ่งที่ ต้องปิดก่อนถือว่าควบคุมนี้ใช้งานได้จริง — ไม่ใช่ backlog ทั่วไป


1. คำถามที่ต้องตอบก่อนเขียนโค้ด (Owner / Compliance ตัดสิน)

1.1 🔴 ไฟล์ AMLO เป็น full snapshot หรือ delta

ทำไมสำคัญ: ถ้าเป็น delta แล้วเราไปใช้นิยาม “ติดถ้ามีใน batch ล่าสุด” ผู้ที่ถูกบล็อกเกือบทั้งหมดจะถูก ปลดบล็อกพร้อมกันในรอบแรกหลัง go-live และไม่มีใครสังเกตเห็น

สถานะ: เอกสารนี้เลี่ยงความเสี่ยงไปแล้วด้วยนิยาม sticky (ดู Architecture §3) ซึ่งถูกต้องทั้งสองกรณี คำตอบนี้จึงไม่บล็อกเฟส 1 — แต่บล็อกเฟส 2 (การปลดบล็อกอัตโนมัติ และ payload แบบ newly-flagged/cleared)

วิธีตอบที่ถูกที่สุด — ใช้ข้อมูลที่ ingest ไปแล้ว ไม่ต้องนัดคุยกับต้นทาง:

SELECT b.file_name, b.stamp_date, b.row_count,
       count(DISTINCT m.cust_code) AS distinct_cust
FROM los.amlo_ingestion_batch b
LEFT JOIN los.amlo_screening_match m ON m.batch_id = b.id
GROUP BY 1,2,3
ORDER BY b.stamp_date DESC;

แล้วดู overlap ของชุด cust_code ระหว่าง 2 batch ล่าสุดที่จบแล้ว — ชุดใหญ่คล้ายกันมาก = snapshot · ชุดเล็กและแทบไม่ซ้ำกัน = delta ถ้า env นั้นมี batch ที่จบแล้วน้อยกว่า 2 ใบ query นี้ตอบไม่ได้ ให้บันทึกว่า “ยังไม่มีคำตอบ” ห้ามเขียนว่า “น่าจะเป็น snapshot”

1.2 🔴 match ทุกแถวบล็อกหมด หรือมีเกณฑ์

schema เก็บ Similarity (numeric 9,8) และ SearchMethod = การคัดกรองเป็นแบบ fuzzy ไม่ใช่ exact match “มีแถว = บล็อก” ที่ threshold ต่ำ = เหตุการณ์ false positive หมู่ในวันแรกที่เปิดใช้

ต้องตอบ: เกณฑ์ similarity เท่าไหร่ / AmloType ไหนบ้างที่บล็อก / ใครเป็นเจ้าของเกณฑ์นี้ (Compliance ไม่ใช่ dev) และเกณฑ์นั้นต้องแก้ได้โดยไม่ deploy หรือไม่

1.3 นิยามของ “ห้ามทำกระบวนการใด ๆ”

ต้องระบุให้ชัดว่าอันไหนได้อันไหนไม่ได้ ข้อเสนอ (รอ Owner ยืนยัน):

การกระทำข้อเสนอ
login เข้าระบบ✅ ได้ — ไม่งั้นเขาจะไม่มีวันเห็นสาเหตุและสลับบริษัทไม่ได้
อ่านข้อมูลเดิม / ดูสถานะงานเก่า✅ ได้ (read-only)
สร้าง/ส่ง/อนุมัติรายการใหม่ ทุกชนิด❌ ไม่ได้
สลับไปบริษัทที่สะอาด✅ ได้เสมอ
ออกจากระบบ✅ ได้เสมอ

1.4 งานที่ค้างอยู่ของบริษัทที่เพิ่งติด

FlowInstance ที่ยัง Draft/Submitted, งานที่รออนุมัติในคิว maker/approver — freeze หรือ reject ข้อเสนอ: freeze (ห้ามเดินต่อ แต่ไม่ทำลายข้อมูล) เพราะ reject แล้วปลดบล็อกทีหลังจะกู้งานไม่ได้ และการ reject อัตโนมัติจำนวนมากคือ event ที่อธิบายกับลูกค้ายาก — แต่ ผู้อนุมัติฝั่งธนาคารต้องเห็นว่างานนั้นถูก freeze เพราะ AMLO ไม่ใช่ค้างเงียบ ๆ

1.5 อนุมัติให้แตะ Sentinel + APIM policy หรือไม่

การรับประกันความครอบคลุมทั้งหมดใน Architecture §4 วางอยู่บนการให้ resolve-session คืน amloBlocked แล้วให้ facade ปฏิเสธ ถ้า Owner ไม่อนุมัติ → ต้องเลือกทางสำรอง (บังคับใช้ใน middleware ของ SupApp_util_lib + บัญชีเวอร์ชัน lib รายบริการ) และต้องยอมรับว่า service ที่ยังไม่ deploy ใหม่ = ยังไม่ถูกบังคับใช้


2. 🔴 ช่องที่ต้องปิดก่อน go-live (ไม่ใช่ nice-to-have)

การควบคุมด้าน compliance ห้ามสร้างอยู่บน endpoint ที่เปิดโล่ง — รายการนี้คือของที่ มีอยู่จริงตอนนี้ บน origin/development

#ช่องหลักฐานสิ่งที่ต้องทำ
1AmloScreeningController ไม่มี auth เลย — ไม่มี [RequireApiKey] ไม่มี [Authorize] และ ApiKeyAuthFilter เป็น opt-in (ไม่ติด attribute = ปล่อยผ่าน) ทั้งที่ไฟล์ import security namespace ไว้แล้วCentralized01.API/Controllers/v1/AmloScreeningController.cs:1-26, Backend_Package/src/Filters/ApiKeyAuthFilter.cs:33-41ติด [RequireApiKey] — endpoint นี้คืนข้อมูล watchlist ดิบ (similarity, ประเภท, วิธีค้น)
2GET /v1/companies/cust-codes เป็น [AllowAnonymous] และ ไม่มี [RequireApiKey] ในไฟล์เลย (ไม่ใช่แค่ถูก comment ไว้) — และมันคืน แผนที่ custCode → companyId → userId ของทั้งระบบ ซึ่ง design นี้ไปพึ่งพาUserService01.API/Controllers/v1/CompanyController.cs:196,199เพิ่ม [RequireApiKey] (กลไกพร้อมใช้อยู่แล้ว register ไว้ที่ Program.cs:115)
3UserCacheController (warm/refresh/delete) เป็น [AllowAnonymous] โดย [RequireApiKey] comment ไว้UserService01.API/Controllers/v1/UserCacheController.cs:16-18uncomment — แม้ warm/refresh จะสร้างค่าจาก DB ใหม่ (ปลอมค่าไม่ได้) แต่ใช้กระหน่ำ DB และดันทุก request ไปเส้น fallback ที่เป็นเส้น fail-open ได้
4rate limit ของ Centralized เป็น 100/นาที รวมทั้ง service ไม่แยก caller → ยิง endpoint sync มือรัว ๆ กิน budget ของทั้ง serviceCentralized01.API/Extensions/ApiExtensions.cs:81-87policy แยกเฉพาะ route sync มือ (เช่น 1/นาที ต่อ caller)
5audit publisher degrade เป็น NullAuditEventPublisher เงียบ ๆ ถ้า env ไม่ได้ตั้ง Service Bus → audit trail หายทั้งชุดโดยไม่มี errorCentralized02.Infrastructure/DependencyInjection.cs:252-269startup guard / health check ใน env ที่เปิดใช้ควบคุมนี้
6ไม่มีใครรู้เมื่อ ingestion ไม่ได้รันสำเร็จ — ข้อมูลค้างเก่าเงียบ ๆ คือความเสี่ยง compliance โดยตรงalert เมื่อไม่มี batch ที่จบสำเร็จภายในกรอบเวลาที่คาด รวมถึงรอบที่ได้ 0 แถว

3. ขอบบนของความ stale (ต้องยอมรับหรือแก้ให้ต่ำลง)

แหล่งความล่าช้าขนาดหมายเหตุ
รอบตรวจวันละครั้ง≤ 24 ชม.บริษัทที่ติดในไฟล์ที่มาถึงหลังรอบตี 5 จะเห็นวันถัดไป (ยังไม่นับ lag ของต้นทางเอง)
Redis user-info TTL≤ ค่าจริงต่อ env (default 86400 = 24 ชม.)การอ่านไม่ต่ออายุ TTL — ถ้า invalidate หลุด blob จะหมดอายุเองแล้ว re-warm ค่าถูก
APIM facade cache ของ resolve-session120 วินาทีนี่คือ staleness ของชั้นที่ 1 ซึ่งเล็กที่สุดในสามชั้น
SignalR ไม่ถึงผู้ใช้ไม่จำกัด (แต่ไม่กระทบการบังคับใช้)กระทบแค่ว่าเห็น modal ช้า

worst case ที่ต้องบอก Owner: ~48 ชั่วโมง จากบริษัทติดจริงจนผู้ใช้ทุกคนถูกปิดกั้นครบทุกเส้นทาง (24 ชม. รอบตรวจ + 24 ชม. TTL ที่แย่สุด) สมมติฐาน: CacheTtlSeconds เป็นค่า default และ invalidate หลุด · ถ้าตัวเลขนี้ยอมรับไม่ได้ตามข้อกำหนด compliance ต้องเพิ่มรอบตรวจ (เช่น ทุก 4 ชม.) และลด TTL — ทั้งสองอย่างแก้ที่ IaC ไม่ใช่โค้ด


4. การแบ่งเฟส

เฟส 1 — พอสำหรับ 4 scenario ที่ Owner ขอ และปิดความเสี่ยงจริง

  1. นิยาม sticky + 3 สถานะ (Flagged / Clear / NotScreenable) + clearance ที่บันทึกได้
  2. state ระดับบริษัทที่ materialize ใน UserService (Centralized ออกจากเส้นทาง runtime)
  3. บังคับใช้ที่ชั้น session (resolve-session + facade allowlist) — พร้อม tri-state fail-closed ในชั้น 2/3
  4. reconcile-by-pull หลังทุกรอบ ingestion + timer สำรอง · push เป็น best-effort
  5. /users/me เพิ่ม amloBlocked ต่อบริษัท + amloAsOfUtc
  6. modal 2 หน้าแบบปิดไม่ได้ + allowlist
  7. sync มือสั่ง recompute ได้จริง
  8. DailyRunHourBangkok=5 ที่ IaC ทุก env
  9. ปิดช่องทั้ง 6 ข้อใน §2
  10. audit event ครบ 5 ประเภท

เฟส 2 — ทำได้ดีขึ้นแต่ไม่ใช่เงื่อนไขของความถูกต้อง

  • payload แบบ diff (newlyFlagged/cleared) — รอคำตอบ §1.1
  • ปลดบล็อกอัตโนมัติเมื่อพ้นจากไฟล์ — รอคำตอบ §1.1 เช่นกัน
  • transactional outbox ทั้งสองฝั่ง (ตอนนี้ reconcile ทำหน้าที่แทนอยู่)
  • 409 + outcome enum ของ endpoint sync มือ (ถ้ายังไม่ทำในเฟส 1)
  • endpoint บาง ๆ GET /v1/users/me/amlo-status — ทำเมื่อวัดได้จริงว่า payload ของ /users/me เป็นปัญหา ไม่ใช่ทำเพราะดูสะอาดกว่า
  • นโยบาย freeze/reject ของงานค้าง (§1.4) ถ้า Owner เลือกให้จัดการย้อนหลัง

5. รายการที่ยังต้องไปยืนยัน (ยังไม่ verify ในรอบนี้)

  1. IaC / APIM — route /api/user-service/v1/cache/* และ /companies/cust-codes ถูกเปิดออกภายนอกผ่าน APIM หรือไม่ (ถ้าเปิด ความรุนแรงของ §2 ข้อ 2–3 สูงขึ้นมาก)
  2. ค่าจริงต่อ env ของ RedisUserInfo:CacheTtlSeconds — เป็นตัวกำหนดตัวเลข 48 ชม. ใน §3
  3. ค่าจริงต่อ env ของ AmloIngestion:Enabled และ Sftp:* (base repo เป็น false + ค่าว่าง ค่าจริงมาจาก IaC + KeyVault)
  4. เวลาที่ไฟล์ AMLO มาถึง SFTP จริง — ต้องรู้ก่อนตั้งชั่วโมงรัน มิฉะนั้น StabilityWindowMinutes จะทำให้รอบตี 5 ข้ามไฟล์ของวันนั้นไปทั้งใบ
  5. รูปแบบ custCode ของ Companies.CustCode เทียบกับ los.amlo_screening_match.cust_code (การเติม 0 ข้างหน้า / ขีด / ช่องว่าง) — ถ้าไม่ตรงกัน ทุกบริษัทจะกลายเป็น NotScreenable เงียบ ๆ พร้อมกับนับจำนวนบริษัทที่ CustCode เป็น null/ว่าง
  6. สัญญาของ resolve-session — ต้องอ่าน response DTO จริงของ Sentinel ก่อนตกลงว่าจะเติม amloBlocked ตรงไหน และ facade policy ต้องแก้ตรงไหน (Backend_Iac/src/apim/policies/sentinel-facade-inbound-v6.xml)
  7. บัญชีเวอร์ชัน SupApp_util_lib รายบริการ — ถ้าเลือกทางสำรองใน §1.5 นี่คือสิ่งที่ต้องมีก่อนประกาศว่าควบคุมนี้ทำงาน