name: atomic-lld-design description: | Thiết kế Low-Level Design (LLD) cho từng bảng nguồn trong Atomic source system. Sử dụng khi: thiết kế attribute-level cho 1 bảng/Tier, map source columns sang Atomic attributes, tách shared entity (IP Postal Address / IP Electronic Address / IP Alt Identification), xuất file lld_{SOURCE}_{TABLE}.yaml trong DataModel/working/Atomic/lld/{SOURCE}/. Cũng dùng khi: consolidate entity từ nhiều source (Level 2), cập nhật manifest.yaml, classification_schemes.yaml, pending_design.yaml; chạy validate_lld_yaml.py, aggregate_atomic.py, post_check_atomic.py, post_check_source_coverage.py. Yêu cầu: HLD đã duyệt cho source_system tương ứng.
Skill: Thiết kế LLD (Low-Level Design)
Đọc file này TRƯỚC KHI bắt đầu thiết kế LLD cho bất kỳ bảng nguồn nào.
Tài nguyên đi kèm
- Templates YAML (copy + replace placeholder — dùng cho thiết kế mới):
templates/lld_main_entity.yaml— skeleton cho entity chính (PK + BK + FK + audit).templates/lld_shared_IP_Postal.yaml— IP Postal Address.templates/lld_shared_IP_Electronic.yaml— IP Electronic Address (PHONE/FAX/EMAIL/WEBSITE).templates/lld_shared_IP_Alt_Identification.yaml— IP Alt Identification.templates/entity_template.yaml— skeleton Level 2 entity consolidation.
- Templates CSV (legacy — chỉ dùng nếu cần tham khảo format cũ):
- Reference (rule chuẩn dùng chung dự án):
reference/data_domains.md— 12 Data Domain chuẩn + 2 mở rộng.reference/shared_entity_schemas.md— tên trường chuẩn 3 shared entity, quy tắcclassification_context, trường địa lý.reference/post_check_codes.md— chi tiết C1–C5 và source coverage check.reference/file_layout.md— vị trí + encoding + cấu trúc tất cả file LLD.
ĐIỀU KIỆN TIÊN QUYẾT
- HLD đã được duyệt cho source system đang thiết kế.
- File HLD nằm tại
DataModel/working/Atomic/hld/{SOURCE}_HLD_Overview.mdvà{SOURCE}_HLD_Tier{N}.md.
QUY TRÌNH THIẾT KẾ LLD
Bước 0 — Pre-flight check
Trước khi bắt đầu bất kỳ thiết kế nào, kiểm tra trạng thái file LLD đã có:
- Đọc
DataModel/working/Atomic/lld/manifest.yaml→ lấy danh sáchlld_filecho source đang thiết kế. - Với mỗi bảng cần thiết kế, kiểm tra file
DataModel/working/Atomic/lld/{SOURCE}/lld_{SOURCE}_{TABLE}.yaml:
| Trạng thái | Hành động |
|---|---|
File không tồn tại hoặc design_status: draft |
✅ Tiếp tục thiết kế |
File tồn tại, design_status: reviewed |
⚠️ Hỏi xác nhận trước khi ghi đè: "File đã reviewed — tạo lại?" |
File tồn tại, design_status: approved |
⛔ SKIP hoàn toàn — KHÔNG ghi đè |
Quy tắc: approved = đã qua review + approval trong App. AI không bao giờ ghi đè file approved. Nếu cần sửa file đã approved → người thiết kế phải đổi design_status về reviewed hoặc draft thủ công trong App trước.
Bước 1 — Đọc context
Đọc TRƯỚC KHI thiết kế:
- HLD Overview (
{SOURCE}_HLD_Overview.md) → tổng quan entity, quan hệ, BCV Concept đã thống nhất. - HLD Tier tương ứng (
{SOURCE}_HLD_Tier{N}.md) → chi tiết entity và quan hệ Tier đang thiết kế. - Source columns (
Source/{SOURCE}_Tables.csv,{SOURCE}_Columns.csv) → cột, data type, mô tả gốc. Ghi nhận data type của từng cột nguồn — dùng ở Bước 3b để review conversion risk và ghi chú khi data type nguồn không khai báo rõ ràng. - Tất cả file LLD đã có trong cùng source system (
DataModel/working/Atomic/lld/{SOURCE}/):- Entity đã thiết kế và cấu trúc attribute.
- Pattern FK đã dùng (tên trường, data domain).
- Shared entity đã có những trường nào.
- LLD entity tương đồng từ source khác (nếu có): Nếu entity đang thiết kế có kiểu tương đồng với entity ở source khác (cùng BCV Concept, hoặc cùng loại shared entity), đọc ít nhất 1 file LLD tương ứng từ source đó. Mục đích: lấy đúng pattern tên attribute, format nullable, format source_columns, FK comment.
- Ví dụ: thiết kế IP Postal Address cho FMS → đọc
DataModel/working/Atomic/lld/NHNCK/lld_NHNCK_PROFESSIONALS_IP_Postal_Address.yaml. - Ví dụ: thiết kế entity
[Involved Party] Organization→ đọcDataModel/working/Atomic/lld/DCST/lld_DCST_THONG_TIN_DK_THUE.yaml(nếu đã có).
- Ví dụ: thiết kế IP Postal Address cho FMS → đọc
Atomic/lld/classification_schemes.yaml→ kiểm tra Classification Value đã chuẩn hóa.DataModel/working/Atomic/lld/manifest.yaml→ biết file LLD nào đã có vàdesign_statustương ứng.
Bước 2 — Xác định Atomic entity target và Tier
Từ HLD đã duyệt, xác định:
- Bảng nguồn này map về Atomic entity nào?
- BCV Concept và Category đã gán?
- Quan hệ FK với entity nào?
- Entity này thuộc Tier mấy?
Thứ tự thiết kế theo Tier: Hoàn thành LLD Tier N trước khi bắt đầu Tier N+1. Entity Tier sau có FK đến entity Tier trước — cần LLD Tier trước để lấy đúng tên attribute FK.
Bước 3 — Thiết kế attribute-level
Copy templates/lld_main_entity.yaml làm starting point. Replace placeholder, điền từng attribute theo quy tắc dưới. Sinh physical_name cho mỗi attribute theo thuật toán longest-match-first từ system/rules/rule_transform_logical_name.csv (xem mục Physical name bên dưới). data_type để trống — transform_physical_names.py sẽ tự điền dựa vào data_domain.
3a. Mô tả (description)
- Ghép 2 phần: mô tả gốc từ CSDL nguồn (giữ nguyên) + mô tả bổ sung trên model (nếu có).
- Không bỏ mô tả nguồn, không viết lại theo cách hiểu riêng.
- Tiếng Việt PHẢI có dấu đầy đủ (Unicode UTF-8). Không viết Việt-không-dấu, không viết tắt. Hiển thị trực tiếp trong tài liệu Word handover (
atomic-gen-docs). Nếu mô tả gốc từ CSDL nguồn không có dấu → bổ sung dấu khi copy.
3b. Data Domain
Dùng Data Domain phù hợp nhất với ý nghĩa nghiệp vụ của attribute (chi tiết xem reference/data_domains.md). 2 Data Domain mở rộng cho junction denormalized: Array<Text>, Array<Struct>.
Bước 1 — Chọn Data Domain theo nghĩa nghiệp vụ (ưu tiên ngữ nghĩa, không ép theo data type nguồn):
- Ý nghĩa là tiền tệ →
Currency Amount, dù nguồn lưuvarchar - Ý nghĩa là lãi suất →
Interest Rate; tỷ giá →Exchange Rate; phần trăm →Percentage - Ý nghĩa là ngày (không có giờ) →
Date; ngày + giờ →Timestamp - Ý nghĩa là cờ True/False →
Boolean; số đếm/version →Small Counter - Ý nghĩa là mã phân loại →
Classification Value; FK surrogate →Surrogate Key - Không thuộc các loại trên →
Text
Nếu ý nghĩa nghiệp vụ không ánh xạ được vào bất kỳ Data Domain hiện có nào → đề xuất Data Domain mới kèm định nghĩa và data type vật lý dự kiến, ghi vào comment với tag [PROPOSE NEW DOMAIN] để reviewer xem xét bổ sung vào reference/data_domains.md.
Bước 2 — Review conversion risk: đối chiếu Data Domain đã chọn với data type nguồn:
Sau khi chọn xong Data Domain, đọc lại data type của cột nguồn trong Columns.csv và ghi chú nếu có chênh lệch:
| Tình huống | Hành động |
|---|---|
Data type nguồn khớp tự nhiên với domain (ví dụ: date → Date, decimal → Currency Amount) |
Không cần ghi chú thêm |
Data type nguồn hẹp hơn domain nhưng là widening conversion (ví dụ: date → Timestamp, int → decimal) |
Không cần ghi chú — ETL cast tự nhiên, không mất dữ liệu |
Data type nguồn là string/varchar nhưng domain chọn là số (Small Counter, Currency Amount...) |
Ghi chú vào comment: "Nguồn lưu dạng string — ETL cần cast/parse sang [data type vật lý]. Cần validate không có giá trị non-numeric." |
Data type nguồn là số (int, decimal) nhưng domain chọn là Text hoặc Classification Value |
Ghi chú: "Nguồn lưu dạng số — ETL cần convert sang string. Giữ nguyên leading zeros nếu có." |
| Data type nguồn không khai báo trong Columns.csv | Ghi chú: "Data type nguồn không rõ — cần profile trước khi ETL. Domain tạm chọn dựa trên mô tả cột." |
Mục đích của Bước 2 là không thay đổi domain đã chọn mà là ghi nhận conversion risk để team ETL biết trước. Chuẩn hóa dữ liệu theo ngữ nghĩa là đúng; ép kiểu cần được thực hiện có kiểm soát.
3c. FK đến Fundamental entity
- Luôn tạo cặp
[Entity] Id+[Entity] Code— kể cả khi nullable. - Id: data domain =
Surrogate Key. - Code: data domain =
Text. - Nếu Code = NULL thì Id cũng = NULL → cặp nhất quán.
3d. Classification Value
Chỉ 1 trường Code (data domain =
Classification Value). KHÔNG tạo cặp Id + Code.Áp dụng cho: Classification Value, Currency, Calendar Date, mọi bảng danh mục SCD1 không có surrogate key.
etl_derived_valuebắt buộc điền cho Classification Value:Dạng classification_contextetl_derived_valueSCHEME=VALUE(cố định, VD:IP_ELEC_ADDR_TYPE=PHONE)Điền literal VALUE: PHONESOURCE_SYSTEM=SRC.TABLEĐiền literal: SRC.TABLESCHEME(không có=VALUE, dynamic — VD:IP_ADDR_TYPE)Để null hoặc ghi expression mapping ETL (VD: 1=CMND;2=CCCD;3=PASSPORT)Không có classification_contextĐể null Lưu ý quan trọng — IP Postal Address: Nếu bảng nguồn chỉ có 1 loại địa chỉ cụ thể (VD: chỉ có
PERMANENT_ADDRESS, không có cột address_type), KHÔNG dùng bareIP_ADDR_TYPE— phải hardcode:IP_ADDR_TYPE=PERMANENT. Bare context khiến aggregate bỏ sótAddress Type Codekhi merge nhiều source. Chỉ dùngIP_ADDR_TYPE(bare/dynamic) khi nguồn thực sự có cột type động qua lookup.
3e. PK nguồn và BK
- PK bảng nguồn (VD:
ID) → map vào Entity Code (BK), không đưa vào technical field. - Mã nghiệp vụ khác có tính unique (VD:
MA_SO_THUE) → trường nghiệp vụ riêng, không phải BK.
3f. Source System Code
Format bắt buộc — cả 2 trường phải nhất quán:
| Trường | Giá trị bắt buộc |
|---|---|
classification_context |
SOURCE_SYSTEM=NHNCK.TABLE_NAME |
etl_derived_value |
NHNCK.TABLE_NAME (phần VALUE sau dấu =) |
TABLE_NAME = tên bảng nguồn cụ thể (không phải chỉ tên source system).
Pattern sai — KHÔNG dùng:
| Pattern sai | Lý do |
|---|---|
SOURCE_SYSTEM (bare, thiếu =VALUE) |
aggregate không derive được etl_derived_value |
'' (trống) |
aggregate bỏ qua hoàn toàn |
'ETL-derived = NHNCK.TABLE' (free-text) |
không đúng format SCHEME=VALUE |
'SCHEME=SOURCE_SYSTEM' (key/value đảo ngược) |
context không có ý nghĩa |
'Scheme: SOURCE_SYSTEM. ...' (free-text) |
không phải machine-readable format |
3g. Metadata nguồn
- Trường metadata truyền nhận (VD:
GOI_TIN_ID) → trường nghiệp vụ bình thường, không đưa vào nhómds_.
3h. Trường denormalized
- Trường chứa thông tin entity khác nhưng không có cơ chế link → giữ dạng text denormalized. Không đề xuất "map ở entity khác" nếu không có link thực tế.
3i. Bảng junction denormalized theo HLD
Nếu HLD đã quyết định denormalize 1 bảng junction thành ARRAY trên entity cha:
- Thêm attribute vào file LLD của entity cha (không tạo file LLD riêng, không thêm vào manifest).
data_domain=Array<Text>(junction chỉ có code) hoặcArray<Struct>(junction có cặp Id + Code).source_columns= FK phía bên kia của junction (VD:FMS.SECBUSINES.BuId).comment: tên bảng junction gốc + tham chiếu HLD + schema struct nếu làArray<Struct>. Mẫu:Pure junction {TABLE} → denormalize thành ARRAY. Struct: {field1: Domain1; field2: Domain2}. HLD decision: {file HLD}.- Tên attribute: danh từ số nhiều phản ánh nội dung phần tử (VD:
Business Type Codes,Distribution Agent Ids).
3j. Merge entity từ 2 bảng nguồn 1-1 — xử lý cột duplicate
Khi 1 Atomic entity gộp từ 2 bảng nguồn quan hệ 1-1 (VD: Public Company = company_profiles + company_detail), thường có cột trùng giá trị (name VI/EN, business_reg_no, ticker, audit fields).
Quy tắc:
- Chọn 1 bảng làm primary source cho các cột trùng — map
source_columnstừ bảng đó. - Cột trùng của bảng kia document trong
pending_design.yaml:reason: "Giá trị 1-1 với {primary_table}.{col}. Map primary từ {primary_table}."action: "Đã capture qua {primary_table} (1-1)"
- KHÔNG ghi
"X.col1, Y.col2"trongsource_columns. Scriptpost_check_atomic.pyC5 kiểm tra format đúng 3 phầnSOURCE.table.column. - PK kỹ thuật của bảng phụ (VD:
company_detail.id) cũng document pending: "PK kỹ thuật riêng của bảng detail, không phải BK của entity."
3k. Audit block (Created/Updated)
Khi bảng nguồn có cặp CREATED_AT / CREATED_BY / UPDATED_AT / UPDATED_BY, luôn map theo block 6 attribute chuẩn:
| Attribute Name | Data Domain | source_columns | Comment |
|---|---|---|---|
Created Timestamp |
Timestamp |
*.CREATED_AT |
(trống) |
Updated Timestamp |
Timestamp |
*.UPDATED_AT |
(trống) |
Created By [Entity] Id |
Surrogate Key |
*.CREATED_BY |
FK target: {Entity}.{Entity} Id. |
Created By [Entity] Code |
Text |
*.CREATED_BY |
Lookup pair: {Entity}.{Entity} Code. Pair with Created By [Entity] Id. |
Updated By [Entity] Id |
Surrogate Key |
*.UPDATED_BY |
FK target: {Entity}.{Entity} Id. |
Updated By [Entity] Code |
Text |
*.UPDATED_BY |
Lookup pair: {Entity}.{Entity} Code. Pair with Updated By [Entity] Id. |
Quy tắc:
[Entity]= tên ngắn của Atomic entity đích dùng trong tên attribute (ví dụ:Officerkhi FK target làRegulatory Authority Officer).- Comment
FK target:vàLookup pair:phải dùng tên attribute đầy đủ (có prefix entity) — không dùng tên rút gọn.- Đúng:
FK target: Regulatory Authority Officer.Regulatory Authority Officer Id. - Sai:
FK target: Regulatory Authority Officer.Officer Id.
- Đúng:
- Self-reference (entity FK về chính nó): vẫn dùng đầy đủ cặp Id + Code — không bỏ Id.
- Nguồn
DATE(không có giờ): vẫn dùng domainTimestamp— widening conversion, không cần ghi chú. - FK target chưa xác định (entity chưa thiết kế): giữ đủ 6 attribute, đặt
status=pending, commentPending — FK target chưa xác định.
Bước 4 — Rà soát shared entity
Nếu bảng nguồn có grain = 1 Involved Party:
- Trường địa chỉ → IP Postal Address (
templates/lld_shared_IP_Postal.yaml) - Trường liên lạc → IP Electronic Address (
templates/lld_shared_IP_Electronic.yaml) - Trường giấy tờ → IP Alt Identification (
templates/lld_shared_IP_Alt_Identification.yaml)
Involved Party bao gồm cả cá nhân lẫn tổ chức. Không phân biệt loại IP — chỉ cần entity chính đang mô tả 1 IP (cá nhân, tổ chức, công ty, chi nhánh...) là phải tách shared entity.
Quy tắc grain = Involved Party luôn áp dụng, không phụ thuộc HLD Tier có liệt kê shared entity hay không. Nếu HLD Tier chưa có shared entity tương ứng, đồng bộ tài liệu sau khi thiết kế LLD:
- Thêm entry vào
DataModel/working/Atomic/lld/manifest.yaml(blockentries:). - Cập nhật
source_tabletrong HLD Overview và HLD Tier tương ứng. - Ghi 1 dòng vào "Điểm cần xác nhận" của HLD Tier mô tả quyết định tách shared entity.
Tên trường + schema chuẩn cho 3 shared entity: xem reference/shared_entity_schemas.md. File này chứa:
- Bảng tên trường chuẩn cho IP Postal / IP Electronic / IP Alt Identification.
- Quy tắc
classification_context(SCHEME=VALUEbắt buộc, pattern(source)cho type động). - Quy tắc trường địa lý (4 cách xử lý theo bối cảnh nguồn).
- Cột nguồn không map được vào schema chuẩn → document trong
pending_design.yaml.
Nếu grain KHÔNG phải Involved Party → KHÔNG tách, giữ denormalized. Ví dụ: snapshot tờ khai thuế, quyết định hành chính, log kỹ thuật — địa chỉ trong các entity này là denormalized hợp lệ.
Bước 5 — Viết comment
Thứ tự: tag automation trước, notes sau.
FK đến Fundamental entity:
Phân biệt Id (FK constraint thực sự) vs Code (denormalized lookup, không phải FK constraint):
Id — FK constraint duy nhất (Surrogate Key):
FK target: {Atomic Entity Name}.{Atomic Entity Name} Id. {notes}→atomic-gen-docsparse prefixFK target:và đưa vào bảng Constraint của tài liệu CSDL.Hash comment — bắt buộc bổ sung cho ETL: ETL hash surrogate Id từ 2 input:
(source_system_code, business_key). FK_SOURCE = source table của target entity, xác định từSource/{SOURCE}_Columns.csvcột "Ghi chú (FK suy luận)".Case source_columns Hash comment FK bình thường [SRC.TABLE.FK_COL]Hash: hash_id('SRC.TARGET_TABLE', FK_COL).Shared entity (IP sub-table, dùng PK parent) [SRC.PARENT_TABLE.ID]Hash: hash_id('SRC.PARENT_TABLE', ID).FK luôn NULL [](rỗng)Không thêm hash — ghi lý do NULL thay thế Ví dụ:
- Normal:
"FK target: Securities Practitioner.Securities Practitioner Id. Hash: hash_id('NHNCK.PROFESSIONALS', PROFESSIONAL_ID)." - Shared entity:
"FK target: Securities Organization Reference.Securities Organization Reference Id. Shared entity. Hash: hash_id('NHNCK.ORGANIZATIONS', ID)." - Always null:
"FK target: Geographic Area.Geographic Area Id. NULL vì COUNTRIES không có parent."
- Normal:
Code — denormalized lookup (KHÔNG phải FK constraint, chỉ là copy giá trị business key cho tiện query):
Lookup pair: {Atomic Entity Name}.{Atomic Entity Name} Code. Pair with {Id field name}. {notes}→atomic-gen-docsKHÔNG đưa Code vào bảng Constraint. Chỉ Id mới sinh constraint.Currency Code (Classification Value pattern, không có Id surrogate):
FK target: Currency.Currency Code. {notes}→ vẫn dùngFK target:vì đây là FK constraint trực tiếp đến Currency entity (không có cặp Id+Code).
Tại sao tách syntax: parser của atomic-gen-docs đơn giản hoá — chỉ scan FK target: để build Constraint. Code có comment Lookup pair: → tự động không match → không bị duplicate trong Constraint table (đúng chuẩn DBA: 1 FK = 1 constraint, không lặp lại Code).
Classification Value:
Scheme: {SCHEME_CODE}. {notes}- Scheme Code =
UPPER_SNAKE_CASE, nhất quán vớiclassification_schemes.yaml. - KHÔNG dùng cả
FK target:vàScheme:cho cùng 1 trường. - Bắt buộc cross-check: Mọi Scheme Code dùng trong LLD phải tồn tại trong
classification_schemes.yaml. Nếu chưa có → thêm vào ref file ngay trong cùng lượt thiết kế.
Trường nghiệp vụ:
- Ghi BCV Term đã tra cứu được (nếu có) + lý do chọn tên attribute.
- Nếu tên khác BCV Term → giải thích lý do.
- Nếu BCV không có → ghi "BCV: không có term riêng" + cơ sở đặt tên.
Shared entity: Ghi note nhất quán với LLD nào đã duyệt.
Bước 6 — Kiểm tra nhất quán
Trước khi xuất file:
- FK trỏ về entity đã thiết kế → dùng đúng tên trường từ file LLD đã duyệt?
- Shared entity đã có cấu trúc → không thiết kế lại, chỉ bổ sung source mapping?
- Pattern đã dùng (Source System Code, BK, Classification Value) → giữ nguyên?
- Prefix nhất quán trong nhóm trường liên quan?
- Prefix chủ thể cho trường mô tả người/đối tượng khác?
- Mọi trường nguồn đều xuất hiện trong mapping? Không có dòng "không map ở đây"?
- LLD không bao gồm technical fields (ds_*) — xem danh sách chuẩn tại
reference/technical_fields.md? - Tên attribute cùng ý nghĩa với LLD source khác đã có → dùng đúng tên đó (
Charter Capital Amount,Life Cycle Status Code...)? - Entity dùng chung nhiều source: attribute tên công ty/tên tắt/tên tiếng Anh phải dùng prefix entity nhất quán (
Fund Management Company Name,Custodian Bank Short Name) — KHÔNG dùngFull Name/Abbreviation/English Namecho entity shared. - Format
nullablenhất quán:true/false— không dùngYes/No. - Conversion risk: Mọi attribute có Data Domain không khớp tự nhiên với data type nguồn (ví dụ: nguồn
string→ domainSmall Counter) đã có comment ghi chú conversion risk chưa? Nếu data type nguồn không khai báo → đã ghi "cần profile" trong comment? - Domain mới: Nếu có attribute dùng tag
[PROPOSE NEW DOMAIN]→ đã tách thành điểm cần xác nhận riêng để reviewer quyết định bổ sung vàoreference/data_domains.md? - FK comment (xem Bước 5): Id ghi
FK target: ..., Code ghiLookup pair: ... Pair with {Id field}— KHÔNG ghiFK target:cho cả Id+Code. Currency Code (Classification Value pattern, không có Id) ghiFK target:. - FK hash comment (xem Bước 5): Mọi FK Id có
source_columnskhông rỗng → comment phải cóHash: hash_id('SRC.TARGET_TABLE', COL).(FK_SOURCE tra từSource/{SOURCE}_Columns.csv). FK vớisource_columns: []→ không thêm hash, ghi lý do NULL. - Audit block (xem Bước 3k): Bảng nguồn có
CREATED_AT / CREATED_BY / UPDATED_AT / UPDATED_BY→ đủ 6 attribute chuẩn. Comment FK target dùng tên attribute đầy đủ (có prefix entity). Self-reference vẫn có cặp Id + Code. - Format
source_columnsnhất quán: fully qualifiedSOURCE_SYSTEM.schema.Table.Column. - Shared entity: FK dùng
Involved Party Id/Involved Party Code— không dùng tên entity cha. - Bảng junction denormalized theo HLD → attribute ARRAY đã thêm vào entity cha, không có trong manifest.
- Cross-check scheme: Mọi
Scheme: XYZtrong cột comment và mọiXYZ=trong cộtclassification_contextđều có trongclassification_schemes.yaml. - Trường địa lý: mã quốc gia/tỉnh/huyện/xã được xử lý đúng theo bối cảnh nguồn (xem
reference/shared_entity_schemas.md). - Shared entity type động: Nếu nguồn có cột type qua lookup_values (
identity_type_cd...) → đã dùngSCHEME=(source)placeholder chưa? Không để bare context. - Shared entity — cột không map: PK kỹ thuật / audit fields / business flag của bảng nguồn shared đã được document trong
pending_design.yaml? - Merge entity 1-1:
source_columnsKHÔNG dùng format comma-separated"X.col1, Y.col2"— chỉ 1 bảng primary, bảng còn lại document pending. - scope_status sync: Sau khi lưu LLD file → chạy sync script (xem section "Cập nhật scope_status trong BRD Source YAML") → kiểm tra tất cả source_tables (metadata + source_columns) đã là
in_scopetrongbrd_{SOURCE}.yaml. - Encoding: mọi file CSV ghi UTF-8 with BOM (
utf-8-sig) — xemreference/file_layout.md. -
etl_derived_valuecho Classification Value: Mọi row cóclassification_context = SCHEME=VALUE→etl_derived_value = VALUE. Mọi rowSOURCE_SYSTEM=SRC.TABLE→etl_derived_value = SRC.TABLE. Dynamic context (không có=VALUE) → null hoặc expression mapping. - Source System Code:
classification_context = SOURCE_SYSTEM=NHNCK.TABLE_NAME(không free-text, không bare, không trống);etl_derived_value = NHNCK.TABLE_NAME(bắt buộc, không trống). - Post-check C7 + C8: Sau aggregate, chạy
post_check_atomic.py— C7 kiểm tra mọiClassification Valuecó contextSCHEME=VALUEđều cóetl_derived_value; C8 kiểm tra riêngSource System Code. - Post-check: Sau khi chạy aggregate, chạy
post_check_atomic.py(xemreference/post_check_codes.md) và xử lý mọi warning trước khi kết thúc Tier. - Source coverage: Chạy
post_check_source_coverage.py --source {SOURCE}— mọi bảng đã thiết kế đều có 100% cột map (hoặc pending với reason rõ).
OUTPUT
File LLD (.yaml) — Level 1
Tên file: lld_{SOURCE_SYSTEM}_{SOURCE_TABLE}.yaml (entity chính)
hoặc lld_{SOURCE_SYSTEM}_{SOURCE_TABLE}_IP_Postal_Address.yaml v.v. (shared entity).
Mỗi file = 1 bảng nguồn. Ghi vào DataModel/working/Atomic/lld/{SOURCE_SYSTEM}/.
design_status: draft khi xuất ra. Human review trong App → đổi thành reviewed → approved.
Ví dụ non-shared (entity chính):
schema_type: lld_source_table
schema_version: "2.0"
metadata:
source_system: NHNCK
source_table: PROFESSIONALS
atomic_entity: Securities Practitioner
entity_physical_name: scr_practitioner
bcv_core_object: Involved Party
bcv_concept: "[Involved Party]"
table_type: Fundamental
group: T1
design_status: draft
version: "1.0"
designed_by: null
designed_at: null
reviewed_by: null
reviewed_at: null
approved_by: null
approved_at: null
notes: null
attributes:
- attribute_name: Securities Practitioner Id
physical_name: scr_practitioner_id
description: "Khóa đại diện (surrogate key)."
data_domain: Surrogate Key
nullable: false
is_primary_key: true
status: draft
source_columns: []
comment: null
classification_context: null
etl_derived_value: null
- attribute_name: Securities Practitioner Code
physical_name: scr_practitioner_code
description: "Mã NHN do UBCKNN cấp. Map từ PK bảng nguồn."
data_domain: Text
nullable: false
is_primary_key: false
status: draft
source_columns:
- NHNCK.qlnhn.PROFESSIONALS.ID
comment: "BCV Term: Individual Identifier. BK của entity."
classification_context: null
etl_derived_value: null
- attribute_name: Source System Code
physical_name: src_stm_code
description: "Mã hệ thống nguồn dữ liệu."
data_domain: Classification Value
nullable: false
is_primary_key: false
status: draft
source_columns: []
comment: "Scheme: SOURCE_SYSTEM."
classification_context: SOURCE_SYSTEM=NHNCK.PROFESSIONALS
etl_derived_value: NHNCK.PROFESSIONALS
Physical name: Sinh physical_name theo quy tắc B1→B2→B3 trong section QUY TẮC ĐẶT physical_name ở cuối file. data_type để trống — transform_physical_names.py tự patch sau.
Cập nhật manifest.yaml
Đọc DataModel/working/Atomic/lld/manifest.yaml, thêm entry cho file LLD mới vừa tạo (nếu chưa có):
- source_system: NHNCK
source_table: PROFESSIONALS
atomic_entity: Securities Practitioner
group: T1
lld_file: NHNCK/lld_NHNCK_PROFESSIONALS.yaml
design_status: draft
Cập nhật classification_schemes.yaml
- Đọc toàn bộ file hiện tại.
- Bổ sung scheme/giá trị mới phát sinh.
- Xuất 1 file duy nhất chứa toàn bộ cũ + mới.
Cập nhật scope_status trong BRD Source YAML
Sau khi lưu LLD file (hoặc sau khi hoàn thành cả Tier), chạy sync scope cho toàn bộ
LLD đã có của source. Đây là bước đánh in_scope chính thức — thay thế hoàn toàn
Giai đoạn 4b của source-survey.
Thu thập source tables từ toàn bộ LLD của source:
metadata.source_table— bảng chính của mỗi LLD file- Pattern
"{SOURCE}.TABLE.COL"trongsource_columns— bảng phụ/join được reference
Tất cả bảng tìm được → đánh scope_status: in_scope, kể cả bảng hiện đang out_of_scope.
import re, glob, sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
SOURCE = "{SOURCE}" # thay bằng source đang thiết kế
lld_tables = set()
for f in glob.glob(f"DataModel/working/Atomic/lld/{SOURCE}/lld_{SOURCE}_*.yaml"):
content = open(f, encoding='utf-8').read()
m = re.search(r'source_table:\s+"([^"]+)"', content)
if m:
lld_tables.add(m.group(1))
for ref in re.findall(rf'"{SOURCE}\.([A-Z_]+)\.[A-Z_]+"', content):
lld_tables.add(ref)
print(f"Tables to mark in_scope ({len(lld_tables)}): {sorted(lld_tables)}")
with open(f'BRD/Source/brd_{SOURCE}.yaml', encoding='utf-8') as f:
brd_content = f.read()
changed = []
def patch(m):
block = m.group(0)
tm = re.search(r'^ table:\s+(\S+)', block, re.MULTILINE)
if not tm or tm.group(1) not in lld_tables:
return block
for old_status in ('pending', 'out_of_scope'):
if f'scope_status: {old_status}' in block:
changed.append(tm.group(1))
return block.replace(f'scope_status: {old_status}', 'scope_status: in_scope')
return block # đã là in_scope
patched = re.sub(
r'(?s)(^- brd_id:.*?)(?=^- brd_id:|\Z)',
patch, brd_content, flags=re.MULTILINE
)
open(f'BRD/Source/brd_{SOURCE}.yaml', 'w', encoding='utf-8').write(patched)
print(f"Đã đánh in_scope ({len(changed)} bảng): {sorted(changed)}")
Sau khi patch: python scripts/generate_brd_summary.py
Bước 7 — Validate LLD YAML
Sau khi thiết kế xong 1 bảng (hoặc cả Tier), chạy validate:
python DataModel/working/Atomic/lld/scripts/validate_lld_yaml.py --source {SOURCE}
# Hoặc validate 1 file:
python DataModel/working/Atomic/lld/scripts/validate_lld_yaml.py --file DataModel/working/Atomic/lld/{SOURCE}/lld_{SOURCE}_{TABLE}.yaml
Điều kiện passed: Failed: 0. Xử lý mọi E1–E6 trước khi kết thúc Tier.
Xử lý mọi warning trước khi kết thúc Tier. Sau validate, thông báo cho người thiết kế: "Tiếp theo: Review trong App → post_check → approve → trigger Consolidate nếu entity đến từ nhiều source."
Bước 8 — Post-check (sau khi Human approve Level 1)
Khi đã approve toàn bộ bảng của Tier trong App, chạy post-check từ YAML:
python DataModel/working/Atomic/lld/scripts/post_check_atomic.py --source {SOURCE}
python DataModel/working/Atomic/lld/scripts/post_check_source_coverage.py --source {SOURCE}
Xử lý mọi warning (chi tiết C1–C5 xem reference/post_check_codes.md) trước khi sang bước tiếp.
Bước 9 — Entity Consolidation (Level 2, optional)
Điều kiện: Entity đến từ nhiều source tables (VD: Securities Organization Reference từ cả NHNCK + SCMS).
Khi Human trigger "Consolidate entity X" từ App:
- AI đọc tất cả
lld_*.yamlcódesign_status: approvedvàatomic_entity = X. - Build union attribute list, flag inconsistency:
- Data domain mismatch cùng attribute tên giống nhau
- Attribute name không nhất quán giữa source (VD: "Full Name" vs "Organization Full Name")
- Attribute thiếu ở một số source → đề xuất
nullable: truecho source đó
- Sinh
DataModel/working/Atomic/lld/entities/entity_{PHYSICAL_NAME}.yamldùngtemplates/entity_template.yaml. consolidation_status: pending+consolidation_notes:liệt kê issues.- Human review trong App → resolve issues → set
consolidation_status: approved.
# Generate entity_*.yaml từ lld_*.yaml approved:
python DataModel/working/Atomic/lld/scripts/generate_entity_consolidation.py
# Chỉ 1 entity:
python DataModel/working/Atomic/lld/scripts/generate_entity_consolidation.py --entity "Securities Practitioner"
# Xem diff không ghi file:
python DataModel/working/Atomic/lld/scripts/generate_entity_consolidation.py --dry-run
# Validate entity_*.yaml sau khi AI sinh:
python DataModel/working/Atomic/lld/scripts/validate_lld_yaml.py --entities
Bước 10 — Generate YAML (Phase 4)
Sau khi entity_*.yaml đã approved (hoặc entity single-source chỉ cần lld_*.yaml approved):
python DataModel/generate_dm_yaml.py --source {SOURCE}
Output: DataModel/Atomic/{BCV_Folder}/dm_atm_{table}-{SOURCE}.{SRC_TABLE}.yaml
Sub-folder theo BCV Core Object:
Arrangement, Business_Activity, Common, Communication, Condition, Documentation, Event, Group, Involved_Party, Location, Product, Transaction
Kiểm tra nhanh sau khi generate:
ls DataModel/Atomic/**/*-{SOURCE}.*.yaml | wc -l
grep -rL "layer: Atomic" DataModel/Atomic/ --include="*.yaml" | grep {SOURCE}
Dòng 2 phải trả về rỗng.
Bước 10b — Validate YAML (Phase 4b)
python DataModel/validate_dm_yaml.py --source {SOURCE}
Điều kiện passed: Failed: 0. KHÔNG sang Phase 5 khi còn failed.
Bước 11 — Consolidate (Phase 5)
python DataModel/gen_summary_and_model.py --source {SOURCE}
Output:
DataModel/Atomic/dm_manifest.yamlDataModel/atomic_model.yaml
CHECKLIST HOÀN THÀNH TOÀN BỘ PIPELINE
| Phase | Bước | Điều kiện passed |
|---|---|---|
| 0 — Pre-flight | Bước 0 | approved files không bị ghi đè |
| 1 — LLD Design | Bước 1–6 | Mọi lld_*.yaml trong DataModel/working/Atomic/lld/{SOURCE}/ đã đủ và đúng chuẩn |
| 1b — Validate LLD | DataModel/working/Atomic/lld/scripts/validate_lld_yaml.py --source {SOURCE} |
Failed: 0 |
| 2 — Human Review Level 1 | (trong App) | Mọi lld_*.yaml cần thiết kế đã design_status: approved |
| 3 — Post-check | DataModel/working/Atomic/lld/scripts/post_check_atomic.py + post_check_source_coverage.py --source {SOURCE} |
0 WARNING |
| 3b — Consolidation (nếu cần) | DataModel/working/Atomic/lld/scripts/validate_lld_yaml.py --entities |
Failed: 0, consolidation_status: approved |
| 4 — Generate YAML | generate_dm_yaml.py --source {SOURCE} |
Số file đúng; 0 file thiếu layer: Atomic |
| 4b — Validate YAML | validate_dm_yaml.py --source {SOURCE} |
Failed: 0 |
| 5 — Consolidate | gen_summary_and_model.py --source {SOURCE} |
dm_manifest.yaml đúng N dòng; atomic_model.yaml parse được |
QUY TẮC ĐẶT TÊN ATTRIBUTE
Prefix nhất quán trong nhóm trường
Nhiều trường cùng nhóm thông tin → dùng chung prefix.
- VD:
Reporting Period Type Code,Reporting Period,Reporting Period Start Date,Reporting Period End Date.
Prefix chủ thể
Entity chứa nhóm trường mô tả chủ thể khác (không phải chủ thể chính) → thêm prefix chỉ rõ.
- VD: entity "Related Party" →
Related Individual Full Name,Related Individual Birth Year. - KHÔNG áp dụng cho snapshot từ entity cha đã có FK.
Scope entity
Không giả định scope từ tên bảng. Đọc kỹ mô tả nguồn trước.
- VD:
THONG_TIN_DK_THUE= "thông tin đăng ký thuế" (tổ chức, DN, hộ KD) → không gắn prefix "Organization".
QUY TẮC ĐẶT physical_name
Nguyên tắc ưu tiên (B1 → B2 → B3)
B1 —
system/rules/rule_transform_logical_name.csv(ưu tiên tuyệt đối) Tra từng từ (và cụm từ) trong logical name theo thuật toán longest-match-first.B2 — Bảng tra cứu trong SKILL này (chỉ dùng khi từ KHÔNG có trong CSV) Bao gồm: audit block chuẩn, danh từ agent (-er/-or), past participle đặc biệt.
B3 — Giữ nguyên lowercase nếu không có ở B1/B2 (tuyệt đối không tự suy luận).
Format chung
- snake_case, toàn chữ thường
entity_prefix+_+field_abbreviation- KHÔNG dùng từ đầy đủ khi có từ viết tắt chuẩn
Thuật toán transform (longest-match-first) — áp dụng B1
- Lowercase toàn bộ logical name.
- Duyệt từ trái sang phải; tại mỗi vị trí thử match cụm dài nhất có trong
rule_transform_logical_name.csv(cộtName) tại word boundary. - Nếu match → thay bằng
Abbreviationtương ứng (lowercase). - Nếu không match → giữ nguyên word đó (lowercase,
-→_). - Nối các token bằng
_.
Ví dụ:
Securities Practitioner→scr+prac→scr_pracSource System→src+stm→src_stmDate Of Birth→dob(cụm 3 từ match trực tiếp)Sent Timestamp→snd+tms→snd_tms(Sent→SND trong CSV)
Quy tắc đặt tên:
- Entity physical name:
[domain_prefix]_[bcv_term]— transform trên logical entity name. - Attribute physical name:
[entity_prefix]_[field_tokens]— transform trên logical attribute name, không lặp lại prefix entity nếu tên attribute đã bao gồm.
Quy tắc past participle (-ed) — B2 khi từ KHÔNG có trong CSV
BỎ hậu tố
-ed, dùng viết tắt của ROOT động từ. KHÔNG thêmdsau viết tắt root.
| Từ đầy đủ | Root | Viết tắt (B2) | Ví dụ |
|---|---|---|---|
| signed | sign | sgn |
sgn_by_ofcr_id |
| forwarded | forward | fwrd |
fwrd_tms |
| submitted | submit | subm |
subm_by_ofcr_id |
| confirmed | confirm | cnfrm |
cnfrm_tms |
| announced | announce | ancm |
ancm_dt |
Các past participle đã có trong CSV (dùng B1):
issued→ISSU,assigned→ASGN,received→RCV,transferred→TFRD,prepared→PREP,created→CRT,updated→UDT,numbered→NBR.
Bảng từ viết tắt bổ sung (B2 — từ KHÔNG có trong CSV)
| Từ đầy đủ | Viết tắt | Ví dụ |
|---|---|---|
| Audit block chuẩn | ||
| Created Timestamp | crt_tms |
thay created_ts |
| Updated Timestamp | udt_tms |
thay updated_ts |
| Created By … Id | crt_by_…_id |
crt_by_ofcr_id |
| Created By … Code | crt_by_…_code |
crt_by_ofcr_code |
| Updated By … Id | udt_by_…_id |
udt_by_ofcr_id |
| Updated By … Code | udt_by_…_code |
udt_by_ofcr_code |
| Danh từ agent (-er/-or) và nghiệp vụ đặc thù | ||
| violator | vltr |
vltr_cnfrm_rcpt_tms, vltr_cnfrm_by |
| signer (noun) | sgnr |
sgnr_ofcr_id, sgnr_nm |
| recorder (noun) | rcdr |
rcdr_nm, rcdr_title |
| approver (noun) | aprv |
aprv_ofcr_id, aprv_dcsn_nbr |
| sender (noun) | sndr |
sndr_nm, sndr_adr, sndr_ofcr_id |
| monitoring (noun) | mon |
mon_ofcr_id, mon_ofcr_code |
| forwarding (noun/adj) | fwdng |
fwdng_unit |
| reporter (noun) | rptr |
rptr_nm |
| Từ kỹ thuật không có trong CSV | ||
| life cycle status code | lcs_code |
thay life_cycle_st_code |
| unique key | uk |
peti_uk, vln_case_uk |
| party | p |
rel_p_id, rspl_p |
| member | mbr |
mbr_ofcr_id, mbr_full_nm |
| enforcement | nfrc |
nfrc_st, nfrc_tp_code |
| attached / attach | attch |
attch_file, peti_attch_ind |
| guidance | gdnc |
gdnc_doc_nbr, gdnc_doc_dt |
| archived | archv |
archv_nbr, archv_ind |
| Prefix nhóm nghiệp vụ | ||
| Complaint … | cpln_ |
cpln_exists_ind, cpln_cntnt, cpln_rcv_dt, cpln_st_code, cpln_rslt |
| violation | vln |
vln_case_id, vln_bhvr_id, vln_rcrd_id |
| behavior | bhvr |
vln_bhvr_id, vln_bhvr_code |
| record (entity) | rcrd |
vln_rcrd_id, rcrd_tp_code |
| conclusion | cncl |
cncl_nbr, insp_cncl_id |
| circumstance | crcm |
crcm_tp_code |
| execution | exec |
exec_st_code, exec_dsc |
| implementation | impl |
impl_note |
| payment | pymt |
pymt_rcv_dt, pymt_proof_upload_tms |
| supervising leader | sprvsg_ldr |
sprvsg_ldr_id |
| announcement | ancm |
ancm_dt, ancm_ttl |
| remedial (adj/noun) | rmdl |
rmdl_msr, rmdl_ddln_dt |
| abnormal | abnrm |
abnrm_txn_chk_ind |
| coerced | crc |
crc_amt |
| lawsuit | lwst |
lwst_exists_ind, lwst_cntnt |
| reception | rcptn |
rcptn_dt, ctzn_rcptn_id |
| verification | verf |
verf_mins_sign_dt |
| minutes (biên bản) | mins |
verf_mins_sign_dt |