Thuộc Thiết Kế CSDL — Nhóm Hệ thống
Chi Tiết Entity — Hệ Thống¶
Bảng:
audit_log,ai_feedback_log,system_config
audit_log¶
Nhật ký kiểm toán — append-only, ghi lại mọi thay đổi dữ liệu trong hệ thống.
CREATE TABLE audit_log (
id UUID DEFAULT uuidv7(),
public_id UUID NOT NULL DEFAULT uuidv7(), -- ID public cho API/external integration
action TEXT NOT NULL, -- VD: CREATE_DATA_ELEMENT, CONFIRM_MAPPING
entity_type TEXT NOT NULL, -- VD: DATA_ELEMENT, SOURCE_MAPPING
entity_id VARCHAR(50) NOT NULL, -- ID entity thay đổi (hỗ trợ cả BIGINT và UUID)
user_id BIGINT NOT NULL, -- User thực hiện
org_id BIGINT, -- Đơn vị của user
trace_id TEXT, -- UUID Trace ID từ Jaeger/OpenTelemetry
before_data JSONB, -- Snapshot trước thay đổi (null khi CREATE)
after_data JSONB, -- Snapshot sau thay đổi (null khi DELETE)
metadata JSONB, -- Metadata Request Context (IP, Device, User-Agent, JWT Claims...)
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (created_at);
-- Cấu hình sẵn Partition để hệ thống có thể INSERT ngay sau khi Migrate
CREATE TABLE audit_log_y2024 PARTITION OF audit_log FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
CREATE TABLE audit_log_y2025 PARTITION OF audit_log FOR VALUES FROM ('2025-01-01') TO ('2026-01-01');
CREATE TABLE audit_log_y2026 PARTITION OF audit_log FOR VALUES FROM ('2026-01-01') TO ('2027-01-01');
CREATE TABLE audit_log_y2027 PARTITION OF audit_log FOR VALUES FROM ('2027-01-01') TO ('2028-01-01');
-- REVOKE UPDATE và DELETE để đảm bảo append-only
-- Chạy trong migration riêng: V010__audit_log_permissions.sql
-- REVOKE UPDATE, DELETE ON audit_log FROM app_user;
CREATE INDEX idx_al_entity ON audit_log (entity_type, entity_id);
CREATE INDEX idx_al_user ON audit_log (user_id, created_at DESC);
CREATE INDEX idx_al_action ON audit_log (action);
CREATE INDEX idx_al_date ON audit_log (created_at DESC);
CREATE INDEX idx_al_trace ON audit_log (trace_id);
CREATE UNIQUE INDEX idx_al_public_id_created ON audit_log (public_id, created_at);
Danh sách Action chính:
| Action | Entity Type | Mô tả |
|---|---|---|
CREATE_DOMAIN |
DOMAIN | Tạo Domain mới |
UPDATE_DOMAIN |
DOMAIN | Cập nhật Domain |
DELETE_DOMAIN |
DOMAIN | Xóa Domain |
CREATE_DATA_ELEMENT |
DATA_ELEMENT | Tạo Data Element |
UPDATE_DATA_ELEMENT |
DATA_ELEMENT | Cập nhật Data Element |
CHANGE_DE_STATUS |
DATA_ELEMENT | Chuyển trạng thái DE (DRAFT→IN_REVIEW→APPROVED→PUBLISHED) |
ASSIGN_OWNERSHIP |
DATA_ELEMENT | Gán chủ quản cho DE |
CREATE_USER |
APP_USER | Tạo user mới |
UPDATE_USER_ROLES |
APP_USER | Thay đổi vai trò user |
DEACTIVATE_USER |
APP_USER | Tạm dừng tài khoản |
UPLOAD_DISCOVERY |
DISCOVERY_SESSION | Upload file Discovery |
RUN_MATCHING |
DISCOVERY_SESSION | Kích hoạt AI matching |
CONFIRM_MAPPING |
SOURCE_MAPPING | Xác nhận match |
REJECT_MAPPING |
SOURCE_MAPPING | Từ chối match |
OVERRIDE_MAPPING |
SOURCE_MAPPING | Override match |
MARK_DISPUTED |
SOURCE_MAPPING | Đánh dấu DISPUTED |
RESOLVE_DISPUTED |
SOURCE_MAPPING | Giải quyết DISPUTED |
CONFIRM_BATCH |
SOURCE_MAPPING | Data Owner xác nhận batch |
APPROVE_BANG_C |
BANG_C_APPROVAL | Phê duyệt Bảng C |
FINALIZE_OWNERSHIP |
OWNERSHIP_PLAN | Chốt chủ quản Bảng D |
PUBLISH_DICTIONARY |
OWNERSHIP_PLAN | Ban hành Từ điển |
PROPOSE_EXTENSION |
EXTENSION_PROPOSAL | Đề xuất mở rộng |
APPROVE_EXTENSION |
EXTENSION_PROPOSAL | Phê duyệt đề xuất |
REJECT_EXTENSION |
EXTENSION_PROPOSAL | Từ chối đề xuất |
Business Rules:
- Ghi trong cùng @Transactional với business operation — đảm bảo consistency
- before_data / after_data là JSONB snapshot — lưu diff
- REVOKE UPDATE, DELETE ở DB level → không ai sửa/xóa được
- Retention: 5 năm (tuân thủ Luật DL 60/2024)
- Partitioning: Script Liquibase/Application tự động tạo partition mới vào tháng 12 hàng năm cho năm tiếp theo. Dọn dẹp archive bằng DROP PARTITION thay cho DELETE.
ai_feedback_log¶
Ghi nhận mọi quyết định của người dùng đối với gợi ý AI — training data cho ML GĐ2.
CREATE TABLE ai_feedback_log (
id BIGSERIAL,
public_id UUID NOT NULL DEFAULT uuidv7(), -- ID public cho API/external integration
suggestion_type TEXT NOT NULL
CHECK (suggestion_type IN ('MATCHING', 'SIMILARITY')),
user_action TEXT NOT NULL
CHECK (user_action IN ('ACCEPT', 'REJECT', 'MODIFY')),
data_element_id BIGINT REFERENCES data_element(id),
matching_result_id BIGINT REFERENCES matching_result(id),
extracted_field_id BIGINT REFERENCES extracted_field(id),
original_suggestion JSONB NOT NULL, -- Gợi ý gốc từ AI
modified_data JSONB, -- Dữ liệu đã chỉnh sửa (nếu MODIFY)
confidence_score NUMERIC(4,3), -- Score của gợi ý gốc
user_id BIGINT NOT NULL REFERENCES app_user(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (created_at);
-- Cấu hình sẵn Partition để rẽ nhánh dữ liệu theo năm
CREATE TABLE ai_feedback_log_y2024 PARTITION OF ai_feedback_log FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
CREATE TABLE ai_feedback_log_y2025 PARTITION OF ai_feedback_log FOR VALUES FROM ('2025-01-01') TO ('2026-01-01');
CREATE TABLE ai_feedback_log_y2026 PARTITION OF ai_feedback_log FOR VALUES FROM ('2026-01-01') TO ('2027-01-01');
CREATE TABLE ai_feedback_log_y2027 PARTITION OF ai_feedback_log FOR VALUES FROM ('2027-01-01') TO ('2028-01-01');
CREATE INDEX idx_afl_de ON ai_feedback_log (data_element_id);
CREATE INDEX idx_afl_type_action ON ai_feedback_log (suggestion_type, user_action);
CREATE INDEX idx_afl_date ON ai_feedback_log (created_at DESC);
CREATE INDEX idx_afl_user ON ai_feedback_log (user_id);
CREATE UNIQUE INDEX idx_afl_public_id_created ON ai_feedback_log (public_id, created_at);
Cấu trúc original_suggestion JSONB:
{
"field_name": "cccd_so",
"suggested_de_id": 101,
"suggested_de_name": "Số CCCD",
"confidence_score": 0.94,
"algo_breakdown": {
"score_synonym": 1.0,
"score_trigram": 0.87,
"score_levenshtein": 0.80
}
}
Business Rules:
- Mọi quyết định ACCEPT/REJECT/MODIFY được ghi đầy đủ
- original_suggestion lưu nguyên gợi ý gốc — không bị thay đổi
- FK đầy đủ để Python Agent join khi retrain ML ở GĐ2
- Retention: 3 năm
system_config¶
Cấu hình hệ thống — business rules có thể thay đổi không cần deploy lại.
CREATE TABLE system_config (
id BIGSERIAL PRIMARY KEY,
public_id UUID NOT NULL DEFAULT uuidv7(), -- ID public cho API/external integration
config_key TEXT UNIQUE NOT NULL, -- VD: matching.threshold, disputed.min_chars
config_value TEXT NOT NULL, -- Giá trị
data_type TEXT NOT NULL DEFAULT 'STRING'
CHECK (data_type IN ('STRING', 'INTEGER', 'FLOAT', 'BOOLEAN', 'JSON')),
description TEXT, -- Mô tả cấu hình
updated_by BIGINT REFERENCES app_user(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE UNIQUE INDEX idx_sc_public_id ON system_config (public_id);
Cấu hình mặc định (seed data):
| config_key | config_value | data_type | Mô tả |
|---|---|---|---|
matching.threshold.suggested |
0.60 |
FLOAT | Ngưỡng tối thiểu để AI gợi ý |
matching.threshold.high_confidence |
0.90 |
FLOAT | Ngưỡng high confidence |
disputed.min_note_chars |
20 |
INTEGER | Số ký tự tối thiểu ghi chú DISPUTED |
source_mapping_approval.min_confirmed_percent |
70 |
INTEGER | % đơn vị tối thiểu xác nhận để phê duyệt |
discovery.max_file_size_mb |
50 |
INTEGER | Kích thước file upload tối đa (MB) |
discovery.supported_methods |
CSV,SQL_DDL,MANUAL |
STRING | Phương thức Discovery GĐ1 |
scoring.weight.synonym |
0.5 |
FLOAT | Trọng số synonym trong scoring |
scoring.weight.trigram |
0.3 |
FLOAT | Trọng số trigram |
scoring.weight.levenshtein |
0.2 |
FLOAT | Trọng số levenshtein |
scoring.penalty.data_type_mismatch |
0.5 |
FLOAT | Penalty khi kiểu dữ liệu không khớp |
Cập nhật lần cuối: 2026-04-08 26-04-08