Private Docs

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):

IdentifierTypeCardIdPassportNo
NationalId= IdentifierIdnull
Passportnull= IdentifierId
ค่าว่าง/ยังไม่กรอกnullnull

ใช้งาน

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 ตรงๆ


ไฟล์อ้างอิง

สิ่งที่อยากดูไฟล์
นิยาม fieldBackend_Package/src/Middleware/RedisUserInfo/UserInfoForRedis.cs
ตัว middleware ที่อ่าน blobBackend_Package/src/Middleware/RedisUserInfo/RedisUserInfoMiddleware.cs
entity + กฎ projectionBackend_UserService/src/UserService04.Domain/Entities/Users/UserRestrictedProfile.cs
ตัว map เข้า blobBackend_UserService/src/UserService03.Application/Features/Users/UsersMapper.cs
ตัวเขียน RedisBackend_UserService/src/UserService02.Infrastructure/Caching/UserCacheRefreshService.cs
จุดเติมค่าตอน onboarding.../Features/Onboarding/Engine/Handlers/Customer/CreatePlatformUserHandler.cs และ .../PostApproval/CreateCompanyApplicationHandler.cs