ADR-0002. MetaLink liên kết asset qua (principalType, principalId) đa hình
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-03-15 |
| Deciders | platform |
| Supersedes | — |
Bối cảnh
- Nhiều loại entity cần media đính kèm —
Product,ProductVariant,Organizer,Category,Ledger(và quan hệMerchant/User). - Asset là thư viện mount vào nhiều host; nó không thể sở hữu khóa ngoại vào bảng của mọi consumer mà không đảo ngược chiều dependency.
MetaLinknằm trong@nx/corechính là để commerce/ledger có thể tham chiếu mà không gây dep vòng — một FK cứng trỏ về các bảng đó sẽ tái tạo lại vòng đó.
Quyết định
Chúng tôi sẽ lưu owner dưới dạng cặp đa hình mềm: principalType (text, validate theo MetaLinkPrincipalTypes) + principalId (text), không có khóa ngoại DB. Drizzle relations() khai báo các join một-một theo từng type, resolve trên principalId.
Hệ quả
| Ưu | Nhược |
|---|---|
Một bảng MetaLink phục vụ mọi loại entity | Không có toàn vẹn tham chiếu — có thể mồ côi |
| Không có dependency vòng giữa core và consumer | Loại principal mới cần sửa MetaLinkPrincipalTypes + relations() |
Index composite (principalType, principalId) giữ lookup nhanh | Tính hợp lệ của type được thực thi trong code, không phải DB |
Các phương án đã cân nhắc
| Phương án | Ưu | Nhược | Lý do loại bỏ |
|---|---|---|---|
Cột FK theo từng entity (productId, ledgerId, …) | Toàn vẹn tham chiếu thật | Phình schema; dep vòng; sửa mỗi lần | Phá vỡ mục tiêu bảng dùng chung |
| Bảng join theo từng entity | Cardinality sạch | N bảng phải duy trì; nhiều join hơn | Quá phức tạp cho media 1:N |
Owner ref dạng metadata jsonb | Không đổi schema | Không index, không truy vấn được ở quy mô lớn | Cần index composite cho lookup |
Tham chiếu
packages/core/src/models/schemas/public/meta-link/schema.ts(principalType,principalId, index)packages/core/src/models/schemas/public/meta-link/model.ts(relations()đa hình)packages/core/src/models/schemas/public/meta-link/constants.ts(MetaLinkPrincipalTypes)