统一鉴权中心接入(ADR-012):org 重写为 Keycloak 身份 + 角色→端;中间件按路由归属统一判;口令/会话/岗位授权退役;迁移 0032

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015kAzS35kMnZNt4YGgJXtfw
This commit is contained in:
xcs
2026-08-25 17:40:55 +08:00
co-authored by Claude Opus 5
parent 81a185cd61
commit dd31b91829
38 changed files with 1236 additions and 1485 deletions
+8 -5
View File
@@ -17,6 +17,7 @@ import { renderView } from '@modules/interaction';
import type { InteractionService } from '@modules/interaction';
import type { MessageService } from '@modules/message';
import type { OrgService } from '@modules/org';
import { NONE_POSITION_CODE } from '@modules/org';
import type { LlmService, ModelGateway } from '@modules/llm';
import type { ActivityRegistryService } from '@modules/activity-registry';
import type { SkillEngineService } from '@modules/skill-engine';
@@ -2453,7 +2454,11 @@ export function wireEngines(deps: EngineWiringDeps): EngineWiring {
},
},
org: {
positions: async () => new Set((await deps.org.listStaff()).positions.map((p) => p.code)),
// 哨兵岗 NONE(未分配)不是流程包能声明的岗位 —— 不进候选集(ADR-012)
positions: async () =>
new Set(
(await deps.org.listStaff()).positions.filter((p) => p.code !== NONE_POSITION_CODE).map((p) => p.code),
),
candidates: async (position) => {
const staff = await deps.org.staffOfPosition(position);
const withLoad = await Promise.all(
@@ -2614,10 +2619,8 @@ export function wireEngines(deps: EngineWiringDeps): EngineWiring {
// 起单失败入死信 —— 落日志 + 送治理台的消息要素,不静默丢弃
report: async (input) => {
writeLog(`[trigger] 起单失败入死信:${input.triggerId} —— ${input.reason}`);
const { staff } = await deps.org.listStaff();
for (const person of staff) {
const governs = await deps.org.authorize(person.id, { kind: 'governance', function: 'trigger' }, 'govern');
if (!governs) continue;
// 收件人 = 能进运营中心的人(触发器的启停归运营;ADR-012 权限只到端)
for (const person of await deps.org.staffWithEnd('ops')) {
await deps.message.notify({
staffId: person.id,
title: `触发器起单失败:${input.triggerId}`,