Skip to main content

koprogo_api/application/ports/
module_registry.rs

1//! Port (trait) du registre de modules — Story 5.1 (#585), ADR-0015.
2//!
3//! Hexagonal : le trait vit côté application, l'implémentation PostgreSQL
4//! dans `infrastructure/database/repositories/module_registry_impl.rs`.
5//!
6//! Toutes les méthodes retournent `Result<_, AppError>` (CRITICAL.md §4).
7
8use crate::application::error::AppError;
9use crate::domain::entities::Module;
10use async_trait::async_trait;
11use uuid::Uuid;
12
13#[async_trait]
14pub trait ModuleRegistry: Send + Sync {
15    /// Les modules actifs (`archived_at IS NULL`) d'une ACP.
16    ///
17    /// Une ACP inconnue rend une liste vide, pas une erreur : la garde de
18    /// portée s'exécute **avant** et c'est elle qui décide si l'appelant a
19    /// le droit de savoir que l'ACP n'existe pas.
20    async fn list_enabled(&self, acp_id: Uuid) -> Result<Vec<Module>, AppError>;
21
22    /// Allume un module. Idempotent : rallumer un module déjà actif remet
23    /// simplement `archived_at` à `NULL` et ne duplique pas la ligne — c'est
24    /// ce qui permet le cycle activer/désactiver/réactiver d'INV-27 sans
25    /// perdre les données.
26    async fn enable(&self, acp_id: Uuid, module: Module) -> Result<(), AppError>;
27
28    /// Éteint un module. Idempotent également. **Ne supprime rien** : pose
29    /// `archived_at`. Le refus d'éteindre `identity` est une règle métier et
30    /// vit dans le use-case, pas ici.
31    async fn disable(&self, acp_id: Uuid, module: Module) -> Result<(), AppError>;
32
33    /// Chemin chaud : appelé par `ModuleGuard` à chaque requête gardée.
34    async fn is_enabled(&self, acp_id: Uuid, module: Module) -> Result<bool, AppError>;
35}