feat: 配置API(分组校验管线/整份版本/回滚/重置出厂/试金石/平台设置)
- config_validation.validate_group: 九组校验管线(类型/键 allowlist/数值 范围/prompts 大小上限 50KB·100KB/wall 全量交 compile_wall/push.prefix 跨租户查重 spec E1),错误清单中文带字段路径 - config_routes: GET/PUT config(整组替换原样入版本,MAX+1,热 reload)/ reset(按 Tenant.profile 取出厂档案组)/versions 列表·详情/rollback (旧版复制为新版本,历史不可变)/wall/test 试金石(逐句判定,不落库 不 bump)/settings 平台设置 CRUD(仅超管,resolver 接线归 Phase 3) - db.write_config_version: 版本写入公共路径(创建向导与配置 API 单一 事实源);Tenant 落 profile 列(重置出厂按它取对应档案) - _profile_snapshot/_blankify 迁 tenant_source(两路由模块共用); db_source_app/super_client 夹具收拢 conftest(两测试文件共用) - 测试: 519 → 537 全绿 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ PlatformBase.metadata,engine/models.ensure_schema 只跑 Base.metadata——
|
||||
(Windows 文件锁,同 registry)。
|
||||
"""
|
||||
import datetime
|
||||
import json
|
||||
import pathlib
|
||||
|
||||
from sqlalchemy import (
|
||||
@@ -38,6 +39,7 @@ from sqlalchemy import (
|
||||
Text,
|
||||
UniqueConstraint,
|
||||
event,
|
||||
func,
|
||||
select,
|
||||
)
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
@@ -69,6 +71,10 @@ class Tenant(PlatformBase):
|
||||
slug: Mapped[str] = mapped_column(String(64), unique=True, index=True)
|
||||
name: Mapped[str] = mapped_column(String(128))
|
||||
status: Mapped[str] = mapped_column(String(16), default="active")
|
||||
# 创建向导选定的出厂档案(Task 6 起):重置出厂按它取对应档案组
|
||||
# (auto/jiancai 档案 / blank = jiancai 去身份组)。缺省 blank——
|
||||
# 正常路径一律经创建向导写入,缺省只是手工插行的兜底语义。
|
||||
profile: Mapped[str] = mapped_column(String(16), default="blank")
|
||||
created_at: Mapped[datetime.datetime] = mapped_column(default=_utcnow)
|
||||
|
||||
|
||||
@@ -176,6 +182,29 @@ async def ensure_platform_schema(engine: AsyncEngine) -> None:
|
||||
|
||||
# ---- 密码哈希:定义在 auth.py(见文件头 re-export)---------------------------
|
||||
|
||||
# ---- 配置版本写入(Task 6 抽公共:创建向导与配置 API 的单一版本写路径) --------
|
||||
|
||||
|
||||
async def write_config_version(
|
||||
session: AsyncSession, tenant_id: int, snapshot: dict, *,
|
||||
updated_by: str = "", comment: str | None = None) -> int:
|
||||
"""写新配置版本:MAX(version)+1,整份快照直存(spec §5.2 历史不可变,
|
||||
当前生效 = MAX)。Task 5 创建向导(版本 1)与 Task 6 配置 API(PUT 分组
|
||||
编辑/rollback 复制旧版/reset 重置出厂)的公共写入路径——两处各自
|
||||
MAX+1 会漂移,收敛为单一事实源。调用方负责 commit;返回新版本号。"""
|
||||
current = (await session.execute(
|
||||
select(func.max(TenantConfigVersion.version))
|
||||
.where(TenantConfigVersion.tenant_id == tenant_id))).scalar()
|
||||
version = (current or 0) + 1
|
||||
session.add(TenantConfigVersion(
|
||||
tenant_id=tenant_id,
|
||||
version=version,
|
||||
config_json=json.dumps(snapshot, ensure_ascii=False),
|
||||
updated_by=updated_by,
|
||||
comment=comment))
|
||||
return version
|
||||
|
||||
|
||||
# ---- 超管引导 ---------------------------------------------------------------
|
||||
|
||||
async def bootstrap_superuser(
|
||||
|
||||
Reference in New Issue
Block a user