hr-system/docs/01-design/database-design.md

356 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 迭代1总体设计 —— 数据库设计hr-webocai 口径)
- 版本v2.0迭代1-总体设计,取代 v1 Java/JPA 口径v1 已归档至 `docs/_archive/01-design-v1-old/`
- 状态:提交审核
- 需求基线:`docs/00-requirement/requirement-spec.md`SRS v2+ `iteration1-function-detail.md`F01~F15
- 架构基线:`docs/01-design/architecture.md`
- 规范依据ocai 技能集 database-table-definition-specmodels/*.json + json2ddl、crud-definition-spec、sqlor-database-module
## 1. 设计总则
1. **表定义声明式管理**:所有表以 `models/{table}.json`summary/fields/indexes/codes 四段定义build.sh 中 `json2ddl mysql . > mysql.ddl.sql` 生成 DDL 导入 `hr` 库。本文 DDL 为生成物等价示例,开发以 models JSON 为准。
2. **统一约定**InnoDButf8mb4 / utf8mb4_unicode_ci主键 `id VARCHAR(32)`getID() 雪花串sqlor 惯例);公共审计列 `created_by/updated_by/created_at/updated_at``sor.C` 不自动填时间戳,写入时显式 `created_at=curDateString()`
3. **逻辑删除策略**迭代1员工与组织**不做物理删除**,统一走"停用(status=inactive)/离职流程"(对 baseline-decision Q6 的裁决落地)。
4. **自定义字段EAV**花名册字段F03与组织字段F01采用"字段定义表 + 字段值表"EAV 方案,支撑字段/分组/类型规则自定义;固定高频查询字段(组织、职位、状态、入离职日期)冗余在员工主表保证列表性能。
5. **敏感字段**:身份证号密文列 + 哈希列(确定性,供唯一性与黑名单匹配),手机号明文存储、按角色脱敏展示;`roster_field_def.sensitive` 驱动字段级脱敏与可见性。
6. **库划分**:单库 `hr`,表前缀区分模块:`org_`(hr-org)、`roster_`(hr-roster)、`flow_`(hr-flow)、`contract_`(hr-contract)、`sys_`(hr-system)appbaseusers/orgs/appcodes与 rbac 表沿用基础包自带结构,不在本文重复。
## 2. ER 图(实体关系描述)
```
┌──────────────┐
│ appbase │
│ users/orgs/ │◄── 登录用户、字典 appcodes
│ appcodes │
└──────┬───────┘
│ user_id 引用
┌─────────────┐ parent_id │ ┌──────────────────┐
│ org_unit │◄─自引用──────┼──────│ sys_data_scope │ 组织维度数据范围
│ 组织 │ │ │ sys_audit_log │ 操作日志(F12)
└──┬───┬──────┘ │ │ sys_message │ 站内消息(F15)
│ │org_field_value │ │ sys_remind_rule │ 提醒规则
│ ▼ │ └────────▲─────────┘
│ org_field_def │ │ 推送
│ │ │
│ ┌─────────────┐ ┌─────▼───────────────┴───┐
│ │org_job/ │ │ roster_employee │ 员工唯一事实源(F03)
│ │org_position◄─┼──│ org_id/position_id/ │
│ │org_sequence/ │ │ employee_status/... │
│ │org_grade_* │ └──┬──────┬──────┬─────────┘
│ └─────────────┘ │ │ │
│ │ │ ▼
│ roster_field_def◄────┘ roster_field_value(EAV)
│ roster_field_group roster_timeline(时间轴)
│ │
│ 异动业务(hr-org) │ 合同(hr-contract)
│ org_entry ──────────┤ contract_info ── employee_id
│ org_regularization ─┼──► contract_type / contract_template
│ org_transfer(+detail)│ contract_remind_rule
│ org_leave(+handover) │ │审批
│ org_concurrent_post │ ▼
│ │审批流转 │ ┌──────────────┐
└────────┴──────────────┴────►│ flow_def │ 流程定义
biz_type+biz_id │ flow_form_def│ 表单定义(引用花名册字段)
│ flow_node_def│ 节点(审批人/字段权限)
│ flow_role │ 审批角色
│ flow_instance│ 实例 ──► flow_task(待办)
│ │ └► flow_op_log
└──────────────┘
hr-report 无自有表:只读聚合 org_/roster_/flow_ 表,叠加 sys_data_scope 范围过滤。
```
核心关系说明:
- `roster_employee` 为全系统员工数据唯一事实源;`org_entry/regularization/transfer/leave/concurrent_post` 通过 `employee_id`(入职审批阶段可为空)关联,审批通过后经 hr-roster 回写接口更新主档。
- 所有审批类记录通过 `flow_instance_id` 关联流程实例;`flow_instance.biz_type + biz_id` 反向定位业务单据,流程完成后回调业务模块回写。
- `roster_field_value`/`org_field_value` 为 EAV 值表,外键指向 `roster_field_def`/`org_field_def`
- 所有表与 appbase.users 之间为逻辑外键operator_id/leader_id/approver_id不建物理外键sqlor 惯例,跨模块解耦)。
## 3. models JSON 示例规范格式json2ddl 输入)
`hr-roster/models/roster_employee.json`
```json
{
"summary": [
{"name": "roster_employee", "title": "员工主档", "pk": ["id"], "charset": "utf8mb4", "collate": "utf8mb4_unicode_ci"}
],
"fields": [
{"name": "id", "title": "主键", "type": "varchar", "length": 32},
{"name": "employee_no", "title": "工号", "type": "varchar", "length": 32},
{"name": "name", "title": "姓名", "type": "varchar", "length": 64},
{"name": "gender", "title": "性别", "type": "varchar", "length": 16},
{"name": "id_number_cipher", "title": "证件号密文", "type": "varchar", "length": 256},
{"name": "id_number_hash", "title": "证件号哈希", "type": "varchar", "length": 64},
{"name": "birthday", "title": "出生日期", "type": "date"},
{"name": "phone", "title": "手机号", "type": "varchar", "length": 20},
{"name": "email", "title": "邮箱", "type": "varchar", "length": 128},
{"name": "org_id", "title": "组织", "type": "varchar", "length": 32},
{"name": "position_id", "title": "职位", "type": "varchar", "length": 32},
{"name": "job_id", "title": "职务", "type": "varchar", "length": 32},
{"name": "grade_level_id", "title": "职级", "type": "varchar", "length": 32},
{"name": "grade_rank_id", "title": "职等", "type": "varchar", "length": 32},
{"name": "sequence_id", "title": "序列", "type": "varchar", "length": 32},
{"name": "employee_type", "title": "员工类型", "type": "varchar", "length": 16},
{"name": "employee_status", "title": "员工状态", "type": "varchar", "length": 16},
{"name": "hire_date", "title": "入职日期", "type": "date"},
{"name": "regular_date", "title": "转正日期", "type": "date"},
{"name": "leave_date", "title": "离职日期", "type": "date"},
{"name": "company_id", "title": "合同公司", "type": "varchar", "length": 32},
{"name": "work_location", "title": "办公地点", "type": "varchar", "length": 128},
{"name": "direct_leader_id", "title": "直属主管", "type": "varchar", "length": 32},
{"name": "remark", "title": "备注", "type": "text"},
{"name": "created_by", "title": "创建人", "type": "varchar", "length": 32},
{"name": "updated_by", "title": "更新人", "type": "varchar", "length": 32},
{"name": "created_at", "title": "创建时间", "type": "timestamp"},
{"name": "updated_at", "title": "更新时间", "type": "timestamp"}
],
"indexes": [
{"name": "uk_employee_no", "unique": true, "fields": ["employee_no"]},
{"name": "uk_id_number_hash", "unique": true, "fields": ["id_number_hash"]},
{"name": "idx_org_id", "fields": ["org_id"]},
{"name": "idx_status", "fields": ["employee_status"]},
{"name": "idx_hire_date", "fields": ["hire_date"]},
{"name": "idx_direct_leader", "fields": ["direct_leader_id"]}
],
"codes": [
{"name": "gender", "source": "appcodes", "code": "GENDER"},
{"name": "employee_type", "source": "appcodes", "code": "EMP_TYPE"},
{"name": "employee_status", "source": "appcodes", "code": "EMP_STATUS"}
]
}
```
CRUD 侧配套 `hr-roster/json/roster_employee_list.json`crud-definition-spec`tblname=roster_employee``params` 顶层配置 `new_data_url/update_data_url/delete_data_url` 指向 `wwwroot/api/roster_employee_{create,update,delete}.dspy``data_filter` 声明姓名/工号/组织/状态筛选项,`browserfields.alters` 引用 GENDER/EMP_TYPE/EMP_STATUS 字典。
## 4. 表结构设计43 张业务表)
> 公共列约定:凡标【审计】的表均含 `created_by/updated_by/created_at/updated_at`;日志类表仅含 `created_at`。DDL 示例见 §4.6。
### 4.1 hr-org 组织人事18 张,前缀 org_
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 1 | org_unit | 组织F01 | id, org_code, org_name, parent_id(自引用), org_type(字典ORG_TYPE), leader_id, effective_date, expire_date(空=长期), status(active/inactive), sort_no【审计】 | uk_org_code; idx_parent_id; idx_status |
| 2 | org_unit_change | 组织变更时间轴F01 | id, org_id, change_type(add/edit/disable/move/split/merge/delete), before_json, after_json, effective_date, operator_id, flow_instance_id, created_at | idx_org_id; idx_created_at |
| 3 | org_field_def | 组织自定义字段F01 | id, field_code, field_name, field_type(text/number/date/select/file), options_json, required, sort_no, status【审计】 | uk_field_code |
| 4 | org_field_value | 组织字段值 EAV | id, org_id, field_id, value_text, value_date, value_file, updated_at | uk(org_id,field_id) |
| 5 | org_job | 职务F02 | id, job_code, job_name, status, sort_no, remark【审计】 | uk_job_code |
| 6 | org_position | 职位F02 | id, position_code, position_name, job_id, sequence_id, category(字典POS_CATEGORY), dept_ids(多值,逗号分隔), description, status, sort_no【审计】 | uk_position_code; idx_job_id |
| 7 | org_sequence | 序列F02 | id, seq_category, seq_name, grade_level_ids(关联职级类别), status【审计】 | — |
| 8 | org_grade_level | 职级F02 | id, level_code, level_name, level_category, start_rank_id, end_rank_id, sort_no【审计】 | uk_level_code |
| 9 | org_grade_rank | 职等F02 | id, rank_code, rank_name, rank_level(int), sort_no【审计】 | uk_rank_code |
| 10 | org_blacklist | 黑名单F04/F07 | id, name, id_number_hash, id_number_cipher, reason, source(leave/manual), source_employee_id, created_by, created_at | idx_id_number_hash |
| 11 | org_contract_company | 合同公司F01/F09 | id, company_code, company_name, credit_code, legal_person, contact_info, status【审计】 | uk_company_code |
| 12 | org_entry | 入职记录F04 | id, employee_id(可空,待入职), name, id_number_cipher/hash, employee_type, org_id, position_id, company_id, work_location, hire_date, entry_status(pending_approval/pending_entry/entered/cancelled/blocked), is_rehire, register_status(登记表填写状态), flow_instance_id, remark【审计】 | idx_entry_status; idx_hire_date; idx_flow_instance_id |
| 13 | org_regularization | 转正记录F05 | id, employee_id, probation_end_date, regular_date, apply_type(self/proxy/manual), status(pending/approved/rejected/cancelled), flow_instance_id, remark【审计】 | idx_employee_id; idx_regular_date |
| 14 | org_transfer | 调动单F06支持批量 | id, transfer_type(promotion/demotion/position_change/org_adjust), status(pending/confirmed/cancelled), effective_date, batch_no, flow_instance_id, remark【审计】 | idx_status; idx_effective_date |
| 15 | org_transfer_detail | 调动明细(逐人) | id, transfer_id, employee_id, from_org_id, to_org_id, from_position_id, to_position_id, from_grade_level_id, to_grade_level_id, status | idx_transfer_id; idx_employee_id |
| 16 | org_leave | 离职记录F07 | id, employee_id, leave_type(辞职/劝退/合同到期/退休), leave_reason(字典LEAVE_REASON), leave_date, apply_type(self/proxy/manual), status(pending_leave/left/cancelled), handover_status, certificate_file, blacklist_flag, flow_instance_id, remark【审计】 | idx_employee_id; idx_status; idx_leave_date |
| 17 | org_leave_handover | 离职交接项 | id, leave_id, item_type(approval/file/subordinate/permission/other), item_content, handover_to_id, status(pending/done), remark | idx_leave_id |
| 18 | org_concurrent_post | 兼岗F08 | id, employee_id, org_id, position_id, start_date, end_date, status(awaiting/active/expired), flow_instance_id【审计】 | idx_employee_id; idx_status |
### 4.2 hr-roster 花名册7 张,前缀 roster_
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 19 | roster_field_group | 字段分组F03 | id, group_code, group_name(工作信息/个人信息/绩效结果/培训记录), sort_no, status【审计】 | uk_group_code |
| 20 | roster_field_def | 字段定义F03 核心) | id, group_id, field_code, field_name, field_type(text/number/date/select/multiselect/file), options_json(字典code或自定义项), required, sensitive(0/1), editable_self(0/1), need_audit(0/1自助修改审核), apply_types(JSON适用员工类型), sort_no, status【审计】 | uk_field_code; idx_group_id |
| 21 | roster_employee | 员工主档F03 | 见 §3 models 示例 | 见 §3 |
| 22 | roster_field_value | 字段值 EAV | id, employee_id, field_id, value_text, value_number(decimal(18,4)), value_date, value_file, updated_by, updated_at | uk(employee_id,field_id); idx_field_id |
| 23 | roster_empno_rule | 工号规则F03 | id, rule_name, prefix, match_field(如company_id), match_value, seq_length, current_seq(int), status【审计】 | — |
| 24 | roster_timeline | 员工时间轴F03/F12 联动) | id, employee_id, event_type(entry/regular/transfer/leave/concurrent/contract/field_change/migrate), event_date, title, content_json, source_type, source_id, created_at | idx_emp_date(employee_id,event_date) |
| 25 | roster_type_rule | 员工类型字段规则F03 分类管理) | id, employee_type, field_rules_json(按类型必填/隐藏字段), status【审计】 | uk(employee_type) |
### 4.3 hr-flow 流程审批7 张,前缀 flow_
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 26 | flow_form_def | 表单定义F10 | id, form_code, form_name, biz_type(entry/regular/transfer/leave/handover/concurrent/contract_sign/contract_renew/contract_change/contract_stop/roster_self_edit), fields_json(引用roster_field_def或自定义项), status【审计】 | uk_form_code |
| 27 | flow_def | 流程定义F10 | id, flow_code, flow_name, form_id, biz_type, match_cond_json(员工类型/部门匹配条件), version, status【审计】 | uk_flow_code; idx_biz_type |
| 28 | flow_node_def | 流程节点 | id, flow_id, node_seq, node_name, approver_type(user/role/leader/admin/flow_role), approver_value, pass_rule(any/all), field_perm_json(节点字段可读写), cc_to(抄送) | idx_flow_id |
| 29 | flow_role | 审批角色F10 | id, role_name, flow_scope_json(可用流程), op_perm_json(操作权限), data_scope_json(数据查看范围), status【审计】 | — |
| 30 | flow_instance | 流程实例 | id, inst_no(审批编号), flow_id, form_id, biz_type, biz_id, title, initiator_id, inst_status(running/approved/rejected/cancelled), submit_data_json, start_time, finish_time | uk_inst_no; idx_biz(biz_type,biz_id); idx_initiator; idx_status |
| 31 | flow_task | 审批任务(待办/已办) | id, instance_id, node_id, node_name, approver_id, task_status(pending/approved/rejected/forwarded/cancelled), comment, handle_time, created_at | idx_approver_status(approver_id,task_status); idx_instance |
| 32 | flow_op_log | 流转日志 | id, instance_id, op_type(submit/approve/reject/forward/cancel/withdraw), operator_id, comment, created_at | idx_instance |
### 4.4 hr-contract 合同4 张,前缀 contract_
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 33 | contract_type | 合同类型F09 自定义) | id, type_code, type_name(劳动合同/保密协议/竞业协议…), status【审计】 | uk_type_code |
| 34 | contract_template | 合同模板F09 | id, template_name, type_id, file_path, field_marks_json(占位符映射), status【审计】 | — |
| 35 | contract_info | 合同台账F09 | id, contract_no, employee_id, type_id, company_id, template_id, start_date, end_date, sign_date, contract_status(active/expired/stopped/renewing), file_path, flow_instance_id, remind_rule_id, esign_status(预留), remark【审计】 | idx_employee; idx_end_date; idx_status |
| 36 | contract_remind_rule | 到期提醒规则F09 | id, rule_name, days_before(int), target_role(self/leader/hr), content_template, status【审计】 | — |
### 4.5 hr-system 权限日志与通用服务7 张,前缀 sys_
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 37 | sys_data_scope | 数据范围F11 | id, admin_user_id(管理员), scope_type(org/field), org_ids_json(组织维度,含子树), field_ids_json(花名册字段维度), remark【审计】 | idx_admin_user |
| 38 | sys_audit_log | 操作日志F12只增不改 | id, module, target_type, target_id, operation(create/update/delete/import/export/approve/login), operator_id, operator_name, before_json, after_json, request_ip, created_at | idx_target(target_type,target_id); idx_operator; idx_created_at; idx_module_op(module,operation) |
| 39 | sys_message | 站内消息F15 | id, receiver_id, msg_type(todo/approval/remind/care/notice), title, content, biz_type, biz_id, send_channel(site; sms/email预留), is_read, created_at | idx_receiver_read(receiver_id,is_read); idx_created_at |
| 40 | sys_remind_rule | 通用提醒规则F12 场景) | id, scene_code(entry/regular/leave/retire/contract_expire/health_cert/social_insurance/custom), rule_name, days_before, content_template, target_role(admin/employee/leader), status【审计】 | uk(scene_code,rule_name) |
| 41 | sys_announcement | 企业公告F15 | id, title, content, publish_scope_json, publish_time, status(draft/published/offline), created_by【审计】 | idx_status |
| 42 | sys_policy | 企业政策F15 | id, title, file_path, view_scope_json, downloadable(0/1), publish_time, status, created_by【审计】 | idx_status |
| 43 | sys_care_config | 关怀配置F15 生日/周年) | id, care_type(birthday/anniversary), template, enable(0/1), push_target(employee/leader), updated_by, updated_at | uk_care_type |
### 4.6 核心表 DDL 示例json2ddl 生成等价物)
```sql
-- roster_employee完整 DDL 见 §3 models JSON
CREATE TABLE roster_employee (
id VARCHAR(32) NOT NULL COMMENT '主键',
employee_no VARCHAR(32) NOT NULL COMMENT '工号',
name VARCHAR(64) NOT NULL COMMENT '姓名',
gender VARCHAR(16) DEFAULT NULL COMMENT '性别(字典GENDER)',
id_number_cipher VARCHAR(256) DEFAULT NULL COMMENT '证件号密文',
id_number_hash VARCHAR(64) DEFAULT NULL COMMENT '证件号哈希(唯一)',
birthday DATE DEFAULT NULL,
phone VARCHAR(20) DEFAULT NULL,
email VARCHAR(128) DEFAULT NULL,
org_id VARCHAR(32) DEFAULT NULL COMMENT '组织',
position_id VARCHAR(32) DEFAULT NULL COMMENT '职位',
job_id VARCHAR(32) DEFAULT NULL COMMENT '职务',
grade_level_id VARCHAR(32) DEFAULT NULL COMMENT '职级',
grade_rank_id VARCHAR(32) DEFAULT NULL COMMENT '职等',
sequence_id VARCHAR(32) DEFAULT NULL COMMENT '序列',
employee_type VARCHAR(16) DEFAULT NULL COMMENT '员工类型(字典EMP_TYPE)',
employee_status VARCHAR(16) DEFAULT NULL COMMENT '状态(字典EMP_STATUS)',
hire_date DATE DEFAULT NULL,
regular_date DATE DEFAULT NULL,
leave_date DATE DEFAULT NULL,
company_id VARCHAR(32) DEFAULT NULL COMMENT '合同公司',
work_location VARCHAR(128) DEFAULT NULL,
direct_leader_id VARCHAR(32) DEFAULT NULL COMMENT '直属主管',
remark TEXT DEFAULT NULL,
created_by VARCHAR(32) DEFAULT NULL,
updated_by VARCHAR(32) DEFAULT NULL,
created_at TIMESTAMP NULL DEFAULT NULL,
updated_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_employee_no (employee_no),
UNIQUE KEY uk_id_number_hash (id_number_hash),
KEY idx_org_id (org_id),
KEY idx_status (employee_status),
KEY idx_hire_date (hire_date),
KEY idx_direct_leader (direct_leader_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='员工主档';
CREATE TABLE org_unit (
id VARCHAR(32) NOT NULL,
org_code VARCHAR(32) NOT NULL COMMENT '组织编码',
org_name VARCHAR(128) NOT NULL COMMENT '组织名称',
parent_id VARCHAR(32) DEFAULT NULL COMMENT '上级组织',
org_type VARCHAR(16) DEFAULT NULL COMMENT '组织类型(字典ORG_TYPE)',
leader_id VARCHAR(32) DEFAULT NULL COMMENT '负责人',
effective_date DATE DEFAULT NULL COMMENT '生效日期',
expire_date DATE DEFAULT NULL COMMENT '失效日期(空=长期)',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT 'active/inactive',
sort_no INT DEFAULT 0,
remark TEXT DEFAULT NULL,
created_by VARCHAR(32) DEFAULT NULL, updated_by VARCHAR(32) DEFAULT NULL,
created_at TIMESTAMP NULL DEFAULT NULL, updated_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_org_code (org_code),
KEY idx_parent_id (parent_id),
KEY idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='组织';
CREATE TABLE flow_instance (
id VARCHAR(32) NOT NULL,
inst_no VARCHAR(32) NOT NULL COMMENT '审批编号',
flow_id VARCHAR(32) NOT NULL, form_id VARCHAR(32) NOT NULL,
biz_type VARCHAR(32) NOT NULL COMMENT '业务类型', biz_id VARCHAR(32) DEFAULT NULL COMMENT '业务单据ID',
title VARCHAR(256) DEFAULT NULL,
initiator_id VARCHAR(32) NOT NULL,
inst_status VARCHAR(16) NOT NULL DEFAULT 'running' COMMENT 'running/approved/rejected/cancelled',
submit_data_json TEXT DEFAULT NULL COMMENT '提交表单数据快照',
start_time TIMESTAMP NULL DEFAULT NULL, finish_time TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_inst_no (inst_no),
KEY idx_biz (biz_type, biz_id),
KEY idx_initiator (initiator_id),
KEY idx_status (inst_status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='流程实例';
CREATE TABLE sys_audit_log (
id VARCHAR(32) NOT NULL,
module VARCHAR(32) NOT NULL COMMENT 'hr-org/hr-roster/...',
target_type VARCHAR(32) NOT NULL COMMENT 'roster_employee/org_unit/...',
target_id VARCHAR(32) NOT NULL,
operation VARCHAR(16) NOT NULL COMMENT 'create/update/delete/import/export/approve/login',
operator_id VARCHAR(32) NOT NULL, operator_name VARCHAR(64) DEFAULT '',
before_json TEXT DEFAULT NULL COMMENT '变更前快照',
after_json TEXT DEFAULT NULL COMMENT '变更后快照',
request_ip VARCHAR(64) DEFAULT NULL,
created_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_target (target_type, target_id),
KEY idx_operator (operator_id),
KEY idx_created_at (created_at),
KEY idx_module_op (module, operation)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='操作日志(只增)';
```
## 5. 索引与性能策略
1. 100 人规模全表扫描亦可满足 ≤500ms但仍按查询模式建索引列表筛选列status/org_id/hire_date/end_date、EAV 值表 uk(employee_id,field_id)、待办 idx(approver_id,task_status)。
2. 组织树、职位职级主数据一次性全量加载≤200/≤500 行),前端缓存,无需分页。
3. EAV 查询模式:花名册列表先按主表条件分页取员工,再批量 `IN` 查值表拼装(每页 ≤50 人 × 显示字段数),避免 EAV 行转列大 JOIN。
4. 报表hr-report直接 SQL 聚合sor.sqlExe 只读100 人规模不建物化视图sys_audit_log 按月保留,冷数据归档不删除。
5. 唯一性:工号、组织编码、职位/职务/职级/职等编码、审批编号均唯一索引;证件号经哈希列唯一(加密为非确定性,哈希列承担唯一与黑名单匹配)。
## 6. 数据字典appbase appcodesinit/data.json 初始化)
| code | 值 | 说明 |
|---|---|---|
| GENDER | male/female/unknown | 性别 |
| ORG_TYPE | group/subsidiary/dept/team | 组织类型 |
| EMP_TYPE | formal/temp/dispatch/intern | 员工类型(正式/临时/派遣/实习) |
| EMP_STATUS | pending_entry/probation/regular/pending_leave/left | 员工状态(待入职/试用/正式/待离职/离职) |
| POS_CATEGORY | management/professional/skill | 职位类别 |
| TRANSFER_TYPE | promotion/demotion/position_change/org_adjust | 调动类型 |
| LEAVE_REASON | personal/company/contract_expire/retire/other | 离职原因 |
| CONTRACT_STATUS | active/expired/stopped/renewing | 合同状态 |
| FLOW_BIZ_TYPE | entry/regular/transfer/leave/handover/concurrent/contract_sign/contract_renew/contract_change/contract_stop/roster_self_edit | 审批业务类型 |
| INST_STATUS | running/approved/rejected/cancelled | 实例状态 |
| REMIND_SCENE | entry/regular/leave/retire/contract_expire/health_cert/social_insurance/custom | 提醒场景 |
| AUDIT_OP | create/update/delete/import/export/approve/login | 操作类型 |
枚举一律不硬编码于 dspyCRUD 下拉经 models `codes` 段引用。
## 7. staff-mgr 数据迁移策略v1 → 迭代1
迁移工具:`repos/hr-system` 仓内规划 `scripts/migrate_staff_mgr.py`Python + sqlor幂等可重跑输出核对报告
| v1 源表staff-mgr | 目标表 | 映射规则 |
|---|---|---|
| staff_department_cache | org_unit | 按树形重建 parent_idorg_code=DEPT{id}status 映射 active/inactive |
| staff_employee | roster_employee | employee_no/name/gender/phone/email 直映id_number AES 解密后按新方案重加密cipher+hashdepartment_id→org_idposition 文本→预置 org_position无匹配则建"未定职"status: active→regular、probation→probation、inactive→lefthire_date 直映 |
| staff_employee_extra | roster_field_value + contract_info | education/major/school/graduation_date/previous_company/work_years → 预置 roster_field_def 字段值technical_level/salary_grade → 预置敏感字段值contract_type/start/end → contract_infotype_id 映射正式/外包/实习协议) |
| staff_change_log | roster_timeline | change_type→event_type(transfer/field_change)old/new 值入 content_jsonevent_type 前缀 `migrate:` 标识迁移来源 |
| staff_audit_log | sys_audit_log | 字段直映module 标记 `staff-mgr-legacy` |
策略与约束:
1. **顺序**org_unit → org_position预置→ roster_field_def/group预置→ roster_employee → roster_field_value → contract_info → timeline/audit。
2. **幂等**:按 employee_no/org_code 去重,重跑仅补差;证件号哈希冲突时输出冲突报告人工裁决(对 baseline-decision Q6冲突员工按离职记录保留不入在职
3. **切换**迭代1 UAT 通过后一次性迁移+双库比对 → staff-mgr 服务下线、仓库冻结只读(保留一个迭代周期)。
4. 迁移全程写 sys_audit_logoperation=migrate迁移数据在时间轴/日志中可辨识。
## 8. 与需求验收项的映射(摘选)
| 验收项function-detail | 数据支撑 |
|---|---|
| F01-4 时间轴留痕 | org_unit_change |
| F03-1/2 自定义字段与分组 | roster_field_def/group/value |
| F03-3 多规则工号 | roster_empno_rule |
| F03-4 自助修改审核 | roster_field_def.editable_self/need_audit + flow biz_type=roster_self_edit |
| F03-6 类型差异规则 | roster_type_rule + apply_types |
| F04-4 黑名单拦截 | org_blacklistid_number_hash 匹配) |
| F07-5 离职证明 | org_leave.certificate_filefiles/ 存储) |
| F09-6 电子签预留 | contract_info.esign_status |
| F10-2 字段权限 | flow_node_def.field_perm_json |
| F11-2 双维度数据范围 | sys_data_scope(scope_type=org/field) |
| F12-3 前后对比 | sys_audit_log.before_json/after_json |
| F15-4 多场景提醒 | sys_remind_rule(scene_code) |