Bỏ qua

Thuộc Thiết Kế CSDL — Nhóm Ma Trận Hiện Trạng

Chi Tiết Entity — Ma Trận Hiện Trạng (Source Mapping)

Bảng: source_mapping, source_mapping_approval, ownership_plan


source_mapping

Mỗi record đại diện cho một ô trong ma trận Source Mapping (Data Element x Đơn vị).

CREATE TABLE source_mapping (
    id                      BIGSERIAL PRIMARY KEY,
    public_id               UUID NOT NULL DEFAULT uuidv7(), -- ID public cho API/external integration
    data_element_id         BIGINT NOT NULL REFERENCES data_element(id),
    organization_unit_id    BIGINT NOT NULL REFERENCES organization_unit(id),
    current_state           TEXT NOT NULL DEFAULT 'EMPTY'
                                CHECK (current_state IN (
                                    'DATABASE', 'DATABASE_OVERLAP', 'FRAGMENTED',
                                    'READY', 'EMPTY', 'DISPUTED', 'CONFIRMED', 'REJECTED',
                                    'AI_SUGGESTED', 'AI_HIGH_CONFIDENCE'
                                )),

    -- AI Matching fields
    confidence_score        NUMERIC(4,3),                         -- 0.000–1.000
    algo_breakdown          JSONB,                                -- Chi tiết scoring

    -- DISPUTED fields
    dispute_note            TEXT,                    -- Lý do tranh chấp (≥ 20 ký tự)
    disputed_by             BIGINT REFERENCES app_user(id),
    disputed_at             TIMESTAMPTZ,
    resolved_by             BIGINT REFERENCES app_user(id),
    resolved_at             TIMESTAMPTZ,
    resolve_note            TEXT,                    -- Lý do giải quyết

    -- Confirmation fields
    confirmed_by            BIGINT REFERENCES app_user(id),
    confirmed_at            TIMESTAMPTZ,

    -- Discovery reference
    discovery_session_id    BIGINT REFERENCES discovery_session(id),

    created_at              TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at              TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    UNIQUE (data_element_id, organization_unit_id),  -- Mỗi ô duy nhất
    CONSTRAINT chk_sm_dispute_note_required CHECK (
        current_state != 'DISPUTED'
        OR (dispute_note IS NOT NULL AND length(btrim(dispute_note)) >= 20)
    )
);

-- Core indexes
CREATE UNIQUE INDEX idx_sm_public_id ON source_mapping (public_id);
CREATE INDEX idx_sm_de_org ON source_mapping (data_element_id, organization_unit_id);
CREATE INDEX idx_sm_org_state ON source_mapping (organization_unit_id, current_state);
CREATE INDEX idx_sm_state ON source_mapping (current_state);
CREATE INDEX idx_sm_session ON source_mapping (discovery_session_id);

-- Partial indexes cho query thường gặp
CREATE INDEX idx_sm_disputed ON source_mapping (current_state) WHERE current_state = 'DISPUTED';
CREATE INDEX idx_sm_confirmed ON source_mapping (current_state) WHERE current_state = 'CONFIRMED';

-- Indexes tối ưu cho AI Matching Worker (TS-P0-06b)
CREATE INDEX idx_sm_confidence ON source_mapping (confidence_score DESC NULLS LAST) WHERE current_state IN ('AI_SUGGESTED', 'AI_HIGH_CONFIDENCE');

Trạng thái ô ma trận (Source Mapping State):

Trạng thái Mô tả Ai set
EMPTY Sở không có DE này Mặc định / Discovery
DATABASE Có trong CSDL Discovery tự động / khai báo
DATABASE_OVERLAP Cùng DE lưu ở nhiều bảng trong cùng đơn vị Discovery tự động
FRAGMENTED Dữ liệu rải rác, chưa cấu trúc Sở khai báo
READY Có CSDL + API, sẵn sàng kết nối Sở khai báo
AI_SUGGESTED AI gợi ý (score ≥ 0.60), chờ review Matching Worker
AI_HIGH_CONFIDENCE AI gợi ý với confidence cao (score ≥ 0.90) Matching Worker
DISPUTED Sở không đồng ý Data Owner / Manager
CONFIRMED Đã xác nhận đúng Data Owner / Approver
REJECTED Bác bỏ ánh xạ Approver

Business Rules: - Unique constraint (data_element_id, organization_unit_id) — mỗi ô duy nhất - DISPUTED bắt buộc dispute_note ≥ 20 ký tự - Data Owner chỉ dispute/confirm ô thuộc organization_unit_id của mình (PBAC) - Guard cứng: Không phê duyệt ma trận khi COUNT(*) WHERE current_state = 'DISPUTED' > 0 - Data Mapping Flow: - Hệ thống tự động thiết lập (Pre-populate) toàn bộ matrix (data_element_id, organization_unit_id) thành trạng thái EMPTY. - Khi Discovery AI chạy ra Matching Result có score >= 0.60, AI Worker sẽ cập nhật dòng record tương ứng trong source_mapping từ EMPTY thành AI_SUGGESTED (hoặc AI_HIGH_CONFIDENCE nếu >= 0.90), gán kèm discovery_session_idconfidence_score.


source_mapping_approval

Ghi nhận việc phê duyệt ma trận hiện trạng (Source Mapping) tổng thể bởi Approver.

CREATE TABLE source_mapping_approval (
    id                          BIGSERIAL PRIMARY KEY,
    public_id                   UUID NOT NULL DEFAULT uuidv7(),
    approval_version            INTEGER NOT NULL DEFAULT 1,
    status                      TEXT NOT NULL
                                     CHECK (status IN ('APPROVED', 'REVOKED')),
    confirmed_orgs_count        INTEGER NOT NULL,
    total_orgs_count            INTEGER NOT NULL,
    confirmed_orgs_percent      NUMERIC(5,2) NOT NULL,
    disputed_count              INTEGER NOT NULL DEFAULT 0,
    total_cells                 INTEGER NOT NULL DEFAULT 0,
    confirmed_cells             INTEGER NOT NULL DEFAULT 0,
    approval_note               TEXT,
    approved_by                 BIGINT NOT NULL REFERENCES app_user(id),
    approved_at                 TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    revoked_by                  BIGINT REFERENCES app_user(id),
    revoked_at                  TIMESTAMPTZ,
    revoke_reason               TEXT,
    created_at                  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at                  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT chk_sma_percent_nonneg CHECK (confirmed_orgs_percent >= 0),
    CONSTRAINT chk_sma_percent_max100 CHECK (confirmed_orgs_percent <= 100),
    CONSTRAINT chk_sma_revoke_require_reason CHECK (
        status <> 'REVOKED' OR (revoked_by IS NOT NULL AND revoke_reason IS NOT NULL)
    )
);

CREATE UNIQUE INDEX idx_sma_public_id ON source_mapping_approval (public_id);
CREATE INDEX idx_sma_status ON source_mapping_approval (status);
CREATE INDEX idx_sma_approved_at ON source_mapping_approval (approved_at DESC);
CREATE UNIQUE INDEX idx_sma_singleton_active_approval
    ON source_mapping_approval (('constant')) WHERE status = 'APPROVED';

Business Rules: - Tính Duy Nhất: Tại một thời điểm chỉ có duy nhất một bản phê duyệt có trạng thái APPROVED (được đảm bảo bằng singleton partial index). - Guard phê duyệt: Chỉ APPROVED khi confirmed_orgs_percent > 70disputed_count = 0. - Thu hồi (Revoke): Một bản phê duyệt có thể bị thu hồi. Khi đó, approval_version tiếp theo sẽ được tăng lên để theo dõi lịch sử.


ownership_plan

Bảng D — Gán chủ quản duy nhất cho mỗi Data Element đến cấp Phòng/Ban.

CREATE TABLE ownership_plan (
    id                      BIGSERIAL PRIMARY KEY,
    public_id               UUID NOT NULL DEFAULT uuidv7(), -- ID public cho API/external integration
    data_element_id         BIGINT NOT NULL REFERENCES data_element(id),
    owner_unit_id           BIGINT REFERENCES organization_unit(id),  -- Chủ quản cấp Phòng (nullable = "Dữ liệu cần xây dựng mới")
    status                  TEXT NOT NULL DEFAULT 'PROPOSED'
                                CHECK (status IN ('PROPOSED', 'APPROVED', 'PUBLISHED')),
    proposed_by             BIGINT REFERENCES app_user(id),          -- Manager đề xuất
    approved_by             BIGINT REFERENCES app_user(id),          -- Approver chốt
    override_reason         TEXT,                                     -- Lý do nếu Approver override đề xuất
    approved_at             TIMESTAMPTZ,
    published_at            TIMESTAMPTZ,
    created_at              TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at              TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    UNIQUE (data_element_id)  -- Mỗi DE chỉ có 1 ownership plan (quy tắc 1:1)
);

CREATE UNIQUE INDEX idx_op_public_id ON ownership_plan (public_id);
CREATE INDEX idx_op_status ON ownership_plan (status);
CREATE INDEX idx_op_owner ON ownership_plan (owner_unit_id);
CREATE INDEX idx_op_de ON ownership_plan (data_element_id);

Business Rules: - Quy tắc 1:1: UNIQUE constraint trên data_element_id - owner_unit_id phải tham chiếu đơn vị cấp PHONG - owner_unit_id = NULL → ghi nhận "Dữ liệu cần xây dựng mới" - Khi APPROVED → cập nhật data_element.owner_unit_id - Khi PUBLISHED → cập nhật data_element.status = 'PUBLISHED'


Cập nhật lần cuối: 2026-04-19