Shared Kernel — Couche Domaine¶
Le Shared Kernel contient le code partagé entre tous les bounded contexts. La couche domaine définit les briques DDD fondamentales.
Module : src.share_kernel.domain
Entités de base¶
- class src.share_kernel.domain.base_entity.Entity[source]¶
Classe de base pour toutes les entités du domaine.
Chaque entité possède un identifiant UUID unique. L’égalité entre entités est basée sur l’identité (
id), pas sur les attributs.Exemple :
from src.share_kernel.domain import Entity import uuid class Product(Entity): def __init__(self, name: str, price: float): super().__init__(id=uuid.uuid4()) self.name = name self.price = price p1 = Product("Widget", 9.99) p2 = Product("Widget", 9.99) assert p1 != p2 # Identités différentes
Agrégats (Aggregate Root)¶
- class src.share_kernel.domain.base_aggregate.AggregateRoot(Entity)[source]¶
Étend
Entityavec la gestion des événements domaine.Les agrégats collectent les événements via
_record_event()et les exposent viapull_domain_events()pour publication par l’infrastructure.- _record_event(event: DomainEvent) → None[source]¶
Enregistre un événement domaine dans la file interne de l’agrégat.
- pull_domain_events() → list[DomainEvent][source]¶
Retourne et vide la liste des événements enregistrés. Appelée par l’infrastructure après la persistance.
Exemple :
from src.share_kernel.domain import AggregateRoot, DomainEvent from dataclasses import dataclass @dataclass(frozen=True) class OrderPlaced(DomainEvent): event_type = "order.placed" order_id: str = "" total: float = 0.0 class Order(AggregateRoot): def place(self): self._record_event(OrderPlaced( order_id=str(self.id), total=self.total, ))
Value Objects¶
- class src.share_kernel.domain.base_value_object.ValueObject[source]¶
Frozen dataclass servant de base pour tous les Value Objects. Les VO sont définis par leurs attributs, sans identité propre.
Value Objects disponibles¶
- class src.share_kernel.domain.value_objects.Address[source]¶
Adresse postale avec validation du code pays ISO 3166-1.
- Parameters:
street – Rue
city – Ville
postal_code – Code postal
country_code – Code pays ISO 3166-1 alpha-2 (ex:
"FR","CA")state_or_region – État ou région (optionnel)
from src.share_kernel.domain.value_objects import Address addr = Address( street="123 Rue Principale", city="Montréal", postal_code="H2X 1Y4", country_code="CA", state_or_region="QC", )
- class src.share_kernel.domain.value_objects.Email[source]¶
Adresse email avec normalisation automatique (minuscules, trim).
- Parameters:
value – L’adresse email
from src.share_kernel.domain.value_objects import Email email = Email(value="User@Example.COM") assert email.value == "user@example.com" assert email.domain == "example.com"
- class src.share_kernel.domain.value_objects.PhoneNumber[source]¶
Numéro de téléphone au format E.164 (
+[code pays][numéro]).- Parameters:
value – Le numéro au format E.164
from src.share_kernel.domain.value_objects import PhoneNumber phone = PhoneNumber(value="+14155551234")
Événements Domaine¶
- class src.share_kernel.domain.domain_event.DomainEvent[source]¶
Classe de base pour tous les événements domaine. Les événements sont des dataclasses gelées (frozen) et sérialisables en JSON.
- classmethod from_dict(data: dict) → DomainEvent[source]¶
Désérialise un événement depuis un dictionnaire. Utilise le registre global pour trouver la bonne classe.
- src.share_kernel.domain.domain_event.register_event(event_cls: type[DomainEvent]) → type[DomainEvent][source]¶
Décorateur de classe pour enregistrer un événement dans le registre global.
from src.share_kernel.domain.domain_event import DomainEvent, register_event from dataclasses import dataclass @register_event @dataclass(frozen=True) class InvoiceCreated(DomainEvent): event_type = "invoice.created" invoice_id: str = "" amount: float = 0.0
Exceptions¶
Exceptions DDD de base¶
- class src.share_kernel.domain.exceptions.DomainException(Exception)[source]¶
Base pour toutes les exceptions domaine.
- class src.share_kernel.domain.exceptions.EntityNotFoundException(DomainException)[source]¶
Entité non trouvée par son identifiant.
- Parameters:
entity_name – Nom de l’entité
entity_id – Identifiant recherché
- class src.share_kernel.domain.exceptions.BusinessRuleViolationException(DomainException)[source]¶
Règle métier violée.
Exceptions Multi-tenant¶
- class src.share_kernel.domain.exceptions.DjangoMultitenantError(Exception)[source]¶
Racine pour toutes les erreurs multi-tenant.
- class src.share_kernel.domain.exceptions.TenantError(DjangoMultitenantError)[source]¶
Base pour les erreurs liées aux tenants.
- class src.share_kernel.domain.exceptions.TenantNotFoundError(TenantError)[source]¶
Tenant introuvable.
- class src.share_kernel.domain.exceptions.TenantInactiveError(TenantError)[source]¶
Accès à un tenant suspendu ou archivé.
- class src.share_kernel.domain.exceptions.TenantSchemaError(TenantError)[source]¶
Erreur de provisionnement ou migration de schéma.
- class src.share_kernel.domain.exceptions.NoTenantContextError(TenantError)[source]¶
Opération nécessitant un contexte tenant, mais aucun n’est défini.
- class src.share_kernel.domain.exceptions.AuthorizationError(DjangoMultitenantError)[source]¶
Base pour les erreurs d’autorisation.
- class src.share_kernel.domain.exceptions.AccessDeniedError(AuthorizationError)[source]¶
Accès refusé par l’évaluation ABAC.
- Parameters:
reason – Raison du refus
policy_id – Identifiant de la politique (optionnel)
- class src.share_kernel.domain.exceptions.ApprovalRequiredError(AuthorizationError)[source]¶
Action nécessitant une approbation. Le PEP intercepte cette exception et retourne HTTP 202.
- Parameters:
approval_request_id – ID de la demande d’approbation créée
message – Message descriptif
Interfaces (ABC)¶
- class src.share_kernel.domain.interfaces.TenantIsolationBackend(ABC)[source]¶
Interface pour les stratégies d’isolation des tenants.
- abstractmethod activate_tenant(tenant, connection) → None[source]¶
Configure la connexion DB pour le tenant actif.
- abstractmethod deactivate_tenant(connection) → None[source]¶
Restaure la connexion DB à son état par défaut.
- class src.share_kernel.domain.interfaces.ConditionEngine(ABC)[source]¶
Interface pour les moteurs d’évaluation de conditions ABAC.
Enums et Value Objects Multi-tenant¶
- class src.share_kernel.domain.multitenant_value_objects.TenantId[source]¶
Wrapper typé autour d’un UUID de tenant.
- class src.share_kernel.domain.multitenant_value_objects.UserId[source]¶
Wrapper typé autour d’un UUID d’utilisateur.
- class src.share_kernel.domain.multitenant_value_objects.PolicyId[source]¶
Wrapper typé autour d’un UUID de politique.
- class src.share_kernel.domain.multitenant_value_objects.PolicyEffect(StrEnum)[source]¶
ALLOW: La politique autorise l’accèsDENY: La politique refuse l’accès
- class src.share_kernel.domain.multitenant_value_objects.ActionType(StrEnum)[source]¶
Actions ABAC standard mappées depuis les actions DRF :
LIST,READ,CREATE,UPDATE,DELETE,WILDCARD
- class src.share_kernel.domain.multitenant_value_objects.TenantStatus(StrEnum)[source]¶
ACTIVE: Tenant actifSUSPENDED: Tenant suspenduARCHIVED: Tenant archivé
- class src.share_kernel.domain.multitenant_value_objects.MembershipStatus(StrEnum)[source]¶
ACTIVE: Membership activeINVITED: Invitation en attenteSUSPENDED: Membership suspendue
- class src.share_kernel.domain.multitenant_value_objects.ApprovalStatus(StrEnum)[source]¶
PENDING,APPROVED,REJECTED,EXPIRED,CANCELLED,EXECUTION_FAILED
- class src.share_kernel.domain.multitenant_value_objects.PolicyScope(StrEnum)[source]¶
GLOBAL: Politique globale (tous les tenants)TENANT: Politique spécifique au tenant
- class src.share_kernel.domain.multitenant_value_objects.IsolationBackendType(StrEnum)[source]¶
SCHEMA,RLS,SHARED_FK
- src.share_kernel.domain.multitenant_value_objects.DRF_ACTION_MAPPING¶
Mapping des actions DRF vers les actions ABAC :
{ "list": "list", "retrieve": "read", "create": "create", "update": "update", "partial_update": "update", "destroy": "delete", }