============================ Tenant — Services Domaine ============================ Les services domaine du Tenant Context encapsulent la logique métier qui ne relève pas d'un seul agrégat. Module : ``src.module.tenant.domain.services`` .. module:: src.module.tenant.domain.services :synopsis: Services domaine pour la gestion des tenants provision_tenant ================ .. function:: provision_tenant(tenant, isolation_backend, event_publisher) -> None Provisionne le stockage d'un nouveau tenant et émet l'événement de création. 1. Appelle ``isolation_backend.create_tenant_storage(tenant)`` 2. Publie ``TenantCreated`` :param tenant: Instance du modèle Tenant :param isolation_backend: Backend d'isolation (schema, RLS, shared_fk) :param event_publisher: Callable pour publier les événements .. code-block:: python from src.module.tenant.domain.services import provision_tenant from src.share_kernel.infrastructure.isolation import get_isolation_backend from src.share_kernel.infrastructure.event_bus import publish_event provision_tenant( tenant=my_tenant, isolation_backend=get_isolation_backend(), event_publisher=publish_event, ) resolve_tenant_from_identifier ================================ .. function:: resolve_tenant_from_identifier(identifier, tenant_queryset) -> Tenant Résout un tenant depuis un UUID ou un slug. Valide que le tenant est actif. :param identifier: UUID string ou slug :param tenant_queryset: QuerySet pour la recherche :returns: Instance Tenant :raises TenantNotFoundError: Si le tenant n'existe pas :raises TenantInactiveError: Si le tenant est suspendu ou archivé **Ordre de résolution :** 1. Tente de parser comme UUID 2. Si échec, cherche par slug .. code-block:: python from src.module.tenant.domain.services import resolve_tenant_from_identifier from src.module.tenant.models import Tenant tenant = resolve_tenant_from_identifier("acme-corp", Tenant.objects.all()) tenant = resolve_tenant_from_identifier("550e8400-...", Tenant.objects.all()) validate_membership ==================== .. function:: validate_membership(user_id, tenant_id, membership_queryset) -> TenantMembership Vérifie qu'un utilisateur a une membership active dans un tenant. :param user_id: UUID de l'utilisateur :param tenant_id: UUID du tenant :param membership_queryset: QuerySet pour la recherche :returns: Instance TenantMembership :raises MembershipNotFoundError: Si pas de membership active Événements domaine ================== Module : ``src.module.tenant.domain.events`` .. module:: src.module.tenant.domain.events :synopsis: Événements domaine du Tenant Context Tous les événements héritent de ``DomainEvent`` et sont enregistrés avec ``@register_event``. .. class:: TenantCreated(DomainEvent) Émis lors de la création d'un tenant. :Champs: ``tenant_slug``, ``schema_name`` :event_type: ``"tenant.created"`` .. class:: TenantSuspended(DomainEvent) Émis lors de la suspension d'un tenant. :Champs: ``tenant_slug`` :event_type: ``"tenant.suspended"`` .. class:: TenantActivated(DomainEvent) Émis lors de la réactivation d'un tenant. :Champs: ``tenant_slug`` :event_type: ``"tenant.activated"`` .. class:: TenantArchived(DomainEvent) Émis lors de l'archivage d'un tenant. :Champs: ``tenant_slug`` :event_type: ``"tenant.archived"`` .. class:: MemberAdded(DomainEvent) Émis lors de l'ajout d'un membre au tenant. :Champs: ``user_id``, ``roles`` :event_type: ``"tenant.member_added"`` .. class:: MemberRemoved(DomainEvent) Émis lors de la suppression d'un membre. :Champs: ``user_id`` :event_type: ``"tenant.member_removed"`` .. class:: MemberRolesUpdated(DomainEvent) Émis lors de la mise à jour des rôles d'un membre. :Champs: ``user_id``, ``membership_id``, ``old_roles``, ``new_roles`` :event_type: ``"tenant.member_roles_updated"`` .. class:: InvitationSent(DomainEvent) Émis lors de l'envoi d'une invitation. :Champs: ``email``, ``invited_by_id`` :event_type: ``"tenant.invitation_sent"`` .. class:: InvitationAccepted(DomainEvent) Émis lors de l'acceptation d'une invitation. :Champs: ``email``, ``user_id`` :event_type: ``"tenant.invitation_accepted"`` Value Objects ============= Module : ``src.module.tenant.domain.value_objects`` .. module:: src.module.tenant.domain.value_objects :synopsis: Value Objects du Tenant Context .. class:: TenantContext Snapshot immuable du contexte tenant courant. :Champs: ``tenant_id``, ``tenant_slug``, ``schema_name``, ``status`` .. class:: MembershipInfo Snapshot immuable des informations de membership. :Champs: ``membership_id``, ``user_id``, ``tenant_id``, ``roles``, ``abac_attributes``, ``status``