Layered Architecture Principles
Relevant source files
The following files were used as context for generating this wiki page:
Layered architecture in the CodeBot project is designed to enforce a clear separation of concerns between user interface interactions, business logic orchestration, domain rules, and infrastructure implementation. This structural approach ensures that the system is maintainable, testable, and scalable by preventing tight coupling between high-level policy and low-level detail.
The project transition, particularly for the WebApp and Telegram Bot components, emphasizes moving away from "God Objects" and direct database access within controllers toward a structured flow using Services, Facades, and DTOs (Data Transfer Objects).
Sources: PROMPTS_WEBAPP_LAYERING.md:16-43, GUIDES/ARCHITECTURE_ANALYSIS_PART1.md:12-25
Core Architectural Layers
The architecture is divided into four primary logical layers, each with specific responsibilities and allowed dependencies.
1. Presentation Layer (Web/Bot)
This layer acts as the entry point for external requests, whether through HTTP routes in the WebApp or Command Handlers in the Telegram Bot. Its primary role is to receive input, perform basic request validation, and delegate execution to the Application layer.
- Components: Flask routes, Telegram command handlers, Request/Response schemas (Pydantic), and View Models.
- Constraint: Must not contain business logic or direct database queries.
Sources: PROMPTS_WEBAPP_LAYERING.md:73-74, GUIDES/ARCHITECTURE_ANALYSIS_PART1.md:88-100
2. Application Layer (Services)
The Application layer orchestrates use cases. it acts as a mediator that uses Domain services and Infrastructure repositories to fulfill a specific user goal.
- Components:
SnippetService, DTOs, and Use-case orchestrators. - Logic: Handles flow control, but delegates specific business rules to the Domain layer.
Sources: PROMPTS_WEBAPP_LAYERING.md:75-76, GUIDES/ARCHITECTURE_ANALYSIS_PART1.md:144-155
3. Domain Layer
The Domain layer is the "Pure" core of the system. it contains the business logic, entities, and invariant rules that are independent of any external framework or database.
- Components:
LanguageDetector,CodeNormalizer, and Entities likeSnippet. - Constraint: Must have zero dependencies on infrastructure or web frameworks.
Sources: PROMPTS_WEBAPP_LAYERING.md:77-78, refactoring_engine.py:228-251
4. Infrastructure Layer
This layer handles technical details such as data persistence, external API integrations, and cross-cutting concerns.
- Components:
FilesFacade,SnippetRepository(MongoDB), and external service wrappers (GitHub, Drive). - Pattern: Implements the Repository Pattern to abstract the data source from the rest of the application.
Sources: PROMPTS_WEBAPP_LAYERING.md:79-80, GUIDES/ARCHITECTURE_ANALYSIS_PART1.md:159-178
Architectural Flow and Data Interaction
The following diagram illustrates the standard data flow from a user request through the various layers to the persistence medium and back.
The diagram above shows the unidirectional flow of dependencies where higher layers depend on lower layers, with pure logic residing in the Domain core.
Sources: PROMPTS_WEBAPP_LAYERING.md:71-84, GUIDES/ARCHITECTURE.md:18-35
Technical Comparison: Legacy vs. Layered Approach
The refactoring plan highlights specific "code smells" and their architectural resolutions.
Pattern Shift Table
| Aspect | Legacy Approach (Anti-Pattern) | Layered Architecture Principle |
|---|---|---|
| Data Access | Direct get_db() calls in routes | Usage of FilesFacade or Repositories |
| Input Handling | Manual validation in handlers | Pydantic Schemas / DTOs |
| Logic Location | Fat Controllers (Business logic in routes) | Pure Domain Services (CodeNormalizer) |
| Global State | God Objects in utils.py | Specific infrastructure/shared modules |
Sources: PROMPTS_WEBAPP_LAYERING.md:52-67, GUIDES/ARCHITECTURE_ANALYSIS_PART1.md:184-210
Implementation Example: Snippet Saving
When saving a code snippet, the responsibilities are distributed to ensure that the route only handles the interface, while the domain handles the "what" and the infrastructure handles the "how".
Sequence illustrating the separation between code normalization (Domain) and the saving operation (Infrastructure).
Sources: GUIDES/ARCHITECTURE_ANALYSIS_PART1.md:213-248, GUIDES/ARCHITECTURE.md:162-178
Refactoring and Decomposition Strategy
To achieve this architecture in a monolithic codebase (like the previous main.py containing 2,322 lines), a phased decomposition is required.
Phase 1: Modular Extraction
The refactoring_engine.py is used to automate the split of monolithic files into domain-specific modules. This process groups related functions by:
- Section Identification: Mapping code comments (e.g.,
# 1) USER MANAGEMENT) to functional slugs. - Affinity Grouping: Grouping functions that call each other or share naming prefixes.
- Cyclic Dependency Resolution: Introducing shared layers to break import loops between newly created modules.
Sources: refactoring_engine.py:257-289, code_review_2025_10/REFACTORING_PLAN.md:25-45
Phase 2: Domain Collocation
Rather than generic "Service" or "Model" files, the project prioritizes Collocation. This involves placing entities and the functions that operate on them within the same domain module (e.g., users.py containing both the User class and user-related logic).
Sources: refactoring_engine.py:1003-1045, PROMPTS_WEBAPP_LAYERING.md:88-95
Golden Rules for Layer Boundaries
To maintain the integrity of the architecture, developers must adhere to the following rules:
- No DB in Routes: Routes must never import
dborMongoClient. They interact only withget_files_facade()orget_snippet_service(). - Pure Domain: Domain files must not import from the web framework (Flask/FastAPI) or database drivers.
- DTO Enforcement: Services should communicate using DTOs rather than raw request objects or raw dictionary results from the database.
- Shared vs. Infrastructure: General utilities (text formatting, time) reside in
shared/, while system-specific tools (file I/O, security hashing) reside ininfrastructure/.
Sources: PROMPTS_WEBAPP_LAYERING.md:81-86, GUIDES/ARCHITECTURE_ANALYSIS_PART1.md:251-267
Conclusion
Adhering to these Layered Architecture Principles reduces technical debt by limiting the impact of changes. By isolating the Domain logic from Infrastructure and Presentation, the CodeBot project enables easier onboarding, simplified unit testing of business rules, and the flexibility to swap underlying technologies (such as the database or web framework) without rewriting the core application logic.
Sources: code_review_2025_10/CODE_REVIEW_SUMMARY.md:144-158, PROMPTS_WEBAPP_LAYERING.md:129-132