Shared Kernel — Couche Infrastructure

La couche infrastructure fournit les implémentations concrètes des interfaces domaine : modèles Django, repositories, bus d’événements, et utilitaires partagés.

Module : src.share_kernel.infrastructure

Modèles abstraits Django

class src.share_kernel.infrastructure.django_base_model.IdentifierModel(models.Model)

Modèle abstrait avec clé primaire UUID.

id: UUIDField

Clé primaire UUID4, générée automatiquement.

class src.share_kernel.infrastructure.django_base_model.TimeStampedModel(models.Model)

Modèle abstrait avec horodatage de création et modification.

created_at: DateTimeField

Date de création (auto_now_add).

updated_at: DateTimeField

Date de dernière modification (auto_now).

class src.share_kernel.infrastructure.django_base_model.AuditModel(models.Model)

Modèle abstrait avec traçabilité de création et modification.

created_by: ForeignKey

Utilisateur ayant créé l’enregistrement.

updated_by: ForeignKey

Utilisateur ayant effectué la dernière modification.

class src.share_kernel.infrastructure.django_base_model.SoftDeleteModel(models.Model)

Modèle abstrait avec suppression logique (soft delete).

is_deleted: BooleanField
deleted_at: DateTimeField
deleted_by: ForeignKey
class src.share_kernel.infrastructure.django_base_model.BaseModel(IdentifierModel, TimeStampedModel)

Combine UUID + horodatage. Base recommandée pour les modèles simples.

class src.share_kernel.infrastructure.django_base_model.ERPBaseModel(IdentifierModel, TimeStampedModel, AuditModel)

Combine UUID + horodatage + audit. Base recommandée pour les modèles ERP.

Exemple d’utilisation :

from src.share_kernel.infrastructure import BaseModel

class Product(BaseModel):
    name = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=10, decimal_places=2)

    class Meta:
        db_table = "products"

Managers avec Soft Delete

class src.share_kernel.infrastructure.managers.SoftDeleteQuerySet(QuerySet)

QuerySet qui supporte la suppression logique.

alive() QuerySet

Retourne uniquement les enregistrements non supprimés.

deleted() QuerySet

Retourne uniquement les enregistrements supprimés.

soft_delete() int

Marque les enregistrements comme supprimés (is_deleted=True).

restore() int

Restaure les enregistrements supprimés.

class src.share_kernel.infrastructure.managers.SoftDeleteManager(Manager)

Manager qui filtre automatiquement les enregistrements supprimés.

get_queryset() SoftDeleteQuerySet

Retourne uniquement les enregistrements vivants.

all_with_deleted() SoftDeleteQuerySet

Retourne tous les enregistrements, y compris les supprimés.

Repository Django

class src.share_kernel.infrastructure.base_django_repo.DjangoRepository[TAggregate, TModel][source]

Implémentation générique du pattern Repository utilisant Django ORM.

get_by_id(entity_id: UUID) TAggregate | None[source]

Récupère un agrégat par son ID. Retourne None si non trouvé.

get_by_id_or_raise(entity_id: UUID) TAggregate[source]

Récupère un agrégat ou lève EntityNotFoundException.

save(aggregate: TAggregate) TAggregate[source]

Persiste un agrégat (création ou mise à jour).

delete(aggregate: TAggregate) None[source]

Supprime un agrégat.

Méthodes abstraites à implémenter :

abstractmethod _to_aggregate(model: TModel) TAggregate[source]

Convertit un modèle Django en agrégat domaine.

abstractmethod _to_model(aggregate: TAggregate) TModel[source]

Convertit un agrégat domaine en modèle Django.

Exemple :

class ProductRepository(DjangoRepository[ProductAggregate, ProductModel]):
    model_class = ProductModel

    def _to_aggregate(self, model):
        return ProductAggregate(id=model.id, name=model.name, price=model.price)

    def _to_model(self, aggregate):
        return ProductModel(id=aggregate.id, name=aggregate.name, price=aggregate.price)

Event Dispatcher

class src.share_kernel.infrastructure.event_dispatcher.EventDispatcher

Extrait les événements d’un agrégat et les publie sur le bus d’événements.

dispatch(aggregate: AggregateRoot) None

Appelle aggregate.pull_domain_events() et publie chaque événement sur le bus d’événements global.

Exemple :

from src.share_kernel.infrastructure import EventDispatcher

dispatcher = EventDispatcher()
tenant_repo.save(tenant_aggregate)
dispatcher.dispatch(tenant_aggregate)  # Publie TenantCreated

Données de référence (Master Data)

Tous les modèles de référence héritent de TranslatableSharedModel et utilisent TranslatedFields pour les champs textuels. Les traductions sont stockées dans des tables *Translation distinctes.

Voir Internationalisation (django-parler) pour le guide complet.

class src.share_kernel.infrastructure.reference_data.Currency(TranslatableSharedModel, ERPBaseModel)

Devises ISO 4217.

Champs:

code, symbol, decimal_places, is_active

Champs traduits:

name

Table:

ref_currencies / ref_currencies_translation

class src.share_kernel.infrastructure.reference_data.Country(TranslatableSharedModel, ERPBaseModel)

Pays ISO 3166-1.

Champs:

code (alpha-2), code_alpha3 (alpha-3), currency (FK), is_active

Champs traduits:

name

Table:

ref_countries / ref_countries_translation

class src.share_kernel.infrastructure.reference_data.Department(TranslatableSharedModel, ERPBaseModel)

Départements organisationnels hiérarchiques.

Champs:

code, parent (self FK), manager (User FK), is_active

Champs traduits:

name

Table:

ref_departments / ref_departments_translation

get_ancestors() list[Department]

Retourne la liste des départements parents (du plus proche au plus éloigné).

class src.share_kernel.infrastructure.reference_data.UnitOfMeasureCategory(TranslatableSharedModel, ERPBaseModel)

Catégories d’unités de mesure.

Champs traduits:

name

Table:

ref_uom_categories / ref_uom_categories_translation

class src.share_kernel.infrastructure.reference_data.UnitOfMeasure(TranslatableSharedModel, ERPBaseModel)

Unités de mesure avec conversion.

Champs:

category (FK), symbol (unique), ratio, is_reference, rounding, is_active

Champs traduits:

name

Table:

ref_units_of_measure / ref_units_of_measure_translation

Utilitaires partagés

src.share_kernel.infrastructure.utils.generate_uuid() uuid.UUID

Génère un nouveau UUID4.

src.share_kernel.infrastructure.utils.validate_schema_name(name: str, regex: str = '^[a-z][a-z0-9_]{2,62}$') bool

Valide un nom de schéma PostgreSQL contre une regex configurable.

src.share_kernel.infrastructure.utils.is_reserved_schema_name(name: str, reserved: list[str] | None = None) bool

Vérifie si un nom de schéma est réservé (public, pg_catalog, etc.).