Use core-owned scope storage

This commit is contained in:
2026-07-10 17:33:43 +02:00
parent 2bc57fefe3
commit 7e8df56723
4 changed files with 17 additions and 44 deletions

View File

@@ -1,9 +1,11 @@
# GovOPlaN Tenancy
`govoplan-tenancy` owns the live `tenancy_tenants` table, tenant lifecycle, and
tenant settings API route contributions during the GovOPlaN module split.
`govoplan-tenancy` owns tenant lifecycle, tenant administration API route
contributions, and the `tenancy.tenantResolver` capability during the GovOPlaN
module split.
`govoplan-access` depends on this module, and core's registry inserts tenancy
before access for authenticated platform composition. Core migrations rename the
historical `tenants` table to the module-prefixed table name for existing
development databases.
`govoplan-access` no longer hard-depends on this module. Access can run in the
single-scope compatibility mode used by the core/access baseline; installing
tenancy adds explicit tenant management and resolver behavior. The shared scope
storage table is core-owned as `core_scopes`; tenancy provides lifecycle and
administration behavior over those rows rather than owning the table.

View File

@@ -6,7 +6,7 @@ from sqlalchemy.orm import Session
from govoplan_core.admin.common import AdminValidationError, slugify
from govoplan_core.admin.settings import get_system_settings
from govoplan_access.auth import ApiPrincipal, get_api_principal, has_scope, require_scope
from govoplan_core.auth import ApiPrincipal, get_api_principal, has_scope, require_scope
from govoplan_core.audit.logging import audit_event
from govoplan_core.core.access import CAPABILITY_ACCESS_TENANT_PROVISIONER, TenantAccessProvisioner
from govoplan_core.core.change_sequence import ChangeSequenceEntry, decode_sequence_watermark, encode_sequence_watermark, record_change, sequence_watermark_is_expired

View File

@@ -1,33 +1,6 @@
from __future__ import annotations
import uuid
from typing import Any
from sqlalchemy import Boolean, JSON, String, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from govoplan_core.db.base import Base, TimestampMixin
def new_uuid() -> str:
return str(uuid.uuid4())
class Tenant(Base, TimestampMixin):
__tablename__ = "tenancy_tenants"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
slug: Mapped[str] = mapped_column(String(100), unique=True, nullable=False, index=True)
name: Mapped[str] = mapped_column(String(255), nullable=False)
description: Mapped[str | None] = mapped_column(Text)
default_locale: Mapped[str] = mapped_column(String(20), default="en", nullable=False)
settings: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict, nullable=False)
allow_custom_groups: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
allow_custom_roles: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
allow_api_keys: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
users: Mapped[list["User"]] = relationship("User", back_populates="tenant", cascade="all, delete-orphan")
from govoplan_core.tenancy.scope import Tenant, new_uuid
__all__ = ["Tenant", "new_uuid"]

View File

@@ -1,10 +1,11 @@
from __future__ import annotations
from govoplan_core.core.access import CAPABILITY_TENANCY_TENANT_RESOLVER
from govoplan_core.core.module_guards import persistent_table_uninstall_guard
from govoplan_core.core.modules import MigrationSpec, ModuleContext, ModuleManifest
from govoplan_core.db.base import Base
from govoplan_tenancy.backend.db import models as tenancy_models # noqa: F401 - populate Tenancy ORM metadata
from govoplan_core.core.access import (
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
CAPABILITY_TENANCY_TENANT_RESOLVER,
)
from govoplan_core.core.modules import ModuleContext, ModuleManifest
def _tenant_resolver(context: ModuleContext):
@@ -25,11 +26,8 @@ manifest = ModuleManifest(
id="tenancy",
name="Tenancy",
version="0.1.6",
required_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR),
route_factory=_route_factory,
migration_spec=MigrationSpec(module_id="tenancy", metadata=Base.metadata),
uninstall_guard_providers=(
persistent_table_uninstall_guard(tenancy_models.Tenant, label="Tenancy"),
),
capability_factories={
CAPABILITY_TENANCY_TENANT_RESOLVER: _tenant_resolver,
},