Implementación de referencia de una API RESTful construida con Laravel 12 y arquitectura Domain-Driven Design (DDD). Gestión de planes de suscripción completamente dockerizada, con autenticación Sanctum, documentación Swagger y suite de tests.
El proyecto esta estructurado siguiendo los principios de DDD con las siguientes capas:
- Entidades: Plan, Company, User con logica de negocio
- Objetos de Valor: Money, UserLimit, PlanName, Email, etc.
- Eventos: Eventos de dominio como PlanCreated
- Interfaces de Repositorio: Contratos para persistencia de datos
- DTOs: Data Transfer Objects para limites de API
- Casos de Uso: Operaciones de negocio (CreatePlan, UpdatePlan, etc.)
- Servicios: Servicios especificos de aplicacion
- Modelos: Modelos Eloquent (PlanModel, CompanyModel, UserModel)
- Repositorios: Implementaciones concretas de repositorios
- Eventos: Infraestructura de manejo de eventos
- Controladores: Controladores API con inyeccion de dependencias
- Requests: Clases de validacion de formularios
- Resources: Transformadores de respuesta API
- Policies: Logica de autorizacion
- Laravel App (PHP 8.4 FPM Alpine)
- Nginx (Servidor web)
- MySQL 8.0 (Base de datos)
- Vite (Compilacion de assets frontend con TailwindCSS)
- Aplicacion: http://localhost:8080 (Nginx)
- Base de datos: localhost:3306 (MySQL)
- Docker y Docker Compose instalados
- Git para clonar el repositorio
-
Clonar el repositorio
git clone https://github.com/RikardoBonilla/laravel-ddd-api.git cd laravel-ddd-api -
Configurar variables de entorno
cp src/.env.example src/.env
-
Levantar el entorno Docker
docker-compose up -d
-
Acceder al contenedor de la aplicacion
docker exec -it zalvadora_app sh -
Instalar dependencias PHP
cd /var/www/html composer install -
Generar clave de aplicacion
php artisan key:generate
-
Ejecutar migraciones
php artisan migrate
-
Instalar dependencias Node.js
npm install
-
Compilar assets
npm run dev
Las variables de entorno para Docker:
- Host:
db(nombre del servicio Docker) - Puerto: 3306
- Base de datos:
zalvadora_db - Usuario:
root - Contraseña:
root
📥 Cliente HTTP Request
↓
🌐 Nginx (Puerto 8080)
↓
🚀 Laravel Application
↓
🛣️ Router (routes/api_v1.php)
↓
🎮 Controller (Presentation Layer)
↓
⚡ Use Case (Application Layer)
↓
📋 Repository Interface (Domain Layer)
↓
💾 Repository Implementation (Infrastructure Layer)
↓
📊 Eloquent Model
↓
🗃️ MySQL Database
Archivo de Entrada: routes/api_v1.php:15
Route::get('/plans', [PlanController::class, 'index']);Flujo de Archivos:
- Router →
routes/api_v1.php - Controller →
app/Presentation/Controllers/PlanController.php:index() - Use Case →
app/Application/UseCases/Plan/GetAllPlansUseCase.php - Repository →
app/Infrastructure/Repositories/EloquentPlanRepository.php:findAll() - Model →
app/Infrastructure/Models/PlanModel.php - Response →
app/Presentation/Resources/PlanResource.php
Informacion Transferida:
- Entrada: Request vacio (solo headers de autenticacion)
- Proceso: Consulta a base de datos para obtener todos los planes
- Salida: JSON con lista de planes transformados
Flujo de Archivos:
- Router →
routes/api_v1.php:16 - Validation →
app/Presentation/Requests/CreatePlanRequest.php - Controller →
app/Presentation/Controllers/PlanController.php:store() - DTO →
app/Application/DTOs/PlanDto.php - Use Case →
app/Application/UseCases/Plan/CreatePlanUseCase.php - Entity →
app/Domain/Entities/Plan.php - Repository →
app/Infrastructure/Repositories/EloquentPlanRepository.php:save() - Model →
app/Infrastructure/Models/PlanModel.php
Informacion Transferida:
- Entrada: JSON con datos del plan (name, monthly_price_amount, monthly_price_currency, user_limit, features)
- Validacion: Reglas de negocio y formato
- Proceso: Creacion de entidad de dominio y persistencia
- Salida: JSON con plan creado y codigo 201
Flujo de Archivos:
- Router →
routes/api_v1.php:17 - Controller →
app/Presentation/Controllers/PlanController.php:show() - Use Case →
app/Application/UseCases/Plan/GetPlanByIdUseCase.php - Repository →
app/Infrastructure/Repositories/EloquentPlanRepository.php:findById() - Model →
app/Infrastructure/Models/PlanModel.php
Informacion Transferida:
- Entrada: UUID del plan en la URL
- Proceso: Busqueda por ID en base de datos
- Salida: JSON con datos completos del plan o error 404
Flujo de Archivos:
- Router →
routes/api_v1.php:18 - Validation →
app/Presentation/Requests/UpdatePlanRequest.php - Controller →
app/Presentation/Controllers/PlanController.php:update() - DTO →
app/Application/DTOs/PlanDto.php - Use Case →
app/Application/UseCases/Plan/UpdatePlanUseCase.php - Repository →
app/Infrastructure/Repositories/EloquentPlanRepository.php:update()
Informacion Transferida:
- Entrada: UUID + JSON con datos actualizados
- Proceso: Validacion, busqueda, actualizacion de entidad
- Salida: JSON con plan actualizado
Flujo de Archivos:
- Router →
routes/api_v1.php:19 - Controller →
app/Presentation/Controllers/PlanController.php:destroy() - Use Case →
app/Application/UseCases/Plan/DeletePlanUseCase.php - Repository →
app/Infrastructure/Repositories/EloquentPlanRepository.php:delete()
Informacion Transferida:
- Entrada: UUID del plan
- Proceso: Verificacion de existencia y eliminacion
- Salida: Respuesta vacia con codigo 204
La aplicacion utiliza Laravel Sanctum para autenticacion basada en tokens:
-
Login →
POST /api/v1/login- Entrada: email, password
- Proceso: Validacion de credenciales
- Salida: Token de acceso
-
Proteccion de Rutas:
- Middleware
auth:sanctumen rutas protegidas - Header requerido:
Authorization: Bearer {token}
- Middleware
- id (UUID) - Clave primaria
- name (VARCHAR) - Nombre del plan
- monthly_price_amount (INTEGER) - Precio en centavos
- monthly_price_currency (VARCHAR) - Codigo de moneda
- user_limit (INTEGER) - Limite maximo de usuarios
- features (JSON) - Array de caracteristicas
- created_at (TIMESTAMP)
- updated_at (TIMESTAMP)- id (UUID) - Clave primaria
- name (VARCHAR) - Nombre de la empresa
- email (VARCHAR) - Email unico de la empresa
- plan_id (UUID) - Clave foranea a plans
- created_at (TIMESTAMP)
- updated_at (TIMESTAMP)- id (UUID) - Clave primaria
- name (VARCHAR) - Nombre del usuario
- email (VARCHAR) - Email unico del usuario
- company_id (UUID) - Clave foranea a companies
- role (ENUM) - Rol del usuario (admin/user)
- password (VARCHAR) - Contraseña encriptada
- created_at (TIMESTAMP)
- updated_at (TIMESTAMP)- URL: http://localhost:8080/api/documentation
- JSON Spec: http://localhost:8080/docs/api-docs.json
- Caracteristicas:
- Documentacion completa con OpenAPI 3.0
- Esquemas de request/response
- Documentacion de autenticacion
- Pruebas interactivas
- Ejemplos de requests y responses
| Metodo | Endpoint | Descripcion | Autenticacion |
|---|---|---|---|
| GET | /api/v1/plans |
Listar planes | Requerida (Admin) |
| POST | /api/v1/plans |
Crear plan | Requerida (Admin) |
| GET | /api/v1/plans/{id} |
Mostrar plan | Opcional |
| PUT | /api/v1/plans/{id} |
Actualizar plan | Requerida (Admin) |
| DELETE | /api/v1/plans/{id} |
Eliminar plan | Requerida (Admin) |
| POST | /api/v1/login |
Iniciar sesion | No |
- Value Objects de dominio (Money, UserLimit, PlanName, etc.)
- Entidades de dominio (Plan, Company, User)
- Casos de uso y logica de negocio
- Funcionalidad de endpoints API
- Autenticacion y autorizacion
- Integracion con base de datos
# Ejecutar todas las pruebas
docker exec zalvadora_app php artisan test
# Ejecutar pruebas especificas
docker exec zalvadora_app php artisan test --filter=PlanTest
# Ejecutar con cobertura
docker exec zalvadora_app php artisan test --coverage# Iniciar entorno completo
docker-compose up -d
# Detener entorno
docker-compose down
# Acceder al contenedor de la app
docker exec -it zalvadora_app sh
# Ver logs
docker-compose logs -f app# Servidor de desarrollo (concurrente: server, queue, logs, vite)
composer dev
# Ejecutar pruebas
composer test
# o
php artisan test
# Formateo de codigo
./vendor/bin/pint
# Migraciones
php artisan migrate
# Limpiar cache de configuracion
php artisan config:clear
# Generar documentacion Swagger
php artisan l5-swagger:generate# Build de desarrollo con hot reload
npm run dev
# Build de produccion
npm run build
# Watch para cambios
npm run watchlaravel-ddd-api/
├── docker/ # Configuraciones Docker
│ ├── app/Dockerfile # Contenedor PHP-FPM
│ └── nginx/default.conf # Configuracion Nginx
├── src/ # Aplicacion Laravel
│ ├── app/
│ │ ├── Domain/ # Capa de Dominio
│ │ │ ├── Entities/
│ │ │ ├── ValueObjects/
│ │ │ └── Repositories/
│ │ ├── Application/ # Capa de Aplicacion
│ │ │ ├── DTOs/
│ │ │ └── UseCases/
│ │ ├── Infrastructure/ # Capa de Infraestructura
│ │ │ ├── Models/
│ │ │ └── Repositories/
│ │ └── Presentation/ # Capa de Presentacion
│ │ ├── Controllers/
│ │ ├── Requests/
│ │ └── Resources/
│ ├── routes/api_v1.php # Rutas API v1
│ ├── database/migrations/ # Migraciones de BD
│ └── tests/ # Pruebas unitarias y de funcionalidad
└── docker-compose.yml # Configuracion Docker Compose
└── README.md # Esta documentacion
- Laravel Framework 12.x - Framework principal
- Laravel Sanctum - Autenticacion API
- L5 Swagger - Documentacion API
- Laravel Tinker - REPL para debugging
- PHPUnit - Framework de testing
- Laravel Pint - Formateo de codigo
- Ramsey UUID - Generacion de UUIDs
- Vite - Compilacion de assets
- TailwindCSS - Framework de estilos
- Laravel Vite Plugin - Integracion con Laravel
- Concurrently - Ejecucion de multiples comandos
# Verificar que el contenedor de BD este ejecutandose
docker-compose ps
# Recrear contenedores
docker-compose down
docker-compose up -d --build# Desde el host
sudo chown -R $USER:$USER src/
# Dentro del contenedor
chown -R www-data:www-data /var/www/html/storage
chown -R www-data:www-data /var/www/html/bootstrap/cache# Limpiar todos los caches
docker exec zalvadora_app php artisan config:clear
docker exec zalvadora_app php artisan cache:clear
docker exec zalvadora_app php artisan route:clear
docker exec zalvadora_app php artisan view:clear-
Configurar cache:
php artisan config:cache php artisan route:cache php artisan view:cache
-
Optimizar Composer:
composer install --optimize-autoloader --no-dev
-
Compilar assets para produccion:
npm run build
- Crear rama feature desde main
- Implementar cambios siguiendo arquitectura DDD
- Añadir pruebas unitarias y de funcionalidad
- Ejecutar formateo con Laravel Pint
- Verificar que todas las pruebas pasen
- Crear Pull Request
- Seguir PSR-12 para PHP
- Usar Laravel Pint para formateo automatico
- Documentar metodos publicos con PHPDoc
- Mantener cobertura de pruebas > 80%
MIT License — Desarrollado por Ricardo Andres Bonilla Prada.
Desarrollado con ❤️ usando Laravel 12, Docker, y arquitectura DDD