Private Docs

E2E Runtime Verification — รันจริง local (real ASB + real DB)

ผลรันจริง E2E onboarding/approval บน local fleet 7 service — แยกชัด 3 ชั้นการทดสอบ (Postman HTTP / dev-driver in-memory / direct-ASB) + sequence ทีละ request ของ Postman collection (18/44 ที่ขับจริง) ว่าพังจังหวะไหน เพราะอะไร

อัปเดต: 2026-06-25

วันที่: 2026-06-25 · runtime view — คู่กับ 05-e2e-sequence-diagrams.md (static code view)

เอกสารนี้แก้ใหม่ (v2): รอบก่อน report รวบ 3 ชั้นการทดสอบที่ต่างกันไว้เป็นก้อนเดียว (“ทดสอบ 44 API / เขียว 5/5”) ทำให้ดูเหมือน Postman ขับ flow เขียวทั้งเส้น — ไม่จริง · v2 นี้แยก 3 ชั้นออกจากกัน + ลง sequence ทีละ request ตั้งแต่ต้นจนจบ ว่า request ไหนควรได้อะไร · จริงได้อะไร · พังเพราะอะไร เพื่อให้ตัดสินใจได้ว่าจุดไหนตามต่อจุดไหนข้าม

🟢 UPDATE (รันรอบใหม่ 2026-06-25 เย็น): ปิดช่องว่าง S1 ได้แล้ว — ขับ NEW_REQUESTOR จริงทั้งเส้น ตั้งแต่ OTP step 1 (email มั่ว, mock Entra/OTP) → submit → US→ASB→OC saga → WF pickup/approve จริง → OC saga Approved/Completed (local OC consume จริงทุก hop, DB-verified) · WF create bug (WfTemplate.Id) = fix แล้วใน development (merge มาใช้ได้) · ขอบเขต: ถึง OC saga terminal เท่านั้น — return path กลับ US/NS ยังไม่ verify · หลักฐานเต็ม: Atlas docs/orchestration-integration/25062026/REAL_E2E_RUN_RESULT.md (+ MOCK_REMOVAL_LIST.md สำหรับ mock ที่ต้องลบ)


0. สำคัญที่สุด — มี 3 ชั้นการทดสอบ คนละเรื่องกัน (อย่ารวบ)

รอบนี้มีการพิสูจน์ 3 แบบ ซึ่งคนละ surface คนละระดับหลักฐาน — รอบก่อนเอามารวมเป็น “เขียว” ก้อนเดียว = เข้าใจผิด:

#ชั้น (surface)ขับด้วยอะไรverdictระดับหลักฐาน
S1Postman HTTP จริง (A1–A14) — CRUD ผ่าน HTTP ของ service จริงnewman รัน collection ชน localhost fleet🔴 แดงเกือบหมด — ทุก state-mutation พังจริงสุด (รัน HTTP จริง มี response code ทุก request)
S2Postman dev-driver in-memory (request OC demo/onboarding)1 HTTP call → OC รัน saga timeline ในหน่วยความจำ🟢 เขียว แต่พิสูจน์แค่ saga logicกลาง — in-memory, endpoint dev-only, ไม่ใช่ integration ผ่าน ASB
S3Direct node→ASB publish (จำลอง message ที่ US/WF จะส่ง)script @azure/service-bus ยิง event เข้า superapp-dev จริง🟢 เขียว 5/5 hop แต่ message สังเคราะห์ + เป็นหลักฐานรอบก่อนกลาง — OC consume→saga→persist จริงบน ASB จริง แต่ publisher เป็น harness ไม่ใช่ US/WF จริง · evidence รอบ session ก่อน (RefNo E2E-LOCAL-mqtflyy7) ยังไม่ได้ re-verify รอบนี้

อ่านบรรทัดเดียว: Postman (S1) ไม่เคยขับ saga ให้เขียวได้แม้แต่ hop เดียว — มันพังที่ submit ตั้งแต่ต้น · ที่ “เขียว 5/5” คือ S3 (ยิง ASB ตรง ไม่ใช่ Postman) · ที่ saga logic ถูกต้องคือ S2 (in-memory) · 3 อย่างนี้ห้ามนับรวมกัน


1. Boot 7/7 ✅ (พื้นฐานก่อนทุก surface)

checkผลหลักฐาน
7 service boot + /health 200✅ 7/7US
OC
WF
Task
NS
Codex
Central
ตอบ 200
ต่อ DB จริง (cluster Azure)Codex คืน app rows · OC/WF persist saga ลง DEV_OrchestratorDb
ต่อ ASB จริง (superapp-dev)OC register 6/6 consumer (“started — Topic=…”) ไม่มี error
WF ชี้ DEV_WorkflowDb โดยไม่ auto-migratelog [KeyVault] VaultUri='' + ไม่มี “Applying migration”

2. Surface S1 — Postman/newman HTTP run: ทีละ request ตั้งแต่แรกจนจบ

collection มี 44 request · รันจริง 18 (Setup 3 + Scenario A 15) · อีก 26 ไม่ได้ขับ (§3) รัน: newman ชน localhost fleet · เวลา 2026-06-25T11:01:03Z · report: scratchpad/reports/scenarioA.{html,xml} ตัวแปรที่จับได้: flow_instance_id = a2d3b444-f704-4492-8b71-beeff7651700 · ref_no = ว่างตลอด (submit ไม่เคยสำเร็จ → ไม่มี refNo ออกมา)

อ่านคอลัมน์: ควรได้ = ตาม design happy-path · จริง = HTTP code ที่ได้ + state · verdict ✅ ผ่าน / ❌ พังเอง (independent) / ⛔ cascade (พังต่อเนื่องเพราะ id ว่าง) / ⚠️ สรุปไม่ได้

#request (เจตนา)ควรได้จริง (รันแล้ว)verdict
100 NS whoami (no-auth diag)200 reachable200
200 US list flow-definitions200 list200
300 OC demo/onboarding?approve200 (= S2 in-memory saga)200 (11.7s, รัน timeline ในหน่วยความจำ)(S2 ไม่ใช่ S1)
4A1 US Start instance200 + refNo + step=OTP200 · flowInstanceId ออก · refNo=null · status=Draft · currentStep=OtpVerificationStep✅ create (refNo ยังว่างปกติ — ออกตอน submit)
5A2 US SaveDraft (CompanyInfoStep)200 draft saved500F6
6A3 US Submit (SubmitApplicationStep)2xx + publish flow-submitted + status=Submitted500 (ProblemDetails 400B) · ไม่ publish อะไรเลยF6 (ต้นเหตุทั้งหมด)
7A3b WF Create instance2xx + wfInstanceId500 (documentId ว่าง เพราะ refNo ว่าง)⚠️ สรุปไม่ได้ — ยิงด้วย documentId ว่าง ยังไม่ฟันธงว่า WF พัง
8A4 WF get by-document/{refNo}200 instance404 — URL เป็น by-document/ (refNo ว่าง)⛔ cascade
9A5 TS get task/ref/{refNo}200 task404 — URL เป็น tasks/ref/ (ว่าง)⛔ cascade
10A6 WF Pickup maker → InReview2xx → state InReview500wf_instance_id ว่างใน body⛔ cascade
11A7 US get status → คาด InReviewInReview200 แต่ status=Draft · step=OtpVerificationStep (ไม่ขยับ)✅ อ่านได้ / ❌ ไม่ advance
12A8 WF take-action maker → Reviewed2xx404 — URL Workflow//action (id ว่าง → double-slash)⛔ cascade
13A9 US get status → คาด ReviewedReviewed200 = Draft (เหมือนเดิม)✅ อ่าน / ❌
14A10 WF Pickup approver → InApprove2xx500 — id ว่าง⛔ cascade
15A11 US get status → คาด InApproveInApprove200 = Draft✅ อ่าน / ❌
16A12 WF take-action approver → Approved2xx404 — id ว่าง⛔ cascade
17A13 US get status → คาด ApprovedApproved200 = Draft✅ อ่าน / ❌
18A14 NS notifications200 list401 UnauthorizedF7

🔍 หลักฐานชี้ขาด (smoking gun)

A7/A9/A11/A13 (GET status 4 ครั้งระหว่างทาง) ได้ 200 ทุกครั้ง แต่คืนค่าเดิมตลอด:

{"data":{"flowInstanceId":"a2d3b444-…","refNo":null,
  "status":"Draft","currentStepType":"OtpVerificationStep", }}

instance ค้างอยู่ที่ step แรก (OTP) ไม่เคยขยับเลย · ทุก GET เขียวเพราะแค่ “อ่าน instance ที่ A1 สร้าง” ไม่ได้แปลว่า flow เดินหน้า

📌 สรุป S1 — เห็นภาพเดียวกัน

  1. เขียวจริงมีแค่: ping 3 ตัว (1–3) + A1 create + 4× GET-status (อ่านอย่างเดียว) · state-mutation ผ่าน HTTP พังหมด
  2. ต้นเหตุเดียว = F6 ที่ A3 (submit 500): NEW_REQUESTOR flow-def เริ่มที่ OtpVerificationStep แต่ collection กระโดดไปยิง SubmitApplicationStep (เป็น step ของ RETURNING_REQUESTOR) → guard ตัดสิน forbidden ถูกต้อง แต่ F6 ทำให้ออกเป็น 500 → refNo ไม่เคยเกิด → A4–A12 ทั้งหมดยิงด้วย id ว่าง = พังต่อเนื่อง (cascade)
  3. finding ที่ independent จริง ๆ มีแค่ 2 ตัว: F6 (submit→500) กับ F7 (NS 401) · ที่เหลือคือ cascade จาก id ว่าง — ไม่ใช่ bug แยก (ยังตัดสินไม่ได้จนกว่า submit จะผ่านแล้วได้ refNo จริง)
  4. A3b (WF create 500) = ยังสรุปไม่ได้ — ยิงด้วย documentId ว่าง · ต้องมี refNo จริงก่อนถึงจะรู้ว่า WF create พังจริงไหม

3. Surface S1 — 26 request ที่ “ไม่ได้ขับ” (เหตุผลเดียวกันหมด)

folderจำนวนทำไมไม่ขับ
Scenario B (Reject)3ต้องผ่าน A1–A6 ก่อน → ตันที่ submit/pickup เหมือน A
Scenario C (Rework→Resubmit)4เหมือนกัน
Scenario D (Cancel 2 ทาง)3เหมือนกัน
Scenario E (Customer auto-approve)4เริ่มที่ US submit เหมือนกัน (ไม่ผ่าน OC แต่ก็ติด submit ฝั่ง US)
Scenario F (Multi-approver)2ต้องถึง InApprove ก่อน → ไม่ถึง
Scenario G (Resubmit after session loss)2ต้องมี wf_instance_id จริง → ไม่มี
Scenario H (Closed)0placeholder — design ยังไม่นิยาม (defer D3)
99 OC Dev-Driver8endpoint dev-only — ขับเทียบเท่าผ่าน S3 (ยิง ASB ตรง) แทน

ทุก scenario เริ่มจาก submit ตัวเดียวกัน → ถ้า submit ยัง 500 ก็ block เหมือนกันหมด · ขับได้เมื่อ unblock §6


4. Surface S3 — Choreography spine 5/5 (ยิง ASB ตรง · ไม่ใช่ Postman · หลักฐานรอบก่อน)

ย้ำ provenance: ส่วนนี้ไม่ได้ขับด้วย Postman · ใช้ node @azure/service-bus craft message ที่ US/WF จะ publish แล้วยิงเข้า superapp-dev จริง → ดู OC consume→saga→persist · publisher เป็น harness สังเคราะห์ · evidence = session รอบก่อน (RefNo E2E-LOCAL-mqtflyy7 ใน DEV_OrchestratorDb) — รอบนี้ยังไม่ได้ re-verify

sequenceDiagram
    autonumber
    participant HR as Harness (node→ASB)
    participant OC as OrchestratorService
    participant DB as DEV_OrchestratorDb

    rect rgb(232,248,232)
        HR->>OC: ASB flow-submitted (superapp-dev จริง)
        OC->>DB: INSERT OrchestrationInstance = AwaitingPickup ✅
    end
    rect rgb(232,248,232)
        HR->>OC: ASB workflow-pickup {WfInstanceId=99001}
        OC->>DB: state = UnderReview ✅
    end
    rect rgb(232,248,232)
        HR->>OC: ASB sent-to-reviewer
        OC->>DB: state = UnderConsideration ✅ (05- เคย ❌ MISSING)
    end
    rect rgb(232,248,232)
        HR->>OC: ASB approval-pickup
        OC->>DB: state = InApprove ✅ (05- เคย ❌ ใหม่ 100%)
    end
    rect rgb(232,248,232)
        HR->>OC: ASB workflow-decision {Approve}
        OC->>DB: state = Approved / Lifecycle = Completed ✅
    end
    rect rgb(255,232,232)
        Note over OC: return path (flow-progress-update / flow-approval-result)
        Note over OC: saga raise outbox ✅ แต่ US consume ไม่ verify (synthetic FlowInstanceId)
    end
hopstateruntime (S3)หมายเหตุ
flow-submittedAwaitingPickupOC consume + persist จริง
workflow-pickupUnderReviewWfInstanceId=99001
sent-to-reviewerUnderConsideration05- เคยมาร์ค ❌ MISSING
approval-pickupInApprove05- เคยมาร์ค ❌ ใหม่ 100%
workflow-decision(Approve)Approved/Completedจบ saga
return → US → NS🟡/❌outbox raise จริง แต่ consume/NS ยังไม่ verify

คุณค่าของ S3: ยืนยันว่า “code แห้ง” ฝั่ง OC consume→saga→persist ทำงานจริงบน ASB จริง (รวม 3 hop ที่ 05- เคยมาร์คว่า MISSING) · ข้อจำกัด: publisher ไม่ใช่ US/WF จริง + ยังไม่ re-verify รอบนี้ → ก่อนเชื่อ ควรยิงซ้ำ+ query DEV_OrchestratorDb ใหม่


5. ติดอะไร — แยก independent vs cascade

Independent (เป็น bug/gap จริง ต้องจัดการ):

#ติดอะไรผลตอนรันสถานะ · เพื่อ unblock
F6FlowAccessGuard คืน Forbidden ด้วย Error.Failure (line 43/46/63) → ApiControllerBase map เป็น 500 ไม่ใช่ 403 (ทุก forbidden path)US submit/savedraft 500 → block S1 ทั้งหมด🔴 confirmed · fix: Error.FailureError.Forbidden (product fix ทีม US) · ⚠️ fix แล้วได้ 403 ถูก แต่ยัง submit ไม่ผ่านจนกว่าจะเดิน OTP จริง
F7NS ไม่มี env auth-bypassNS HTTP 401 (A14)🟡 defer · fix: [AllowAnonymous] หรือใส่ token
F4NotificationDb ขาด Config.AppConfigurations/CustomErrorCodes (42P01)NS seeder fail (boot degraded)🟡 open — confirm minimal-DB vs migration gap
F5inter-service URL = cluster-DNS ไม่ว่าง → ไม่ fall-back stubcall-time hard-fail (Centralized→Codex)🟡 open (config robustness)

Cascade (ไม่ใช่ bug แยก — พังเพราะ id ว่างหลัง submit ตาย): A4/A5 404 (refNo ว่าง) · A6/A10 500 (wf_instance_id ว่าง) · A8/A12 404 (//action) · A3b 500 (documentId ว่าง — สรุปไม่ได้) → ทั้งหมดจะหายเองเมื่อ submit ผ่านแล้วมี refNo จริง

Harness-side (เจอตอนทำ S3):

  • F9 node publisher ต้องส่ง body เป็น Buffer.from(json) (AMQP Data) ไม่งั้น .NET deserialize fail → dead-letter “Malformed” · กระทบจริงถ้ามี non-.NET producer บน prod
  • F9b (ไม่ใช่ bug) approval-pickup ครั้งแรกไม่ transition = harness race (publish เร็วเกิน, saga ExpectState reject out-of-order = ถูกต้อง) · เว้นจังหวะแล้วผ่าน

6. ตามต่อ หรือ ข้าม — เลือกได้ (chase-vs-skip)

งานนี้คือ “รู้ก่อน deploy ว่าต้องปิดอะไร” · แต่ละจุดมีต้นทุนต่างกัน — เลือกตามนี้:

จุดถ้า ตามต่อ ต้องทำอะไรต้นทุนถ้า ข้าม ยอมรับอะไร
ทำ S1 ให้เขียวจริง (HTTP path)flip OTP ExternalEntra→InternalGenerate (config ฝั่ง NS) แล้วเดิน NEW_REQUESTOR wizard 8 step จริง (OTP→…→submit) → US publish flow-submitted เองสูง (harness OTP + 8 step)พึ่งหลักฐาน S3 (ASB-injection) แทน · ยอมรับว่า US HTTP→publish ยังไม่เคย verify
แก้ F6Error.FailureError.Forbidden 3 จุดต่ำ (1 บรรทัด×3)prod ทุก forbidden ออกเป็น 500 (5xx alert ลวง) ต่อไป
ขับ WF จริง (แทน S3 harness)POST /instances → pickup → take-action จริง ให้ WF publish เองกลางเชื่อ S3 ว่า OC consume ถูก แต่ไม่รู้ว่า WF publish payload ตรง schema ไหม
re-verify S3 รอบนี้ยิง ASB ซ้ำ + query DEV_OrchestratorDb ใหม่ต่ำอ้างหลักฐานรอบก่อน (RefNo mqtflyy7) ตามเดิม
A3b / WF createต้องมี refNo จริงก่อน (ขึ้นกับ submit)ยังไม่รู้ว่า WF create พังจริงไหม
F7 / NS 401, F4, F5ตามตาราง §5ต่ำ–กลางไม่อยู่ critical path A · defer ได้

ขอ user ตัดสิน: จะให้เดิน “ตามต่อ S1 ให้เขียวเต็มเส้น” (ลงทุน OTP+8 step) หรือ “ข้าม S1 — พอใจกับ S3+S2 แล้วโฟกัสแก้ F6 เป็น product bug” · บอกมาได้เลยว่าจุดไหนข้าม


เอกสารหลักฐานละเอียด (command + DB query + log) อยู่ที่ Atlas docs/orchestration-integration/25062026/AC_REPORT.md ⚠️ หมายเหตุ: AC_REPORT.md + HANDOFF_LOCAL_E2E_RUNTIME.md ยังเขียนรวบ “เขียว 5/5” แบบไม่แยก 3 surface เหมือน v1 — ถ้าจะให้ตรงกับ v2 นี้ บอกได้ จะไปแก้ให้แยกชั้นเหมือนกัน