🗃️ Reporting Service - Data Model¶
1. Giới thiệu¶
Tài liệu này mô tả chi tiết mô hình dữ liệu của Reporting Service. Service này là một thành phần cốt lõi trong hệ thống dx-vas, hoạt động theo kiến trúc multi-tenant, phục vụ nhu cầu báo cáo và phân tích hệ thống của cả cấp Superadmin lẫn từng tenant riêng biệt.
Reporting Service chịu trách nhiệm quản lý các loại dữ liệu chính sau:
- Các cấu hình mẫu báo cáo (report_templates)
- Lịch sử truy vấn và kết quả báo cáo (report_query_logs)
- Cấu hình báo cáo đã lưu của người dùng (saved_report_configs)
- Cấu hình hiển thị dashboard (saved_dashboard_layouts)
Mô hình dữ liệu này là cơ sở cho việc phát triển backend, định nghĩa API, thực hiện schema migration, đảm bảo tính nhất quán dữ liệu, và đồng thời phục vụ cho việc truy vấn tới hệ thống Data Warehouse như BigQuery.
2. Phạm vi Dữ liệu Quản lý (Scope)¶
Reporting Service bao gồm việc quản lý:
- Danh sách các mẫu báo cáo được định nghĩa sẵn (report_templates)
- Các truy vấn được thực thi dựa trên các template (report_query_logs)
- Cấu hình báo cáo được người dùng lưu lại (saved_report_configs)
- Cấu hình dashboard của người dùng (saved_dashboard_layouts)
3. Ngoài Phạm Vi (Out of Scope)¶
Reporting Service không chịu trách nhiệm quản lý: - ❌ Dữ liệu thô (raw data) từ các hệ thống nguồn – đã được ETL đưa vào Data Warehouse. - ❌ Truy cập trực tiếp vào các table nghiệp vụ cụ thể của CRM/SIS/LMS – được truy vấn gián tiếp qua BigQuery. - ❌ Quản lý quyền truy cập người dùng – thực hiện thông qua API Gateway và RBAC Service.
4. Mục tiêu của Tài liệu Mô hình Dữ liệu¶
- Trình bày cấu trúc các bảng dữ liệu cốt lõi của Reporting Service.
- Mô tả các ràng buộc dữ liệu (constraints), khóa chính/ngoại, chỉ mục (indexes).
- Hỗ trợ cho quá trình phát triển backend, viết đặc tả OpenAPI, thực hiện schema migration, kiểm thử và bảo trì service.
- Làm nền tảng để đảm bảo tính nhất quán schema với các tài liệu liên quan như
design.md,interface-contract.md,openapi.yaml, và các ADRs như [ADR-028 Reporting Architecture], [ADR-029 Report Template Schema], và [ADR-030 Event Schema Governance].
5. Sơ đồ ERD (Entity Relationship Diagram)¶
Sơ đồ sơ bộ
erDiagram
report_templates ||--o{ report_query_logs : generates
report_templates ||--o{ saved_report_configs : based_on
saved_report_configs ||--o{ saved_dashboard_layouts : uses
report_templates {
string id PK
string name
string description
jsonb input_parameters
string data_view
string query_template
jsonb required_permission
string version
boolean is_active
timestamp created_at
timestamp updated_at
}
report_query_logs {
string id PK
string template_id FK
string user_id
string tenant_id
jsonb input_used
timestamp executed_at
float query_duration_ms
string status
jsonb metadata
}
saved_report_configs {
string id PK
string user_id
string tenant_id
string template_id FK
string name
jsonb input_parameters
timestamp created_at
timestamp updated_at
}
saved_dashboard_layouts {
string id PK
string config_id FK
string user_id
string layout_type
jsonb widget_arrangement
timestamp created_at
timestamp updated_at
}
📝 Ghi chú:
report_templates: Định nghĩa mẫu báo cáo, do Superadmin tạo hoặc hệ thống cài sẵn.report_query_logs: Ghi nhận các lần người dùng truy vấn theo mẫu.saved_report_configs: Cho phép người dùng lưu cấu hình để tái sử dụng.saved_dashboard_layouts: Cho phép người dùng tự cấu hình dashboard từ nhiều config.
Sơ đồ chi tiết
erDiagram
report_templates {
string template_id PK
string name
string description
string data_view
boolean is_active
string created_by
timestamp created_at
}
report_template_versions {
string version PK
string template_id FK
string query_template
jsonb input_parameters_schema
timestamp created_at
string created_by
}
report_template_permissions {
string template_id FK
string permission_code
}
report_query_logs {
string log_id PK
string user_id
string tenant_id
string template_id FK
jsonb input_used
string status
int query_duration_ms
timestamp executed_at
}
saved_report_configs {
string config_id PK
string user_id
string tenant_id
string template_id FK
jsonb input_parameters
string name
timestamp created_at
}
saved_dashboard_layouts {
string layout_id PK
string user_id
string config_id FK
jsonb layout
string layout_type
timestamp updated_at
}
report_templates ||--o{ report_template_versions : has
report_templates ||--o{ report_template_permissions : has
report_templates ||--o{ report_query_logs : used_in
report_templates ||--o{ saved_report_configs : config_of
saved_report_configs ||--o{ saved_dashboard_layouts : contains
6. Mô tả chi tiết từng bảng¶
6.1. report_templates¶
CREATE TABLE report_templates (
template_id VARCHAR PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
data_view TEXT NOT NULL,
is_active BOOLEAN DEFAULT true,
created_by TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
id |
string |
✅ | Mã định danh duy nhất của template |
name |
string |
✅ | Tên hiển thị của template |
description |
string |
⛔ | Mô tả ngắn về báo cáo |
input_parameters |
jsonb |
✅ | Danh sách các tham số người dùng cần nhập |
data_view |
string |
✅ | View/table trong Data Warehouse mà query_template sử dụng |
query_template |
string |
✅ | Câu truy vấn động với placeholder |
required_permission |
jsonb |
✅ | Danh sách quyền cần có để truy cập |
version |
string |
✅ | Phiên bản của template, ví dụ: "v1", "v2" |
is_active |
boolean |
✅ | Đánh dấu template đã bị vô hiệu hóa chưa |
created_at |
timestamp |
✅ | Ngày tạo |
updated_at |
timestamp |
✅ | Ngày cập nhật cuối cùng |
6.2. report_query_logs¶
CREATE TABLE report_query_logs (
log_id UUID PRIMARY KEY,
user_id TEXT NOT NULL,
tenant_id TEXT NOT NULL,
template_id VARCHAR,
input_used JSONB,
status TEXT CHECK (status IN ('success', 'error', 'timeout', 'unauthorized', 'validation_failed')),
query_duration_ms INT,
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (template_id) REFERENCES report_templates(template_id) ON DELETE SET NULL
);
📝 Giải thích: Chúng ta dùng ON DELETE SET NULL cho logs để vẫn giữ log truy vấn dù template bị xóa.
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
id |
string |
✅ | ID của log |
template_id |
string |
✅ | Template mà truy vấn dựa trên |
user_id |
string |
✅ | ID người dùng thực hiện truy vấn |
tenant_id |
string |
✅ | ID tenant |
input_used |
jsonb |
✅ | Tham số truy vấn sử dụng |
executed_at |
timestamp |
✅ | Thời điểm thực hiện truy vấn |
query_duration_ms |
float |
✅ | Thời gian thực thi |
status |
string |
✅ | success, error, timeout |
metadata |
jsonb |
⛔ | Thông tin thêm: source IP, user-agent, etc. |
6.3. saved_report_configs¶
CREATE TABLE saved_report_configs (
config_id UUID PRIMARY KEY,
user_id TEXT NOT NULL,
tenant_id TEXT NOT NULL,
template_id VARCHAR NOT NULL,
input_parameters JSONB NOT NULL,
name TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (template_id) REFERENCES report_templates(template_id) ON DELETE CASCADE
);
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
id |
string |
✅ | ID cấu hình |
user_id |
string |
✅ | Người tạo |
tenant_id |
string |
✅ | Tenant tương ứng |
template_id |
string |
✅ | Template được sử dụng |
name |
string |
✅ | Tên cấu hình người dùng tự đặt |
input_parameters |
jsonb |
✅ | Tham số điền sẵn |
created_at |
timestamp |
✅ | Ngày tạo |
updated_at |
timestamp |
✅ | Ngày cập nhật gần nhất |
6.4. saved_dashboard_layouts¶
CREATE TABLE saved_dashboard_layouts (
layout_id UUID PRIMARY KEY,
user_id TEXT NOT NULL,
config_id UUID NOT NULL,
layout JSONB NOT NULL,
layout_type TEXT CHECK (layout_type IN ('chart', 'table', 'dashboard_grid')),
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (config_id) REFERENCES saved_report_configs(config_id) ON DELETE CASCADE
);
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
id |
string |
✅ | ID layout |
config_id |
string |
✅ | Liên kết tới saved_report_configs |
user_id |
string |
✅ | Người sở hữu |
layout_type |
string |
✅ | grid, tabbed, etc. |
widget_arrangement |
jsonb |
✅ | JSON định nghĩa layout UI |
created_at |
timestamp |
✅ | Thời điểm tạo |
updated_at |
timestamp |
✅ | Lần cập nhật cuối |
7. Các bảng phụ trợ¶
7.1. report_template_versions¶
CREATE TABLE report_template_versions (
version TEXT NOT NULL,
template_id VARCHAR NOT NULL,
query_template TEXT NOT NULL,
input_parameters_schema JSONB NOT NULL,
created_by TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (template_id, version),
FOREIGN KEY (template_id) REFERENCES report_templates(template_id) ON DELETE CASCADE
);
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
id |
string |
✅ | ID bản ghi |
template_id |
string |
✅ | Liên kết tới template chính |
version |
string |
✅ | Số phiên bản (ví dụ: "v1", "v2") |
query_template |
string |
✅ | Nội dung query tương ứng với phiên bản này |
input_parameters |
jsonb |
✅ | Định nghĩa tham số tương ứng |
created_at |
timestamp |
✅ | Thời điểm tạo bản này |
created_by |
string |
✅ | Người tạo phiên bản này |
🎯 Dùng để lưu trữ các phiên bản cũ của report template, giúp rollback dễ dàng hoặc theo dõi lịch sử.
7.2. report_template_permissions¶
CREATE TABLE report_template_permissions (
template_id VARCHAR NOT NULL,
permission_code TEXT NOT NULL,
PRIMARY KEY (template_id, permission_code),
FOREIGN KEY (template_id) REFERENCES report_templates(template_id) ON DELETE CASCADE
);
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
template_id |
string |
✅ | ID template |
permission_code |
string |
✅ | Mã quyền yêu cầu (ví dụ: report.view_finance) |
is_required |
bool |
✅ | true = bắt buộc, false = tùy chọn |
created_at |
timestamp |
✅ | Ngày thêm quyền này vào template |
🎯 Cho phép tách riêng quyền kiểm soát truy cập với từng template thay vì nhét toàn bộ trong 1 cột JSON.
7.3. report_query_status_logs¶
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
id |
string |
✅ | ID log |
query_id |
string |
✅ | ID từ bảng report_query_logs |
status |
string |
✅ | started, running, success, error, timeout |
timestamp |
timestamp |
✅ | Thời điểm log |
message |
string |
⛔ | Mô tả chi tiết hoặc lỗi |
🎯 Ghi nhận chi tiết lifecycle của truy vấn để phục vụ debug và audit.
8. Indexes & Constraints¶
Dưới đây là các chỉ mục và ràng buộc quan trọng nhằm đảm bảo hiệu năng truy vấn và tính toàn vẹn dữ liệu trong hệ thống.
8.1. report_templates¶
Indexes:
- idx_report_templates_active: (is_active)
- idx_report_templates_name: (name)
- idx_report_templates_data_view: (data_view)
Constraints:
- UNIQUE(template_id, version)
- CHECK (version ~ '^v[0-9]+$') – đảm bảo version hợp lệ
8.2. report_query_logs¶
Indexes:
- idx_query_logs_user: (user_id)
- idx_query_logs_template: (template_id)
- idx_query_logs_tenant_time: (tenant_id, executed_at DESC)
Constraints:
- CHECK (query_duration_ms >= 0)
- CHECK (status IN ('success', 'error', 'timeout'))
8.3. saved_report_configs¶
Indexes:
- idx_saved_config_user: (user_id)
- idx_saved_config_tenant: (tenant_id)
- idx_saved_config_template: (template_id)
Constraints:
- UNIQUE(user_id, name) – mỗi người dùng không được đặt tên trùng nhau cho cấu hình đã lưu
- CHECK (input_parameters IS NOT NULL)
8.4. saved_dashboard_layouts¶
Indexes:
- idx_dashboard_layout_user: (user_id)
- idx_dashboard_layout_config: (config_id)
Constraints:
- CHECK (layout_type IN ('grid', 'tabbed', 'freeform'))
8.5. report_template_versions¶
Indexes:
- idx_versions_template: (template_id)
- idx_versions_created_by: (created_by)
Constraints:
- UNIQUE(template_id, version)
- CHECK (version ~ '^v[0-9]+$')
8.6. report_template_permissions¶
Indexes:
- idx_permissions_template: (template_id)
- idx_permissions_code: (permission_code)
Constraints:
- UNIQUE(template_id, permission_code)
9. Chính sách Lưu trữ & Xóa dữ liệu (Retention)¶
Hệ thống Reporting Service cần áp dụng các chính sách lưu trữ phù hợp để cân bằng giữa truy xuất hiệu quả, chi phí lưu trữ và yêu cầu tuân thủ pháp lý.
9.1. report_query_logs¶
- Thời gian giữ: 12 tháng
- Cơ chế xóa: Tự động thông qua batch job định kỳ (ví dụ: Cloud Scheduler + Cloud Function)
- Lý do: Log này phục vụ thống kê hiệu năng và truy vết người dùng. Sau 12 tháng, dữ liệu cũ ít giá trị sử dụng.
9.2. report_template_versions¶
- Thời gian giữ: Vĩnh viễn (hoặc cho đến khi template chính bị xóa)
- Cơ chế xóa: Chỉ xóa khi Superadmin hoặc hệ thống quyết định xóa template chính
- Lý do: Cần lưu lịch sử để rollback hoặc kiểm tra thay đổi.
9.3. saved_report_configs & saved_dashboard_layouts¶
- Thời gian giữ: Vĩnh viễn (miễn là user còn hoạt động)
- Cơ chế xóa: Theo yêu cầu người dùng hoặc khi user bị xóa khỏi hệ thống
- Lý do: Đây là dữ liệu do người dùng lưu thủ công, nên cần tôn trọng quyền sở hữu.
9.4. report_template_permissions¶
- Thời gian giữ: Vĩnh viễn
- Lý do: Là một phần cấu trúc quyền của template, luôn cần cho xác thực truy cập.
9.5. Tuân thủ ADR-024¶
Tất cả các bảng log và dữ liệu có thể chứa thông tin cá nhân (như user_id, input_used, tenant_id) đều:
- Tuân thủ chính sách ẩn danh hóa theo ADR-024 - Data Anonymization & Retention
- Cần kiểm tra masking hợp lý trước khi lưu log truy vấn hoặc log dashboard
10. Phân quyền truy cập dữ liệu¶
Toàn bộ hệ thống Reporting Service tuân thủ mô hình phân quyền động (RBAC) đã được mô tả trong ADR-007 và rbac-deep-dive.md.
10.1. Truy vấn báo cáo (/reports/query)¶
- Kiểm tra quyền truy cập:
- Mỗi
report_templatekhai báo một hoặc nhiềurequired_permission. - Tại thời điểm truy vấn,
RBAC Validatorsẽ kiểm tra xem user có đủ các permission cần thiết trong context tenant hay không. - Việc này được thực hiện ở tầng API Gateway (dựa trên
x-required-permission) và ở tầng Reporting Service như lớp kiểm tra bổ sung (fail-safe). - Ví dụ permission code:
report.view_financial_summaryreport.view_user_growth
10.2. Quản lý Template (/report-templates/**)¶
- Chỉ Superadmin có quyền thực hiện các thao tác tạo, cập nhật, vô hiệu hóa template.
- Permission áp dụng:
report.manage_templatesreport.view_templates
10.3. Saved Report Configs & Dashboards (/saved-configs, /dashboards)¶
- Quyền theo người dùng:
- Người dùng chỉ được phép xem/chỉnh sửa/lưu dashboard của chính mình (
user_id) - RBAC nâng cao (nếu áp dụng):
- Có thể thêm permission như
report.save_config,report.share_dashboardnếu muốn mở rộng chia sẻ trong tương lai.
10.4. Logging & Truy vết¶
- Dữ liệu log (
report_query_logs) được ghi lại cho mỗi truy vấn nhưng chỉ Superadmin và các Auditor mới có quyền truy cập để xem toàn bộ. - API log truy vấn không public trong OpenAPI.
10.5. Cơ chế kiểm soát phân quyền¶
| Tầng kiểm soát | Vai trò |
|---|---|
| API Gateway | Enforce x-required-permission từ template |
| Reporting Service | Kiểm tra lại bằng RBACValidator nội bộ |
| Database | Không để lộ dữ liệu nhạy cảm; xác thực ở tầng truy vấn |
10.6. Liên kết ADR¶
11. Mở rộng trong tương lai¶
Hệ thống dữ liệu của Reporting Service được thiết kế với khả năng mở rộng cao nhằm đáp ứng các nhu cầu mới của tổ chức và tích hợp các công nghệ hiện đại như AI, multi-tenant reporting, và dashboard động.
11.1. Mở rộng Schema Template¶
- Thêm các loại input parameter mới:
multi-select enum,daterange,autocomplete query,dynamic metric- Support các rule validate nâng cao:
- Theo
regex,min/max, hoặc phụ thuộc lẫn nhau giữa các parameter
11.2. Cấu trúc Template động theo từng nhóm báo cáo¶
- Tách các bảng
report_templatesvàreport_template_versionsthành các nhóm (module hóa) theo lĩnh vực:user_growth,revenue,admissions, v.v. - Hỗ trợ đa ngôn ngữ cho
name,description
11.3. Dashboard Config nâng cao¶
- Cho phép:
- Lưu dashboard chia sẻ được giữa nhiều người
- Có trạng thái "private/public"
- Dashboard phân quyền theo role
11.4. Audit Log nâng cao¶
- Mở rộng thêm bảng
report_audit_logs: - Lưu lại truy vấn, hành động chỉnh sửa template, quyền truy cập dữ liệu theo user
- Tuân thủ ADR-008 - Audit Logging
11.5. Chuẩn bị cho AI Agent¶
- Thiết kế schema
report_query_logsvàsaved_configscó thể phục vụ recommendation engine: - Dự đoán báo cáo thường dùng
- Tự động đề xuất dashboard cho từng nhóm người dùng
- Lưu metadata đủ phong phú để AI dễ phân tích hành vi
11.6. Truy vấn thời gian thực (Streaming Report)¶
- Kết nối với BigQuery Streaming hoặc hệ thống OLAP (Clickhouse, Pinot) để hỗ trợ báo cáo gần real-time.
- Thêm cột
is_streaming_enabledtrongreport_templates
11.7. Tích hợp tổ chức thứ 3 (External Systems)¶
- Cho phép ghi
report_query_logsvào hệ thống giám sát như: - GCP Cloud Logging
- Elastic Stack
- Cho phép gọi webhook khi một loại báo cáo được truy cập đủ nhiều (dùng cho cảnh báo hệ thống)
12. ENUM¶
Dưới đây là các giá trị ENUM được sử dụng trong schema của Reporting Service. Các enum này nên được lưu trữ tập trung trong file schema hoặc table config (nếu cần mở rộng động).
12.1. status trong report_query_logs¶
| Giá trị | Ý nghĩa |
|---|---|
success |
Truy vấn thành công |
error |
Lỗi trong quá trình truy vấn |
timeout |
Truy vấn bị timeout |
unauthorized |
Người dùng không có quyền |
validation_failed |
Sai định dạng hoặc thiếu tham số |
12.2. layout_type trong saved_dashboard_layouts¶
| Giá trị | Ý nghĩa |
|---|---|
chart |
Biểu đồ đơn |
table |
Dạng bảng |
dashboard_grid |
Giao diện nhiều biểu đồ |
12.3. input_type trong report_template_versions.input_parameters_schema¶
| Giá trị | Mô tả |
|---|---|
string |
Chuỗi văn bản |
number |
Số |
date |
Ngày |
enum |
Tập giá trị lựa chọn |
multi-select |
Chọn nhiều giá trị |
boolean |
Đúng/Sai |
daterange |
Khoảng thời gian |
autocomplete |
Gợi ý từ danh sách |
query-select |
Truy vấn động danh sách từ data_view |
12.4. permission_code (ví dụ)¶
| Giá trị | Mô tả |
|---|---|
report.view_financial_summary |
Xem báo cáo tài chính tổng quan |
report.manage_report_templates |
Quản lý mẫu báo cáo |
report.view_user_growth |
Xem tăng trưởng người dùng |
report.save_config |
Lưu cấu hình báo cáo cá nhân |
Lưu ý: Các enum này được dùng trong schema report_template_versions.input_parameters_schema, các cấu hình template, và cơ chế phân quyền động.
Dưới đây là MARKDOWN BLOCK cho phần mới 📑 13. ENUM dưới dạng bảng phụ trợ, giúp bạn quản lý các enum dưới dạng bảng dữ liệu thay vì chỉ là CHECK. Cách này giúp:
- Dễ cập nhật, tra cứu, hỗ trợ dashboard quản trị.
- Cho phép mapping mô tả và metadata (ngôn ngữ, màu sắc, v.v.).
- Thân thiện hơn nếu bạn dùng BigQuery hoặc dashboard tùy biến.
📑 13. ENUM dưới dạng bảng phụ trợ¶
Thay vì sử dụng CHECK constraint, hệ thống sẽ quản lý các giá trị enum quan trọng dưới dạng bảng phụ trợ (lookup tables). Điều này tăng tính linh hoạt và khả năng mở rộng.
13.1. 📄 report_statuses¶
Trạng thái trả về khi thực hiện một truy vấn báo cáo.
CREATE TABLE report_statuses (
status TEXT PRIMARY KEY,
description TEXT,
color TEXT -- ví dụ: dùng cho dashboard UI
);
INSERT INTO report_statuses (status, description, color) VALUES
('success', 'Truy vấn thành công', 'green'),
('error', 'Lỗi không xác định', 'red'),
('timeout', 'Quá thời gian xử lý', 'orange'),
('unauthorized', 'Không đủ quyền truy cập', 'gray'),
('validation_failed', 'Tham số đầu vào không hợp lệ', 'yellow');
Bảng này thay thế CHECK(status IN ...) trong report_query_logs.
13.2. 📄 dashboard_layout_types¶
Các kiểu layout dashboard cho phép.
CREATE TABLE dashboard_layout_types (
layout_type TEXT PRIMARY KEY,
description TEXT
);
INSERT INTO dashboard_layout_types (layout_type, description) VALUES
('chart', 'Hiển thị dạng biểu đồ'),
('table', 'Hiển thị dạng bảng'),
('dashboard_grid', 'Dạng lưới kết hợp');
Thay thế CHECK(layout_type IN ...) trong saved_dashboard_layouts.
🔗 Áp dụng¶
Các bảng như report_query_logs, saved_dashboard_layouts sẽ tham chiếu qua FOREIGN KEY:
FOREIGN KEY (status) REFERENCES report_statuses(status)
FOREIGN KEY (layout_type) REFERENCES dashboard_layout_types(layout_type)
🎯 Lợi ích:
- Hỗ trợ hiển thị UI phong phú (label, color, v.v.).
- Dễ thay đổi, mở rộng mà không cần ALTER TABLE.
- Có thể đồng bộ và quản lý qua giao diện admin.