"""租户与站点配置模型。 - TenantConfig.data = deep_merge(DEFAULT_CONFIG, snapshot):租户快照 ⊕ 出厂默认 - Site.brand 的合并基线是**租户级** data["brand"](而非出厂默认), 这样租户级 brand 自定义也能被各站点继承。 """ from dataclasses import dataclass from app.platform.defaults import DEFAULT_CONFIG, deep_merge @dataclass(frozen=True) class Site: slug: str name: str domains: tuple[str, ...] brand: dict # 站点门面覆盖层 ⊕ 租户默认 brand(已深合并) @dataclass(frozen=True) class TenantConfig: slug: str name: str status: str # active | disabled data: dict # deep_merge(DEFAULT_CONFIG, snapshot) sites: tuple[Site, ...] = () @classmethod def from_snapshot(cls, slug, name, snapshot, sites=(), status="active"): merged = deep_merge(DEFAULT_CONFIG, snapshot) resolved = tuple( Site(s["slug"], s.get("name", s["slug"]), tuple(s.get("domains", ())), deep_merge(merged["brand"], s.get("brand", {}))) for s in sites) return cls(slug=slug, name=name, status=status, data=merged, sites=resolved)