Coverage for src / lexigram / contracts / tenancy / types.py: 0%
27 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
1"""Tenancy value types."""
3from __future__ import annotations
5from dataclasses import dataclass, field
6from datetime import datetime
7from enum import Enum
8from typing import Any
11class TenantStatus(str, Enum):
12 """Lifecycle status of a tenant.
14 Attributes:
15 ACTIVE: Tenant is fully operational and accepts requests.
16 INACTIVE: Tenant has been deactivated and no longer accepts requests.
17 SUSPENDED: Tenant has been suspended (e.g. for non-payment) and is
18 temporarily blocked from accessing the system.
19 PROVISIONING: Tenant is being created; isolation resources are being
20 set up.
21 """
23 ACTIVE = "active"
24 INACTIVE = "inactive"
25 SUSPENDED = "suspended"
26 PROVISIONING = "provisioning"
29@dataclass(frozen=True)
30class TenantInfo:
31 """Core tenant identity record.
33 The ``config`` field here is the tenant's *static* provisioning config
34 (plan limits, feature flags set at creation time). Runtime per-tenant
35 overrides are managed separately by ``TenantConfigProviderProtocol`` /
36 ``TenantConfigService``. The two are independent — ``TenantInfo.config``
37 is a snapshot stored alongside the tenant record; ``TenantConfigService``
38 is a live, cached, key-value overlay.
40 Attributes:
41 tenant_id: Unique identifier for the tenant.
42 slug: URL-safe, human-readable identifier (e.g. ``acme-corp``).
43 name: Display name of the tenant.
44 status: Current lifecycle status.
45 plan: Subscription plan name (optional).
46 config: Static provisioning configuration snapshot.
47 metadata: Arbitrary application-defined metadata.
48 created_at: Timestamp when the tenant was created.
49 """
51 tenant_id: str
52 slug: str
53 name: str
54 status: TenantStatus
55 plan: str | None = None
56 config: dict[str, Any] = field(default_factory=dict)
57 metadata: dict[str, Any] = field(default_factory=dict)
58 created_at: datetime | None = None
61@dataclass(frozen=True)
62class TenantResolutionContext:
63 """Immutable snapshot of request data available for tenant resolution.
65 Passed to every :class:`~lexigram.contracts.tenancy.protocols.TenantResolverProtocol`
66 during the resolution chain so resolvers can inspect request metadata
67 without depending on any web framework type.
69 Attributes:
70 headers: HTTP request headers (lowercased keys).
71 host: The ``Host`` header value (e.g. ``acme.app.com``).
72 path: The request path (e.g. ``/api/tenants/acme/users``).
73 claims: Decoded JWT claims from the current authentication context.
74 """
76 headers: dict[str, str]
77 host: str | None = None
78 path: str | None = None
79 claims: dict[str, Any] = field(default_factory=dict)
82__all__ = [
83 "TenantInfo",
84 "TenantResolutionContext",
85 "TenantStatus",
86]