fix(cma): 工作台跨实体污染治本 — 全局键拆账套 + 缺列收口 + 预警归属兜底
任务 dama-workbench-entity-isolation-fullstack-20260922(DAMA 诊断 / 项目Bot batch5 §B / 任总 2026-09-22「都批」) B1 现金基线拆账套(零 DDL) - cash_forecast_engine: 键 cash.current_balance → cash.current_balance.<entity_id>; 读只读本账套键、不做旧键回退;set_* 签名 entity_id 必传(漏传 TypeError) - cash.py: POST /balance 挂 get_entity_id;网银流水联动写回带账套 B3(a) alignment_config 拆账套(零 DDL) - alignment.py: GET/POST /config、GET /tree 只读 alignment_config.<entity_id>;未配置=configured:false B3(b) 预警 KPI 归属兜底 - bot_bridge_v2: 去掉 kpi_id or 1 兜底;本账套无 KPI 定义 → 跳过建预警 + OperationLog 留痕 (kpi_alerts.kpi_id NOT NULL ⇒ 方案A 置 NULL 不可行,走方案B 跳过+审计) B2 缺列五表分表处置 - notification_logs: 经 alert_id → kpi_alerts.entity_id join 归属(无父键行不返回) - notification_channels / okr_templates: 集团共享口径写入 docstring(有意不过滤) - system_configs: 由 B1/B3(a) 拆键覆盖;kpi_data_quality_logs 沿用 batch5 的 join 收口 P0 语义收敛 - tenant.py: current_tenant 收敛为项目Bot A2A 状态记录,GET 仅 it/ceo;POST 补 operation_logs 审计 证据:新增/改写用例 22 条;全量 1370 passed(基线 1348)
This commit is contained in:
@@ -2,10 +2,21 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from app.database import get_db
|
||||
from app.deps import get_entity_id
|
||||
from app.models import NotificationChannel, NotificationLog
|
||||
from app.auth_middleware import require_role, require_auth_401
|
||||
from datetime import datetime
|
||||
|
||||
# ── B2(2026-09-22 dama-workbench-entity-isolation-fullstack-20260922)────────────────
|
||||
# 本模块两张表在 `models/__init__.py` 均**无 entity_id 列**,按「分表处置」口径落地:
|
||||
# · `notification_logs`(Log 类)→ **经父键 join 归属**,零迁移:
|
||||
# alert_id → kpi_alerts.id → kpi_alerts.entity_id(GET /logs 已收口)。
|
||||
# · `notification_channels`(**配置类,无父键可桥接**)→ 任总 2026-09-22 已批
|
||||
# 「方案 1(零 DDL)」:**保持全局 = 集团共享配置**(一套 wecom/mail/sms 渠道
|
||||
# 供全账套复用;预警推送是集团行为,渠道与账套无关)。
|
||||
# ⚠️ 因此 `/channels*` 四个端点**有意不按账套过滤**——这是口径,不是漏隔离。
|
||||
# 若后续需要「账套私有渠道」,须单独立单加 entity_id 列(DDL + 回填 + 唯一键改造)。
|
||||
|
||||
# 用户端点:统一要求会话 Bearer 鉴权(cma-api-auth-surface-audit-20260914)
|
||||
# 缺口:本 router 6 个端点全部无鉴权——无 token 可读写通知渠道(config 内含 webhook
|
||||
# 地址/令牌等凭据)、可触发渠道测试推送、可读推送日志。收口为 require_auth_401。
|
||||
@@ -97,14 +108,28 @@ def test_channel(ch_id: int, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.get("/logs")
|
||||
def list_logs(page: int = 1, db: Session = Depends(get_db)):
|
||||
"""通知历史"""
|
||||
total = db.query(NotificationLog).count()
|
||||
logs = db.query(NotificationLog).order_by(
|
||||
def list_logs(page: int = 1,
|
||||
entity_id: int = Depends(get_entity_id),
|
||||
db: Session = Depends(get_db)):
|
||||
"""通知历史(**按会话账套收口**,B2 零迁移)
|
||||
|
||||
2026-09-22 dama-workbench-entity-isolation-fullstack-20260922(§四 B2):
|
||||
`notification_logs` 无 entity_id 列 → 经父键 join 归属:
|
||||
`notification_logs.alert_id → kpi_alerts.id → kpi_alerts.entity_id`。
|
||||
口径与 batch5 对 `KpiDataQualityLog` 的处置一致(宁少勿错):
|
||||
`alert_id IS NULL` 的行无可归属父键 → **不返回**(不暴露给任一账套)。
|
||||
"""
|
||||
from app.models import KPIAlert
|
||||
scoped = (db.query(NotificationLog)
|
||||
.join(KPIAlert, NotificationLog.alert_id == KPIAlert.id)
|
||||
.filter(KPIAlert.entity_id == entity_id))
|
||||
total = scoped.count()
|
||||
logs = scoped.order_by(
|
||||
NotificationLog.created_at.desc()
|
||||
).offset((page - 1) * 20).limit(20).all()
|
||||
return {
|
||||
"total": total,
|
||||
"entity_id": entity_id,
|
||||
"data": [{
|
||||
"id": l.id,
|
||||
"alert_id": l.alert_id,
|
||||
|
||||
Reference in New Issue
Block a user