SupApp_util_lib — ดึงเลขบัตรประชาชน / Passport ของ user
คู่มือใช้งาน CardId + PassportNo บน UserInfoForRedis (v10.8.0) — ทำไมมี 2 field ทั้งที่มี IdentifierId อยู่แล้ว, วิธีอ่าน, ค่าจะมีเมื่อไหร่, ข้อควรระวัง PDPA, gotchas
อัปเดต: 2026-08-05
วิธีที่ backend service ใน SuperAPP อ่าน เลขบัตรประชาชน และ หมายเลขหนังสือเดินทาง ของ user จาก Redis user-info blob โดยไม่ต้องเรียก UserService — ต่อยอดจาก คู่มือ Role/UserInfo ซึ่งอธิบาย pipeline หลักไว้แล้ว
ทำไมต้องมี 2 field ทั้งที่มี IdentifierId อยู่แล้ว
คำถามที่ควรถาม — และคำตอบตรงๆ คือ มันไม่ได้เพิ่มข้อมูลใหม่เลย
UserRestrictedProfiles เก็บ IdentifierId (ตัวเลข) คู่กับ IdentifierType (NationalId | Passport) มาตั้งแต่แรก ซึ่งแยกบัตรกับ passport ได้อยู่แล้ว — แต่เก็บได้ ทีละค่าเดียว
CardId / PassportNo คือ projection ของคู่นั้น มีไว้เพื่อความสะดวกของ consumer อย่างเดียว:
// ก่อน — ต้อง branch เอง และต้องรู้จัก enum
var cardId = info.IdentifierType == IdentifierType.NationalId ? info.IdentifierId : null;
// หลัง — อ่านตรงๆ
var cardId = info.CardId;
กฎที่ domain การันตีให้ (ไม่มีทาง diverge):
IdentifierType | CardId | PassportNo |
|---|---|---|
NationalId | = IdentifierId | null |
Passport | null | = IdentifierId |
| ค่าว่าง/ยังไม่กรอก | null | null |
ใช้งาน
1) bump package
<PackageReference Include="SupApp_util_lib" Version="10.8.0" />
2) setup ไม่มีอะไรเพิ่ม — ถ้า service คุณ wire RedisUserInfo ไว้แล้วตาม คู่มือหลัก ไม่ต้องแก้ Program.cs หรือ appsettings.json เลย field ใหม่มากับ blob เดิม
3) อ่านค่า
var info = HttpContext.GetUserInfo();
var cardId = info?.CardId; // string? — เลขบัตร 13 หลัก
var passportNo = info?.PassportNo; // string? — เลข passport
if (string.IsNullOrEmpty(cardId) && string.IsNullOrEmpty(passportNo))
{
// ยังไม่มีข้อมูล — ดู "ค่าจะมีเมื่อไหร่" ข้างล่าง
// อย่า throw: null เป็นสถานะปกติ ไม่ใช่ error
}
ค่าจะมีเมื่อไหร่
| กลุ่ม user | ได้ค่าจากไหน |
|---|---|
| End user ที่กด link register จากอีเมลเชิญ | ดึงจากใบสมัครของ requestor (designee record) ตอนสร้าง/ผูก account |
| Requestor ที่ระบุตัวเองเป็น end user (Shell-NR / self-binder) | เขียนลง user เดิมตอน self-bind — คนกลุ่มนี้ไม่ได้รับอีเมลเชิญ จึงมีทางเขียนแยกของตัวเอง |
| User ที่แก้เลขเอกสารผ่าน API อัปเดตโปรไฟล์ | projection ถูกคำนวณใหม่ทันทีในคำสั่งเดียวกัน |
| User ที่ onboard ไปก่อนที่ field นี้จะมี | เป็น null จนกว่าจะรัน backfill ของ env นั้น — ข้อมูลเดิมยังอยู่ครบใน IdentifierId เสมอ |
ค่าใหม่จะไปโผล่ใน Redis blob เมื่อ UserCacheRefreshService ทำงาน ซึ่งมี 3 จังหวะ: refresh อัตโนมัติหลัง command ที่แก้ user, endpoint warm (ต้องมี API key), หรือ TTL หมดอายุ (default 86400 วินาที)
PDPA — ข้อควรระวัง
สิ่งที่ consumer ต้องทำ:
- ห้าม log ค่านี้ ห้ามใส่ใน exception message ห้าม echo กลับใน error payload
- ห้ามส่งต่อออก response ของ endpoint ที่ไม่ได้ auth หรือไม่ได้ owner-scope
- ถ้าต้องแสดงผลบนหน้าจอ ให้ mask (เช่นโชว์ 4 ตัวท้าย) — เก็บค่าเต็มไว้เฉพาะตอนที่ต้องใช้จริง
อนาคต: มีแผนเข้ารหัส at-rest ด้วย EF value converter + key จาก KeyVault เมื่อถึงตอนนั้นจะมีการตัดสินใจว่า blob จะเก็บค่าเต็ม / mask / หรือถอดออก — อย่าออกแบบ feature ที่พึ่งค่าเต็มใน blob แบบถาวรโดยไม่คุยก่อน
Gotchas
SchemaVersion ยังเป็น 1 เหมือนเดิม — ตั้งใจ
การเพิ่ม field ครั้งนี้ ไม่ bump CurrentSchemaVersion เพราะถ้า version ไม่ตรง middleware จะ ไม่ inject อะไรเลยทั้ง request (ไม่ใช่ fallback ไป HTTP) ยาวจนกว่า TTL 24 ชั่วโมงจะหมด → service ที่ยังไม่ bump lib จะ auth พังทันที
field ใหม่จึงปลอดภัยทั้ง 2 ทาง: binary เก่าอ่าน blob ใหม่ = ข้าม member ที่ไม่รู้จัก, binary ใหม่อ่าน blob เก่า = ได้ null
bump lib แล้ว restore ไม่เจอ
dotnet nuget locals http-cache --clear ก่อน — NuGet cache ค้าง index เก่าได้แม้ version ขึ้น feed แล้ว
feed เป็น immutable
10.8.0 push ขึ้นไปแล้วแก้ไม่ได้ ถ้าต้องแก้อะไรใน UserInfoForRedis ต้องขยับเป็น 10.8.1
อย่าเขียนค่าเองจากฝั่ง consumer
field พวกนี้เป็น read-only จากมุม consumer — UserService เป็นเจ้าของ write path เดียว ถ้า service คุณมีความจำเป็นต้องเขียน ให้คุยก่อน อย่าไปยิง endpoint อัปเดต user ตรงๆ
ไฟล์อ้างอิง
| สิ่งที่อยากดู | ไฟล์ |
|---|---|
| นิยาม field | Backend_Package/src/Middleware/RedisUserInfo/UserInfoForRedis.cs |
| ตัว middleware ที่อ่าน blob | Backend_Package/src/Middleware/RedisUserInfo/RedisUserInfoMiddleware.cs |
| entity + กฎ projection | Backend_UserService/src/UserService04.Domain/Entities/Users/UserRestrictedProfile.cs |
| ตัว map เข้า blob | Backend_UserService/src/UserService03.Application/Features/Users/UsersMapper.cs |
| ตัวเขียน Redis | Backend_UserService/src/UserService02.Infrastructure/Caching/UserCacheRefreshService.cs |
| จุดเติมค่าตอน onboarding | .../Features/Onboarding/Engine/Handlers/Customer/CreatePlatformUserHandler.cs และ .../PostApproval/CreateCompanyApplicationHandler.cs |