Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,33 @@ pnpm dev # http://localhost:3000 ;Console: /_console/ ;管理员 adm
1 个草稿方案(4 节点流程、5 个参与主体、18 条指标下达)。用户不能种子,请在 Setup 中创建
用户、加入组织单元并分配岗位。

> ⚠️ 演示夹具的租户对齐(临时):种子写入的组织单元 `organization_id` 为空,而管理员在
> Setup 里新建的单元会被引擎盖上当前组织;共享规则的收件方展开对这一列做等值比较,所以
> 只有种子单元展开不出人。`src/data/align-demo-units.ts` 在 `kernel:bootstrapped` 时把这几个
> 种子单元(且仅这几个 id、且仅 `organization_id` 为空的行、且仅 dev / test)补成与 Setup 新建
> 单元一致。这是 objectstack-ai/objectstack#14547 的临时夹具修补,平台修复落地后请连同
> `objectstack.config.ts` 里的调用一起删除。

## 角色与岗位

| 需求角色 | 岗位(position) | 权限集 | 数据范围 |
|---|---|---|---|
| 系统管理员 | `kpi_admin`(组织 owner/admin 自动等同) | `kpi_admin_set` | 全部 |
| 人力审核 | `kpi_hr_reviewer` | `kpi_hr_reviewer_set` | 全部 |
| 人力负责人 | `kpi_hr_head` | `kpi_hr_head_set` | 全部 |
| 部门填报人员 | `kpi_dept_reporter` | `kpi_dept_reporter_set` | 本部门(private + 按主体共享规则) |
| 分公司核对人员 | `kpi_branch_checker` | `kpi_branch_checker_set` | 本分公司核对任务 |
| 分管领导 | `kpi_exec_leader` | `kpi_exec_leader_set` | 开源版按全部放行;企业版切 `unit_and_below` |

「本部门 / 分管」深度依赖平台企业版 `hierarchy-security`;开源版用 `src/security/sharing-rules.ts`
的按组织单元共享规则表达本部门可见,实施时按真实组织追加单元 id。
| 部门填报人员 | `kpi_dept_reporter` | `kpi_dept_reporter_set` | 本部门(private + 动态记录共享) |
| 分公司核对人员 | `kpi_branch_checker` | `kpi_branch_checker_set` | 本分公司核对任务(private + 动态记录共享) |
| 分管领导 | `kpi_exec_leader` | `kpi_exec_leader_set` | 所分管主体(private + 动态记录共享) |

「本部门 / 本分公司 / 分管范围」不依赖平台企业版 `hierarchy-security` 的 `unit / unit_and_below`
深度:填报单、核对任务、数据调整、考核结果的 OWD 都是 private,可见性由方案发布时按
「参与主体」「分管领导」「到人分工」写入的**共享规则数据**(`src/services/sharing-service.ts`)
放宽。接入新客户组织只改数据,不改元数据。

规则**按方案**建:条件里带方案 id,规则名按方案加前缀,发布时对本方案做一次对账 ——
换掉分管领导、撤掉参与主体、撤掉到人分工,旧授权当场失效,而历史方案的授权原样保留。
方案**已关闭 / 已归档**后转为「留读、去写」:填报单、核对任务、数据调整由可编辑降为只读
(还要查得到历史,但不该再改),考核结果本就只读。

## 业务流程(默认 4 节点,可按方案配置)

Expand Down
10 changes: 5 additions & 5 deletions docs/04-需求符合度清单.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
| 4 | 填报:按填报视图录入或批量导入 → 自动保存 → 即时算分 → 提交冻结 | ✅ | 填报单表单内嵌明细网格 + 明细列表内联编辑;`EntryLineScoreHook` 保存即算分(T8、T9、T11);提交后明细冻结(T16);导入走平台 CSV 向导、xlsx 导出 | ⚠️ xlsx 直接导入为平台导入 API 能力,未做专用按钮(pre-intake R-低-02,列二期) |
| 5 | 核对与审核:分公司并行核对 → 人力审核 → 领导审批;驳回填原因、退回上一环节 | ✅ | 提交按分公司生成并行核对任务(T15),争议阻断推进(T18),全部确认自动推进(T19);驳回原因必填(T20),退回上一节点并重置核对(T21);人力 → 领导 → 已通过(T22、T23) | — |
| 6 | 计分:按既定口径自动算每个指标得分 | ✅ | `src/lib/scoring.ts` 四种方式 + 单元测试 14 条;计算说明落库 | 口径细节(逆向指标、封顶、到人合成)按推断实现,待疑点 Q-01~Q-05 拍板后只改数据 / 一处代码 |
| 7 | 汇总:部门 / 分公司 / 到人 / 分管领导四维,可钻取到指标得分明细 | ✅ | `kpi_result` 由 `results-service` 在通过 / 归档 / 调整落地时生成(T24、T27);结果对象带来源填报单与计算明细 JSON;看板 2、矩阵报表可钻取 | ⚠️ 加减分批准后不自动重算结果(需下一次通过 / 调整 / 归档触发);升级项 |
| 7 | 汇总:部门 / 分公司 / 到人 / 分管领导四维,可钻取到指标得分明细 | ✅ | `kpi_result` 由 `results-service` 在通过 / 归档 / 调整落地时生成(T24、T27);加减分审批落定后由 `BonusAfterDecideHook` 立即重算(T48、T49);结果对象带来源填报单与计算明细 JSON;看板 2、矩阵报表可钻取 | — |
| 8 | 归档:审批通过后生成不可变快照,数据锁定 | ✅ | `kpi_snapshot`(SHA-256 校验和)+ `SnapshotImmutableHook`(T28~T30);归档后明细、加减分锁定(T31、T32) | — |

## 二、范围功能(需求 §1.3)
Expand All @@ -27,15 +27,15 @@
| 12 | 加减分 | ✅ | `kpi_bonus` 主从填报单,审批后计入最终得分(T25) | 封顶 / 保底未做(疑点 Q-04 待拍板) |
| 13 | 数据调整(源数据 / 计算结果) | ✅ | `kpi_adjustment`:记录调整前值、审批、批准即落地并重算(T26、T27) | — |
| 14 | 审计查询 | ✅ | `kpi_review_record` 只增不改(T33、T34)+ 平台审计日志 / 记录历史页签 | — |
| 15 | 组织与权限 | ✅ | 复用平台组织单元 / 用户;岗位 6、权限集 6、共享规则 28 | 见 §三 数据范围偏差 |
| 15 | 组织与权限 | ✅ | 复用平台组织单元 / 用户;岗位 6、权限集 6;共享规则不再是元数据,由方案发布按参与主体动态写入(`src/services/sharing-service.ts`,T39) | 见 §三 数据范围偏差 |
| 16 | 数据接入与归档 | ✅ | 填报 / 导入 / 系统计算三类来源在指标上声明;归档快照 | 「系统计算」来源的自动取数需对接客户数据源,零外部集成(蓝图 §4) |

## 三、角色与安全(需求 §2)

| # | 需求 | 态 | 实现落点 / 证据 | 偏差与出口 |
|---|---|---|---|---|
| 17 | 六类角色职责 | ✅ | 岗位 `kpi_admin / kpi_hr_reviewer / kpi_hr_head / kpi_dept_reporter / kpi_branch_checker / kpi_exec_leader`,流程节点按岗位把关(hook 经 `sys_user_position` 查询) | 组织 owner / admin 自动等同系统管理员 |
| 18 | 数据范围:全部 / 分管 / 本部门 / 仅本人 | ⚠️ | 全部 = org、仅本人 = own 原生;本部门 / 本分公司 = private 基线 + 按组织单元共享规则(`sharing-rules.ts`);到人结果行级安全只看本人 | **平台受限**:`unit / unit_and_below` 深度属企业版 `hierarchy-security`(`objectstack validate` 明示,企业包未公开发布)。分管范围在开源版按全部放行;切企业版改两处 scope 即可。已记入解读报告 R-中-05、蓝图 V0.2 |
| 18 | 数据范围:全部 / 分管 / 本部门 / 仅本人 | ✅ | 全部 = org、仅本人 = own 原生;本部门 / 本分公司 / 分管范围 = private 基线 + 方案发布时按参与主体、分管领导、到人分工写入的**动态共享规则**(`src/services/sharing-service.ts`),组织变化零元数据改动;到人结果行级安全只挡他人的到人维度(T41、T44、T46、T51)。不再依赖企业版 `hierarchy-security` | 四点实现说明:① 规则**按方案**建(条件带方案 id、规则名按方案加前缀),发布时对账停用本方案下已不该存在的规则 —— 换掉分管领导、撤主体、撤到人分工都当场失效,历史方案的授权原样保留(T54~T56);② 方案**已关闭 / 已归档**后,填报单 / 核对任务 / 调整由 `edit` 降为 `read`(留读、去写),结果本就只读(T57);③ 本应用的业务记录全部由 hook 以系统上下文创建,而平台对 `isSystem` 写入跳过记录共享物化(官方补偿手段是重新求值规则),因此每个业务触发点都重新声明一次相关规则;④ 演示种子的组织单元 `organization_id` 为空,`src/data/align-demo-units.ts` 在启动时把它们补成与 Setup 新建单元一致 —— 这是 objectstack-ai/objectstack#14547 的**临时夹具**修补,平台修复后删除(T52) |
| 19 | 越权访问拒绝、经办人以登录账号为准 | ✅ | 权限集对象级 + 字段级;经办人 / 审批人字段只读由 hook 盖章 | — |
| 20 | 账号安全(密码策略、停用即失效、失败限制、白名单、敏感操作留痕) | ✅ | 平台账号体系(`sys_user` 失败计数 / 锁定 / 封禁 / 强制改密);审批、驳回、归档留痕 | 访问来源白名单归部署层(反向代理 / 网关)配置 |

Expand All @@ -50,5 +50,5 @@

## 五、统计

- ✅ 完整实现 19 条;⚠️ 有偏差 5 条(#4 xlsx 直导、#7 加减分不触发重算、#18 分管范围、#22 自由公式边界、#23 未压测);❌ 未实现 0 条。
- ⚠️ 出口:#18 平台受限(已登记、已给企业版切换路径);#4 / #7 / #23 升级为二期事项交 PM 裁决;#22 退回需求确认(演示后拍板)。
- ✅ 完整实现 21 条;⚠️ 有偏差 3 条(#4 xlsx 直导、#22 自由公式边界、#23 未压测);❌ 未实现 0 条。
- ⚠️ 出口:#4 / #23 升级为二期事项交 PM 裁决;#22 退回需求确认(演示后拍板)。#18 已完整实现,但其中的演示夹具对齐是临时的,随 objectstack-ai/objectstack#14547 的平台修复删除。
Binary file added docs/evidence/issue-2/admin-sheets.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/evidence/issue-2/checker-tasks.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/evidence/issue-2/leader-sheets.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/evidence/issue-2/reporter-sheets.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions objectstack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import { KpiApp } from './src/apps/index.js';
import { allHooks } from './src/hooks/index.js';
import { allPermissionSets, allPositions } from './src/security/index.js';
import { registerKpiPositionBindings } from './src/security/bind-position-sets.js';
import { allSharingRules } from './src/security/sharing-rules.js';
import { KpiTranslationBundle } from './src/translations/index.js';
import { KpiSeedData } from './src/data/index.js';
import { registerDemoUnitAlignment } from './src/data/align-demo-units.js';

/**
* KPI 考核管理系统 — 基于 ObjectStack 的独立应用。
Expand Down Expand Up @@ -48,12 +48,13 @@ export default defineStack({

positions: allPositions,
permissions: allPermissionSets,
sharingRules: allSharingRules,

data: KpiSeedData,
});

/** 岗位↔权限集绑定在安全引导完成后幂等补齐(不能用种子,见 bind-position-sets.ts)。 */
export const onEnable = async (ctx: unknown): Promise<void> => {
registerKpiPositionBindings(ctx as Parameters<typeof registerKpiPositionBindings>[0]);
// 演示夹具的租户对齐 —— 临时,随 objectstack-ai/objectstack#14547 的平台修复一起删除。
registerDemoUnitAlignment(ctx as Parameters<typeof registerDemoUnitAlignment>[0]);
};
Loading