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

39 KiB
Raw Permalink Blame History

一期批次1总体设计 —— 数据库设计hr-webocai 口径)

  • 版本v3.0批次1设计定稿v3.0 变更:对齐 SRS v3.1 —— 库名 hrs/MariaDB、新增编制(F16)/项目式(F17) 5 张表与 sys_openapp 预留表43→49、roster_employee 证件字段扩展D1 手工录入、org_entry 登记链接/二维码字段扫码入职降级、org_leave_handover 钉钉交接占位、字典扩充)
  • 状态:设计定稿批次1评审修订版
  • 需求基线:docs/00-requirement/requirement-spec.mdSRS v3.1+ iteration1-function-detail.mdF01F15+ approved-features.mdFEAT-B1-0112
  • 架构基线:docs/01-design/architecture.md
  • 规范依据ocai 技能集 database-table-definition-specmodels/*.json + json2ddl、crud-definition-spec、sqlor-database-module

1. 设计总则

  1. 表定义声明式管理:所有表以 models/{table}.jsonsummary/fields/indexes/codes 四段定义build.sh 中 json2ddl mysql . > mysql.ddl.sql 生成 DDL 导入 hrs 库。本文 DDL 为生成物等价示例,开发以 models JSON 为准。
  2. 统一约定InnoDButf8mb4 / utf8mb4_unicode_ci数据库 MariaDB库名 hrs;主键 id VARCHAR(32)getID() 雪花串sqlor 惯例);公共审计列 created_by/updated_by/created_at/updated_atsor.C 不自动填时间戳,写入时显式 created_at=curDateString()
  3. 逻辑删除策略:员工与组织不做物理删除,统一走"停用(status=inactive)/离职流程";物理删除仅 admin 可执行且必须留审计SRS §5.2-2
  4. 自定义字段EAV花名册字段F03与组织字段F01采用"字段定义表 + 字段值表"EAV 方案;固定高频查询字段(组织、职位、状态、入离职日期)冗余在员工主表保证列表性能。
  5. 敏感字段:身份证号密文列 + 哈希列(确定性哈希,供唯一性与黑名单匹配),手机号明文存储、按角色脱敏展示;roster_field_def.sensitive 驱动字段级脱敏与可见性SRS §2.2-4
  6. 库划分:单库 hrs,表前缀区分模块:org_(hr-org)、roster_(hr-roster)、flow_(hr-flow)、contract_(hr-contract)、sys_(hr-system)appbaseusers/orgs/appcodes与 rbac 表沿用基础包自带结构,不在本文重复。
  7. 预留字段约定:二期对接预留字段一律带明确默认值与字典枚举位(如 esign_status='not_enabled'、id_source='manual'、send_channel='site'),不参与一期业务分支。

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 │ 提醒规则
   │   ▼                     │      │  sys_openapp     │ API开放预留
   │ 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  │          ▼
   │  org_headcount_scheme │     ┌──────────────┐
   │   └ headcount_item    │     │  flow_def    │ 流程定义
   │   └ headcount_snapshot│     │  flow_form_def│ 表单定义(引用花名册字段)
   │  org_project(F17)     │     │  flow_node_def│ 节点(审批人/字段权限)
   │   └ org_project_post  │     │  flow_role    │ 审批角色
   │        │审批流转       │     │  flow_instance│ 实例 ──► flow_task(待办)
   └────────┴──────────────┴────►│               │        └► flow_op_log
              biz_type+biz_id    └──────────────┘
hr-report 无自有表:只读聚合 org_/roster_/flow_ 表,叠加 sys_data_scope 范围过滤。

核心关系说明:

  • roster_employee 为全系统员工数据唯一事实源;org_entry/regularization/transfer/leave/concurrent_post 通过 employee_id(入职审批阶段可为空)关联,审批通过后经 hr-roster roster_writeback 更新主档。
  • 所有审批类记录通过 flow_instance_id 关联流程实例;flow_instance.biz_type + biz_id 反向定位业务单据,流程完成后回调业务模块回写。
  • 编制F16org_headcount_scheme 1─N headcount_item(细分额度);headcount_snapshot 按日快照历史;员工异动回写后同步触发占编重算。占编范围条件以 JSON 表达(员工类型/状态/职位/职级/自定义字段),与 roster_employee + roster_field_value 联查计数。
  • 项目式组织F17org_project 为横向组织(自引用多层级),员工经 org_project_post 同时挂纵向部门roster_employee.org_id与横向项目横向职务体系复用 org_job 表org_job.job_category=horizontal 区分,被花名册/薪酬引用)。
  • 所有表与 appbase.users 之间为逻辑外键operator_id/leader_id/approver_id不建物理外键sqlor 惯例,跨模块解耦)。

3. models JSON 示例规范格式json2ddl 输入)

hr-roster/models/roster_employee.json(含 D1 证件字段组扩展):

{
  "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_type", "title": "证件类型", "type": "varchar", "length": 16, "default": "id_card"},
    {"name": "id_number_cipher", "title": "证件号密文", "type": "varchar", "length": 256},
    {"name": "id_number_hash", "title": "证件号哈希", "type": "varchar", "length": 64},
    {"name": "id_valid_from", "title": "证件有效期起", "type": "date"},
    {"name": "id_valid_to", "title": "证件有效期止(长期=9999-12-31)", "type": "date"},
    {"name": "id_authority", "title": "证件签发机关", "type": "varchar", "length": 128},
    {"name": "id_source", "title": "证件信息来源", "type": "varchar", "length": 16, "default": "manual"},
    {"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": "probation_end_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": "prev_employee_id", "title": "复职关联原档案ID", "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_probation_end", "fields": ["probation_end_date"]},
    {"name": "idx_direct_leader", "fields": ["direct_leader_id"]},
    {"name": "idx_prev_employee", "fields": ["prev_employee_id"]}
  ],
  "codes": [
    {"name": "gender", "source": "appcodes", "code": "GENDER"},
    {"name": "employee_type", "source": "appcodes", "code": "EMP_TYPE"},
    {"name": "employee_status", "source": "appcodes", "code": "EMP_STATUS"},
    {"name": "id_source", "source": "appcodes", "code": "ID_SOURCE"}
  ]
}

CRUD 侧配套 hr-roster/json/roster_employee_list.jsoncrud-definition-spectblname=roster_employeeparams 顶层配置 new_data_url/update_data_url/delete_data_url 指向 wwwroot/api/roster_employee_{create,update,delete}.dspydata_filter 声明姓名/工号/组织/状态筛选项,browserfields.alters 引用 GENDER/EMP_TYPE/EMP_STATUS 字典。

4. 表结构设计49 张业务表)

公共列约定:凡标【审计】的表均含 created_by/updated_by/created_at/updated_at;日志/快照类表仅含 created_at。DDL 示例见 §5。 v3.0 变化hr-org 18→23+编制 3 表+项目式 2 表、hr-system 7→8+sys_openapp 预留、roster_employee/org_entry/org_leave_handover 字段扩展;合计 49 张

4.1 hr-org 组织人事23 张,前缀 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/F17 id, job_code, job_name, job_category(vertical/horizontalF17 横向职务), status, sort_no, remark【审计】 uk_job_code; idx_job_category
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_type, id_number_cipher/hash, id_valid_from/id_valid_to/id_authority/id_source(手工录入 D1), 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(none/invited/filled), register_token, register_url, qrcode_file, register_expire(登记链接/二维码,扫码入职降级), flow_instance_id, remark【审计】 idx_entry_status; idx_hire_date; idx_flow_instance_id; uk_register_token
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/dingtalk_resource(钉钉资源交接占位,D3)/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
19 org_headcount_scheme 编制方案F16 id, scheme_name, cycle_type(year/quarter/month字典HEADCOUNT_CYCLE), cycle_start, cycle_end, status(active/inactive), remark【审计】 idx_cycle(cycle_start,cycle_end); idx_status
20 headcount_item 编制细分项F16 id, scheme_id, scope_json(占编范围:员工类型/状态/职位/职级/自定义字段条件), seg_json(细分维度,可空=整体), head_limit(int), remark【审计】 idx_scheme_id
21 headcount_snapshot 编制快照F16 历史回溯/实时计数) id, scheme_id, item_id, snap_date, used_count(int), over_count(int超编数), created_at uk(scheme_id,item_id,snap_date); idx_snap_date
22 org_project 项目式组织F17 id, project_code, project_name, parent_id(自引用多层级), owner_id(负责人), start_date, end_date, project_status(active/expired/inactive), attrs_json(项目属性), sort_no【审计】 uk_project_code; idx_parent_id; idx_project_status
23 org_project_post 项目任职F17 员工挂横向组织) id, project_id, employee_id, job_id(横向职务,引用 org_job job_category=horizontal), start_date, end_date, status(active/expired)【审计】 uk(project_id,employee_id,job_id,start_date); idx_employee_id

4.2 hr-roster 花名册7 张,前缀 roster_

# 用途 关键字段 关键索引
24 roster_field_group 字段分组F03 id, group_code, group_name(工作信息/个人信息/绩效结果/培训记录), sort_no, status【审计】 uk_group_code
25 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
26 roster_employee 员工主档F03 见 §3 models 示例(含证件字段组/probation_end_date/prev_employee_id 见 §3
27 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
28 roster_empno_rule 工号规则F03 id, rule_name, prefix, match_field(如company_id), match_value, seq_length, current_seq(int), status【审计】
29 roster_timeline 员工时间轴F03/F12 联动) id, employee_id, event_type(entry/regular/transfer/leave/concurrent/contract/field_change/headcount/project/migrate), event_date, title, content_json, source_type, source_id, created_at idx_emp_date(employee_id,event_date)
30 roster_type_rule 员工类型字段规则F03 分类管理) id, employee_type, field_rules_json(按类型必填/隐藏字段), status【审计】 uk(employee_type)

4.3 hr-flow 流程审批7 张,前缀 flow_

# 用途 关键字段 关键索引
31 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/attendance_*桩位), fields_json(引用roster_field_def或自定义项), status【审计】 uk_form_code
32 flow_def 流程定义F10 id, flow_code, flow_name, form_id, biz_type, match_cond_json(员工类型/部门匹配条件), version, status【审计】 uk_flow_code; idx_biz_type
33 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
34 flow_role 审批角色F10 id, role_name, flow_scope_json(可用流程), op_perm_json(操作权限), data_scope_json(数据查看范围), status【审计】
35 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
36 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
37 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_

# 用途 关键字段 关键索引
38 contract_type 合同类型F09 自定义) id, type_code, type_name(劳动合同/保密协议/竞业协议…), status【审计】 uk_type_code
39 contract_template 合同模板F09 id, template_name, type_id, file_path, field_marks_json(占位符映射), status【审计】
40 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, text_file_path(模板生成合同文本,D4), flow_instance_id, remind_rule_id, esign_status(not_enabled/待二期流转,D4), remark【审计】 idx_employee; idx_end_date; idx_status
41 contract_remind_rule 到期提醒规则F09 id, rule_name, days_before(int), target_role(self/leader/hr), content_template, status【审计】

4.5 hr-system 权限日志与通用服务8 张,前缀 sys_

# 用途 关键字段 关键索引
42 sys_data_scope 数据范围F11 id, admin_user_id(管理员), scope_type(org/field), org_ids_json(组织维度,含子树), field_ids_json(花名册字段维度), remark【审计】 idx_admin_user
43 sys_audit_log 操作日志F12只增不改 id, module, target_type, target_id, operation(create/update/delete/import/export/approve/login/migrate), 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)
44 sys_message 站内消息F15 id, receiver_id, msg_type(todo/approval/remind/care/notice), title, content, biz_type, biz_id, send_channel(site; sms/email预留 D9), is_read, created_at idx_receiver_read(receiver_id,is_read); idx_created_at
45 sys_remind_rule 通用提醒规则F15 多场景) 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)
46 sys_announcement 企业公告F15 id, title, content, publish_scope_json, publish_time, status(draft/published/offline), created_by【审计】 idx_status
47 sys_policy 企业政策F15 id, title, file_path, view_scope_json, downloadable(0/1), publish_time, status, created_by【审计】 idx_status
48 sys_care_config 关怀配置F15 生日/周年) id, care_type(birthday/anniversary), template, enable(0/1), push_target(employee/leader), updated_by, updated_at uk_care_type
49 sys_openapp API 开放应用一期预留FEAT-B1-01⑦ id, app_key, app_secret_cipher, app_name, scope_json(授权资源), rate_limit(int), status(active/inactive)【审计】 uk_app_key

5. 核心表 DDL 示例json2ddl 生成等价物)

-- roster_employee完整字段见 §3 models JSON此处为等价 DDL 含证件字段组)
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_type VARCHAR(16) DEFAULT 'id_card' COMMENT '证件类型',
  id_number_cipher VARCHAR(256) DEFAULT NULL COMMENT '证件号密文',
  id_number_hash VARCHAR(64) DEFAULT NULL COMMENT '证件号哈希(唯一)',
  id_valid_from DATE DEFAULT NULL COMMENT '证件有效期起',
  id_valid_to DATE DEFAULT NULL COMMENT '证件有效期止(长期=9999-12-31)',
  id_authority VARCHAR(128) DEFAULT NULL COMMENT '证件签发机关',
  id_source VARCHAR(16) DEFAULT 'manual' COMMENT '证件来源(字典ID_SOURCE: manual/card_reader预留)',
  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,
  probation_end_date DATE DEFAULT NULL COMMENT '试用期止(预计转正日,转正提醒依据)',
  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 '直属主管',
  prev_employee_id VARCHAR(32) DEFAULT NULL COMMENT '复职关联原档案ID(F04-5)',
  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_probation_end (probation_end_date),
  KEY idx_direct_leader (direct_leader_id),
  KEY idx_prev_employee (prev_employee_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 '业务类型(字典FLOW_BIZ_TYPE)',
  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/migrate',
  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='操作日志(只增)';

-- F16 编制管理(新增)
CREATE TABLE org_headcount_scheme (
  id VARCHAR(32) NOT NULL,
  scheme_name VARCHAR(128) NOT NULL COMMENT '方案名称',
  cycle_type VARCHAR(16) NOT NULL COMMENT '周期(字典HEADCOUNT_CYCLE: year/quarter/month)',
  cycle_start DATE NOT NULL, cycle_end DATE NOT NULL,
  status VARCHAR(16) NOT NULL DEFAULT 'active',
  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),
  KEY idx_cycle (cycle_start, cycle_end),
  KEY idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='编制方案';

CREATE TABLE headcount_item (
  id VARCHAR(32) NOT NULL,
  scheme_id VARCHAR(32) NOT NULL COMMENT '编制方案',
  scope_json TEXT NOT NULL COMMENT '占编范围条件(员工类型/状态/职位/职级/自定义字段)',
  seg_json TEXT DEFAULT NULL COMMENT '细分维度(空=整体)',
  head_limit INT NOT NULL DEFAULT 0 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),
  KEY idx_scheme_id (scheme_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='编制细分项';

CREATE TABLE headcount_snapshot (
  id VARCHAR(32) NOT NULL,
  scheme_id VARCHAR(32) NOT NULL,
  item_id VARCHAR(32) NOT NULL COMMENT '细分项',
  snap_date DATE NOT NULL COMMENT '快照日期',
  used_count INT NOT NULL DEFAULT 0 COMMENT '占编人数',
  over_count INT NOT NULL DEFAULT 0 COMMENT '超编数(0=未超编)',
  created_at TIMESTAMP NULL DEFAULT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY uk_scheme_item_date (scheme_id, item_id, snap_date),
  KEY idx_snap_date (snap_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='编制快照(历史回溯)';

-- F17 项目式组织(新增)
CREATE TABLE org_project (
  id VARCHAR(32) NOT NULL,
  project_code VARCHAR(32) NOT NULL COMMENT '项目编码',
  project_name VARCHAR(128) NOT NULL COMMENT '项目名称',
  parent_id VARCHAR(32) DEFAULT NULL COMMENT '上级项目(多层级)',
  owner_id VARCHAR(32) DEFAULT NULL COMMENT '负责人',
  start_date DATE DEFAULT NULL, end_date DATE DEFAULT NULL COMMENT '时间范围',
  project_status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT 'active/expired/inactive(到期自动标识)',
  attrs_json TEXT DEFAULT NULL COMMENT '项目属性',
  sort_no INT DEFAULT 0,
  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_project_code (project_code),
  KEY idx_parent_id (parent_id),
  KEY idx_project_status (project_status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='项目式组织';

CREATE TABLE org_project_post (
  id VARCHAR(32) NOT NULL,
  project_id VARCHAR(32) NOT NULL COMMENT '项目组织',
  employee_id VARCHAR(32) NOT NULL COMMENT '员工',
  job_id VARCHAR(32) DEFAULT NULL COMMENT '横向职务(org_job.job_category=horizontal)',
  start_date DATE DEFAULT NULL, end_date DATE DEFAULT NULL,
  status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT 'active/expired',
  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_proj_emp_job (project_id, employee_id, job_id, start_date),
  KEY idx_employee_id (employee_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='项目任职(横向)';

6. 索引与性能策略

  1. 100 人规模全表扫描亦可满足 ≤500ms但仍按查询模式建索引列表筛选列status/org_id/hire_date/end_date、EAV 值表 uk(employee_id,field_id)、待办 idx(approver_id,task_status)、转正提醒 idx(probation_end_date)。
  2. 组织树、职位职级主数据一次性全量加载≤200/≤500 行),前端缓存,无需分页。
  3. EAV 查询模式:花名册列表先按主表条件分页取员工,再批量 IN 查值表拼装(每页 ≤50 人 × 显示字段数),避免 EAV 行转列大 JOIN。
  4. 报表hr-report直接 SQL 聚合sor.sqlExe 只读100 人规模不建物化视图,满足"延迟 ≤5 分钟"实为实时sys_audit_log 按月保留,冷数据归档不删除。
  5. 编制计数headcount_snapshot 以"异动事件触发 + 每日兜底扫描"双机制维护;实时查询取最新 snap_date历史回溯按 snap_date 精确取数F16 验收③)。
  6. 唯一性:工号、组织编码、项目编码、职位/职务/职级/职等编码、审批编号、登记表 token 均唯一索引;证件号经哈希列唯一(密文为非确定性加密,哈希列承担唯一性与黑名单匹配)。

7. 数据字典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 员工状态(待入职/试用/正式/待离职/离职)
ID_TYPE id_card/passport/other 证件类型
ID_SOURCE manual/card_reader(预留,二期) 证件信息来源D1
POS_CATEGORY management/professional/skill 职位类别
JOB_CATEGORY vertical/horizontal 职务类别F17 横向职务)
TRANSFER_TYPE promotion/demotion/position_change/org_adjust 调动类型
LEAVE_REASON personal/company/contract_expire/retire/other 离职原因
HANDOVER_TYPE approval/file/subordinate/permission/dingtalk_resource(占位)/other 离职交接项类型D3
CONTRACT_STATUS active/expired/stopped/renewing 合同状态
ESIGN_STATUS not_enabled/signing/signed(后两者二期启用) 电子签状态D4 预留)
FLOW_BIZ_TYPE entry/regular/transfer/leave/handover/concurrent/contract_sign/contract_renew/contract_change/contract_stop/roster_self_edit/attendance_*(桩位) 审批业务类型
INST_STATUS running/approved/rejected/cancelled 实例状态
REMIND_SCENE entry/regular/leave/retire/contract_expire/health_cert/social_insurance/custom 提醒场景≥6 类F15 验收④)
HEADCOUNT_CYCLE year/quarter/month 编制周期F16
PROJECT_STATUS active/expired/inactive 项目状态F17到期自动 expired
MSG_CHANNEL site/sms(预留)/email(预留) 消息渠道D9
AUDIT_OP create/update/delete/import/export/approve/login/migrate 操作类型
ENTRY_STATUS pending_approval/pending_entry/entered/cancelled/blocked 入职状态
REGISTER_STATUS none/invited/filled 登记表状态

枚举一律不硬编码于 dspyCRUD 下拉经 models codes 段引用。

8. staff-mgr 数据迁移策略v1 → 一期NFR-8

迁移工具:repos/hr-system 仓内规划 scripts/migrate_staff_mgr.pyPython + 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+hashid_source='manual',证件有效期/签发机关置空待补department_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 去重,重跑仅补差;证件号哈希冲突时输出冲突报告人工裁决(冲突员工按离职记录保留,不入在职)。
  3. 范围:默认"在职 + 离职保留档案"全量;仅迁在职/含历史的最终范围与切换时间点待 PM 确认SRS §11-Q3脚本参数 --scope=active|all 支持两种口径。
  4. 切换UAT 通过后一次性迁移+双库比对 → staff-mgr 服务下线、仓库冻结只读(保留一个迭代周期)。
  5. 迁移全程写 sys_audit_logoperation=migrate迁移数据在时间轴/日志中可辨识。

9. 与需求验收项的映射(摘选)

验收项 数据支撑
F01-4 时间轴留痕 org_unit_change
F01-5 历史架构图 org_unit.effective_date/expire_date + org_unit_change 回放
F02-1~5 五套体系 org_job/position/sequence/grade_level/grade_rank
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 身份证手工录入D1 roster_employee/org_entry 证件字段组 + id_source='manual'
F04-5 复职 roster_employee.prev_employee_id
F04-6 黑名单拦截 org_blacklistid_number_hash 匹配)
F05-3 转正提醒 roster_employee.probation_end_date + sys_remind_rule(scene=regular)
F07-3 钉钉交接占位D3 org_leave_handover.item_type=dingtalk_resource
F07-5 离职证明 org_leave.certificate_filefiles/ 存储)
F09-6 电子签预留D4 contract_info.esign_status + contract_template.text_file_path
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
F13-6 报表数据范围受控 聚合查询叠加 sys_data_scope
F15-4 多场景提醒≥6 类) sys_remind_rule(scene_code) + REMIND_SCENE 字典
F16-1~6 编制 org_headcount_scheme/headcount_item/headcount_snapshot
F17-1~3 项目式组织 org_project/org_project_post + org_job(job_category=horizontal)
FEAT-B1-01⑦ API 开放预留 sys_openapp一期不启用