Bỏ qua

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