feat(后端): 添加授权体系、系统监控与试用期计提

按 2026-11-02 需求补齐计划交付后端能力:
- 角色授权:权限目录化,接口统一准入校验,未登记默认拒绝;
  管理员判断改为按数据库角色重新判定,防止权限码持有者绕过
- 系统监控:单进程采集资源、请求与异常指标,分钟级聚合,
  阈值配置化;敏感配置增加 repr 保护,Redis 密码 URL 转义
- 试用期计提:按回款日判定并写入快照,年度结清与调整单联动;
  人员模型补试用期、离职日期与工资版本历史字段
- 计提模板:公式骨架受控,页面维护名称与参数绑定
- T+ 采集:自动化配置表与进度查询

内置角色禁停用保护对齐模块注释;核算规则版本提为常量并
补充批量核算失败堆栈日志。

影响范围:后端全部模块、数据库迁移 V22-V28
验证:uv run ruff check 通过;922 个单元测试全部通过;
集成测试因本机 MySQL 数据卷被其他容器锁定暂未运行
This commit is contained in:
liuwenxin committed 2026-11-03 11:20:55 +08:00
1 parent 02fb06e0af
commit 1461a8d113
149 files changed
+8736 -368

No files matched your search

+16 -2
View File
@@ -148,7 +148,9 @@ def _cycle_current(session, state):
def tick(session, *, settings=None, now=None):
settings, now = settings or get_settings(), now or local_now()
if not settings.t_plus_automation_enabled:
from app.services.tplus.automation_config import configuration
if not configuration(session, settings)["enabled"]:
return {"status": "DISABLED", "queued": False}
if settings.t_plus_stop_file and Path(settings.t_plus_stop_file).exists():
return {"status": "STOP_REQUESTED", "queued": False}
@@ -243,10 +245,22 @@ def overview(session, *, settings=None, now=None):
base = {"enabled": settings.t_plus_automation_enabled, "weekday": settings.t_plus_schedule_weekday,
"time": settings.t_plus_schedule_time, "timezone": "Asia/Shanghai", "worker_phase": "UNKNOWN",
"heartbeat_at": None, "last_success_at": None, "next_retry_at": None, "alerts": []}
from app.services.tplus.automation_config import configuration
base.update(configuration(session, settings))
base["stop_requested"] = bool(settings.t_plus_stop_file and Path(settings.t_plus_stop_file).exists())
try:
key, database = source_identity(settings)
except RuntimeError:
database = task_service.history_source_database(session)
if database:
base["last_success_at"] = session.scalar(
select(func.max(TPlusSyncBatch.finished_at)).where(
TPlusSyncBatch.source_database == database,
TPlusSyncBatch.status == "SUCCEEDED",
TPlusSyncBatch.sync_mode == "FULL",
)
)
return base
if not inspect(session.connection()).has_table(TPlusAutomationState.__tablename__):
base["alerts"] = [{"code": "MIGRATION_REQUIRED", "message": "运行状态结构尚未升级"}]
@@ -265,7 +279,7 @@ def overview(session, *, settings=None, now=None):
alerts.append({"code": "QUEUE_OVERDUE", "message": "采集任务排队超过15分钟", "batch_no": queued.batch_no})
last_success = session.scalar(select(func.max(TPlusSyncBatch.finished_at)).where(TPlusSyncBatch.source_database == database, TPlusSyncBatch.status == "SUCCEEDED", TPlusSyncBatch.sync_mode == "FULL"))
base["last_success_at"] = last_success
if settings.t_plus_automation_enabled and not base["stop_requested"]:
if base["enabled"] and not base["stop_requested"]:
if last_success is None or now - last_success > timedelta(days=8):
alerts.append({"code": "SYNC_STALE", "message": "尚无成功采集或超过8天未成功同步"})
if state is None or state.heartbeat_at is None or now - state.heartbeat_at > timedelta(minutes=2) or state.worker_phase == "STOPPED":