Skip to content

MVCS to hexagonal#20

Merged
raynaldlao merged 81 commits intomasterfrom
mvcs-to-hexagonal
Apr 23, 2026
Merged

MVCS to hexagonal#20
raynaldlao merged 81 commits intomasterfrom
mvcs-to-hexagonal

Conversation

@raynaldlao
Copy link
Copy Markdown
Owner

@raynaldlao raynaldlao commented Apr 17, 2026

Pull Request : Refactoring Architectural - Passage de MVCS à l'Hexagonal

Objectif

Cette PR a pour but de remplacer l'architecture traditionnelle MVCS (Model-View-Controller-Service) par une Architecture Hexagonale. L'objectif est de découpler totalement la logique métier des frameworks techniques (Flask, SQLAlchemy) pour garantir la maintenabilité, la testabilité et l'évolutivité du blog.

Changements Majeurs

1. Isolation du Cœur Métier (src/application)

  • Domaine Pur : Les entités (Article, Comment, Account) ne dépendent plus d'aucun framework (suppression des dépendances à SQLAlchemy dans le domaine).
  • Ports (Interfaces) : Définition de contrats clairs pour les entrées (input_ports) et les sorties (output_ports).
  • Services : Orchestration de la logique métier sans connaissance des détails d'implémentation technique.

2. Infrastructure et Adaptateurs (src/infrastructure)

  • Adaptateurs d'Entrée (Flask) : Les contrôleurs sont devenus des adaptateurs qui traduisent les requêtes Web en appels vers les ports applicatifs.
  • Adaptateurs de Sortie (SQLAlchemy) : La persistence est isolée dans des adaptateurs spécifiques. Le passage entre la base de données et le Domaine se fait via des DTOs de record.

3. Rôle des DTOs (Data Transfer Objects)

L'utilisation de DTOs spécifiques à chaque frontière de l'hexagone permet d'isoler totalement le Domaine des contraintes techniques :

  • Request DTOs (ex: ArticleRequest) : Capturent et valident les données brutes (Flask form) via Pydantic avant qu'elles ne pénètrent dans le cœur applicatif. Ils garantissent que les services manipulent des données saines.
  • Response DTOs (ex: ArticleResponse) : Préparent les données du Domaine pour les templates HTML. Ils servent de filtres pour ne pas exposer d'attributs sensibles et protéger le Domaine d'une fuite vers la vue.
  • Record DTOs (ex: ArticleRecord) : Assurent la conversion entre les modèles ORM (SQLAlchemy) et les entités du Domaine. Ils gèrent les transformations techniques (dates, types) à la lisière de la persistence.

4. Stratégie de Test Multi-Niveaux

La validation de cette refonte repose sur une organisation rigoureuse des tests, segmentée par dossier :

  • Tests d'Architecture (test_architecture.py) : Utilisation de pytestarch pour garantir le respect des règles de dépendance (ex: interdiction absolue pour application d'importer infrastructure).
  • Tests de Services (tests_services/) : Validation de la logique métier pure (permissions, orchestration) en isolant les dépôts via des Mocks.
  • Tests d'Infrastructure (tests_infrastructure/) :
    • Adaptateurs de Sortie (tests_output_adapters/) : Validation des mappings DTO et de la persistence réelle (via tests_sqlalchemy/) sur une base de données de test dédiée.
    • Adaptateurs d'Entrée (tests_input_adapters/) : Vérification des interactions Flask et de la validation des entrées (dto/).
  • Tests d'Intégration (tests_integration/) : Scénarios "bout-en-bout" validant les parcours utilisateurs réels (sécurité, workflows, sessions) dans un environnement complet.

…eve business logic with service‑level tests
…g author existence and role‑based access and rename listing to get_all_ordered_by_date_desc

I introduced a "fake_author" object to clarify the intent of the article creation tests. "test_create_article_success()" needs an existing account with a valid role to reflect the real security rules applied during article creation. "test_create_article_unauthorized_role()" requires an account with an invalid role to verify that access is correctly denied. Unlike the other tests, there is no need to create a fake_author here, because the focus is on article‑related issues rather than on elements that require using an account.
…e‑based authorization and added the update_article action along with focused tests for both success and failure cases
…nt.account_id` and `fake_article.article_id` instead of hardcoded values
…or/admin authorization, added the delete entry point, reordered permission checks in update_article and added targeted tests for allowed and forbidden deletions
…nt retrieval to the application layer with default parameters and supporting unit tests
…ing descriptive string messages across services, including splitting previously chained `if` conditions using `or` into clearer, separate checks
…y defining the repository port, implementing the service method and adding tests for both success and failure paths
…tion layer by dropping the “Management” suffix from service classes, updating all related files and tests to align with the cleaner and more consistent `Service` naming convention
…ure by adding the repository lookup method, introducing `create_reply` with a simplified threading model and refining both the threading logic and unit tests for clarity and consistency
…ith optimized O(n) threaded tree build using defaultdict, add get_all_by_article_id to the output port, apply attrgetter-based sorting and include core unit tests
…l for comment deletion to prevent unauthorized removals. The service applies a fail‑fast validation flow to ensure data integrity and clear authorization boundaries
…th a dedicated AccountRole Enum to improve type safety and consistency across domain services. This refactor updates service logic and aligns all unit tests with the new role model
…into five action‑focused classes and introduced a shared base class to handle common setup, reducing duplication and keeping the suite clean and readable
…into four action‑focused classes and introduced a shared base class to handle common setup for the service and its mocks
…st suites by introducing action‑focused classes and shared test bases to remove duplicated setup, while replacing hardcoded strings with entity properties for consistency
…tory mocks in setup_method to enforce accurate interface usage and ensure tests fail when calling undefined methods
…and reformatted the test suite with multi‑line imports and calls, while also removing an unused datetime import and cleaning trailing whitespace
…e.update_article to ensure changes are written to the repository, updated the corresponding test to assert a single save() invocation with the modified article
…xtracting them from the service test suite, as they are not specific to the `tests_services` layer and should be treated as shared test utilities
…cy to support the upcoming introduction of DTOs in the infrastructure layer as part of the hexagonal architecture migration
…rastructure for account management, including configuration handling, SQLAlchemy setup, ORM registry and account model, the SQLAlchemy-based AccountRepository adapter and a Pydantic DTO for safe data transfer to the Domain. It also adds unit tests for the DTO and full integration tests for the SQLAlchemy account adapter
…ctured to reflect the hexagonal architecture
…comment handling with an ORM model, a DTO for domain mapping, a repository adapter, along with integration tests and DTO tests
…oving account, article and comment insertion helpers into `SqlAlchemyTestBase`. This reduces duplication across adapter tests, removes redundant model imports in each test file
…uest and RegistrationRequest to validate required credentials, email formatting and password‑confirmation rules, ensuring all boundary validation is fully enforced at the application edge
…in a session‑scoped fixture, updates SqlAlchemyTestBase to an autouse db_context fixture, enables commit‑based inspection with per‑test TRUNCATE cleanup and wraps the truncate helper as a private static method for clarity
…dency‑injection wiring, registers Flask routes manually, implements the CommentAdapter (create/reply/delete), updates ArticleService to load threaded comments, integrates comments into article_detail.html and updates all related tests
…missing session_service, completes AccountSessionService wiring with FlaskSessionAdapter and required repositories, resolves BuildError by renaming registration endpoints to match templates and updates blog_comment_application.py to ensure all core services are properly wired
…t, simplifies all templates, fixes static asset loading via explicit static_folder, adjusts header spacing and updates tests to match registration endpoints and mock routes
…, switches article deletion to POST, centralizes flash messages, activates the profile page with minimalist styling, adjusts global spacing, adds user context to article_detail and updates tests with proper routes and ID‑sync checks
…ord fields and fixes invalid form nesting in registration.html. Adds a test for Pydantic email validation. Implements role‑based UI rules to hide article creation for USER role and adds tests to block unauthorized GET/POST access
…omain purity, core isolation, forbidden framework imports, correct dependency‑inversion layering, port‑only infra dependencies and service‑independent ports. Ensures package discovery with required __init__.py files
…remove N+1 queries, introduces ArticleDetailView and CommentThreadView as domain Read Models, delegates threaded comment mapping to CommentResponse, adds tests for missing‑author fallbacks and sorting and refactors the test suite with unpacking. Updates services to use get_by_ids and return Read Models with consolidated sorting rules
…c modules, restructures them with class-based hierarchies, stabilizes DB resets with atomic TRUNCATE and lock timeouts, unifies truncation logic in db_utils.py, strengthens concurrency tests with full response checks, enforces architectural rules via pytestarch and cleans formatting for a production‑grade suite
… article and comment adapters, enforces non‑empty LoginRequest fields via Pydantic min_length, standardizes the "Validation Error" flash prefix and fixes _register_dummy_route to support parameterized routes
…pace, replaces a lambda with a proper function in CommentService, removes a debug print, renames unused loop variables to `_` in tests and delete an useless comment
…c into dedicated functions, reorganizes the file for bottom‑to‑top readability, introduces semantic naming for the Web Facade (Flask), adds full docstrings and standardizes variable naming across bootstrap code
…rchies for Application and Infrastructure layers, update the global user identification mechanism in the infrastructure layer and centralizes testing exceptions
…r articles, accounts, comments and account sessions to decouple unit tests from Flask. Adds comprehensive unit tests covering all in‑memory adapters
…for improved reliability, removes nested functions and classes to reduce memory allocation, standardizes type hints, harmonizes documentation and removes an unnecessary comment
…roper typing by using Pydantic model_validate for DTO tests, updating domain entities to accept datetime | None, using Any for pytest‑arch graph access, importing the correct Response type, adding type‑safety assertions, introducing a datetime fallback for in‑memory sorting and casting evaluable to Any for private _graph access
…un only the tests in the `tests_hexagonal/` directory
@raynaldlao raynaldlao self-assigned this Apr 17, 2026
…es and static directories regardless of the current working directory by computing their absolute paths relative to the bootstrap script
@hlargitte hlargitte self-requested a review April 21, 2026 18:58
Copy link
Copy Markdown
Owner

@hlargitte hlargitte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

…e article detail view, centralizes comment threading into a shared utility, decouples ArticleService from CommentService through direct repository access and improves readability with a named sorting helper for comments
…nce, strengthens security with stricter cookie settings and validation, prevents sensitive data leakage, ensures UTF‑8/emoji integrity, refactors the session architecture and adds handling for DB timeouts and user desynchronization
…Key Rotation to validate disaster‑recovery behavior
…e, removes redundant uppercase and property‑name comparisons and aligns infrastructure and presentation layers with domain constraints
@raynaldlao raynaldlao merged commit d4e1e1d into master Apr 23, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants