""" app/tenancy/context.py ---------------------- Lightweight, detached descriptor for the resolved tenant. Populated by the resolver while a control-plane session is open, then carried on `g.tenant` for the lifetime of the request. Holds no live ORM object — safe to use after the control session closes. MT-5: plan feature flags and quota limits are included so quota.py and gates.py can read them from g.tenant without a second control-DB round-trip. """ from dataclasses import dataclass from typing import Optional @dataclass(frozen=True) class TenantContext: id: int slug: str name: str plan_id: int db_uri: str # MT-5: plan fields (None = unlimited / not loaded) plan_code: Optional[str] = None # Quota limits (None = unlimited) max_users: Optional[int] = None max_facilities: Optional[int] = None max_inspections_month: Optional[int] = None max_issues_month: Optional[int] = None # Feature gates allow_mobile_api: bool = True allow_scheduled_reports: bool = True allow_branding: bool = True allow_custom_domain: bool = True