Leo Counter is organized around Domain-Driven Design (DDD), Command Query Responsibility Segregation (CQRS), and Clean Architecture principles. The codebase is deliberately structured so that business rules live in isolation from framework and persistence concerns, making each layer independently testable and long-term maintainable. TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/juanVillamilEchavarria/Leo_Counter-app/llms.txt
Use this file to discover all available pages before exploring further.
app/ directory is divided into four top-level namespaces — Domains, Application, Infrastructure, and Http — plus a Shared kernel and Providers directory that wires everything together through Laravel’s service container.
Top-Level Layer Overview
Domains
Pure business logic: aggregates, value objects, domain events, domain service contracts, and repository interfaces. No Laravel or Eloquent imports.
Application
Use-case orchestration via Commands, Queries, DTOs, Handlers, Validators, Mappers, EventHandlers, and Resolvers.
Infrastructure
Eloquent implementations of repository contracts, query executors, framework event handlers, and external-service adapters.
Http
Thin Laravel controllers, form request validators, and API resources. Controllers delegate immediately to the Application layer via the CQRS bus.
Domain Modules
Leo Counter is split into self-contained domain modules. Each module appears inapp/Domains/, app/Application/, app/Infrastructure/, and app/Http/ under the same name.
| Module | Responsibility |
|---|---|
Movimiento | Core financial transaction recording (income, expense, transfer) |
MovimientoFijo | Recurring fixed transactions processed automatically each day |
MovimientoPendiente | Pending/deferred transactions awaiting confirmation |
Presupuesto | Monthly budget tracking and limit enforcement |
Cuenta | Bank and cash account management |
Categoria | Expense and income category management |
Reporte | Financial report generation with KPIs, distributions, and comparatives |
Notificacion | In-app and email notifications with real-time WebSocket broadcasting |
Usuario | User profile and credential management |
Auth | Authentication flow (login, registration, password reset) |
Configuracion | System-wide settings and soft-delete recovery management |
Propietario | Household owner/co-owner management |
Home | Dashboard data aggregation and summary queries |
ArchivoMovimiento | CSV/spreadsheet movement file upload and processing |
Layer Details
Domains Layer (app/Domains/)
The domain layer contains only business concepts. It has no dependency on Laravel, Eloquent, or any infrastructure concern.
What lives in the Domains layer
What lives in the Domains layer
- Aggregates — Rich domain entities that encapsulate state and enforce invariants. Example:
Movimiento,Cuenta,Presupuesto. - Value Objects — Immutable types that describe domain concepts without identity. Example:
MovimientoId,RevertTransactionEffectForCuentaResultVO. - Domain Events — Events raised when significant state changes occur (e.g., a
Movimientois stored or aMovimientoFijotriggers). - Contracts / Repository Interfaces — PHP interfaces that define what persistence operations the domain needs, without specifying how.
- Domain Strategies — Strategy pattern implementations for domain rules such as transaction application and reversion logic (
Movimiento/Strategies/Transaction/Apply,.../Revert). - Exceptions — Domain-specific exceptions that communicate business rule violations.
Application Layer (app/Application/)
The application layer coordinates domain objects and infrastructure services to fulfill use cases. It defines the CQRS messages and their handlers.
What lives in the Application layer
What lives in the Application layer
- Commands — Immutable data objects representing write intentions (e.g.,
StoreMovimientoCommand,DestroyMovimientoCommand,UpdateMovimientoCommand). - Command Handlers — Classes that receive a
Commandfrom theCommandBus, orchestrate domain objects, and persist via repository contracts (e.g.,StoreMovimientoHandler,UpdateMovimientoHandler). - Queries — Immutable data objects representing read requests (e.g.,
ListMovimientoForTableQuery,GetMovimientoForEditQuery,CheckEnoughBalanceQuery). - Query Handlers — Classes that receive a
Queryfrom theQueryBusand return a result without side effects (e.g.,ListMovimientoForTableHandler,GetMovimientoForShowHandler). - DTOs — Data Transfer Objects that carry structured data between layers.
- EventHandlers — React to domain events raised in other modules (cross-cutting concerns such as updating balances after a
Movimientois stored). - Validators — Application-level business validation beyond form request validation.
- Mappers — Convert between domain aggregates and DTOs or persistence models.
- Resolvers — Select the correct strategy or handler at runtime based on context.
Infrastructure Layer (app/Infrastructure/)
The infrastructure layer provides concrete implementations of the contracts defined in the domain and application layers.
What lives in the Infrastructure layer
What lives in the Infrastructure layer
- Eloquent Repositories — Implement
Domains/{Module}/Contracts/Repositoriesusing Laravel’s Eloquent ORM. Example:Infrastructure/Movimiento/Persistence/Repositories/Eloquent/EloquentMovimientoRepository.php. - Query Executors — Implement
Application/{Module}/Contracts/Queries/Executorsusing Eloquent or raw query builders for read-optimized queries. - Framework Event Handlers — Laravel listeners that translate Laravel/Eloquent events into domain events or trigger application commands.
- Builders — Compose complex Eloquent query logic used by query executors.
- Broadcasting — Real-time WebSocket event classes for the Notificacion module, delivered via Laravel Reverb.
- External Service Adapters — Implementations of domain service contracts that call external APIs or framework services (e.g., mail dispatch, file storage).
Http Layer (app/Http/)
The HTTP layer is deliberately thin. Controllers validate the incoming HTTP request, extract parameters, dispatch a command or query through the bus, and return a response or Inertia page.
What lives in the Http layer
What lives in the Http layer
- Controllers — Grouped by domain module under
Http/Controllers/{Module}/. API controllers live underHttp/Controllers/Api/{Module}/. Controllers inject theCommandBusandQueryBus(or specific handlers) through the service container. - Form Requests — Laravel
FormRequestclasses underHttp/Requests/{Module}/perform HTTP-level input validation before the controller runs. - API Resources — Laravel
JsonResourceandResourceCollectionclasses underHttp/Resources/{Module}/shape the JSON output for API endpoints. - Middleware — Shared middleware in
Http/Middleware/.
CQRS Bus Pattern
Leo Counter’s Application layer communicates through a strict command/query bus defined in the Shared kernel.CommandBus. A controller that wants to store a transaction does this:
QueryBus:
ProcessDailyFinancialTasks Artisan command (php artisan leo:process-daily-financial-tasks) also uses the CommandBus to dispatch recurring financial processing for fixed and pending transactions, demonstrating that the CQRS pattern extends to scheduled tasks, not only HTTP requests.
Shared Kernel (app/Shared/)
The Shared kernel contains cross-cutting contracts and utilities that any module may depend on without creating inter-module coupling.
Service Providers and Dependency Injection
Each domain module has one or more service providers underapp/Providers/{Module}/ that bind the domain’s repository interfaces to their Eloquent implementations:
Movimiento Module — Full Directory Tree
The Movimiento module is the most complete example of the full DDD/CQRS structure:Frontend Architecture
The React frontend underresources/js/ mirrors the backend’s domain structure. Domain-specific UI logic, API hooks, TypeScript types, and components are grouped by domain:
types/ for TypeScript interfaces, components/ for React UI components, hooks/ for data-fetching and state hooks, and api/ for Axios/TanStack Query calls. The @ alias (configured in vite.config.ts) maps to resources/js/, making imports consistent across the frontend.