Definir cómo se escribe, organiza y estructura el código PHP/Laravel del proyecto, priorizando código legible, simple y consistente sobre patrones sofisticados.
PSR-1 (estilo básico) y estilo de código de Laravel — OBLIGATORIO, verificado automáticamente por Laravel Pint con el preset laravel. Este preset se basa en PSR-12 y en su sucesor mantenido, PER Coding Style (PHP-FIG marcó PSR-12 como deprecated en favor de PER-CS), con ajustes propios de Laravel. No se exige el preset psr12 estricto de Pint salvo que el equipo lo decida y lo documente.
PSR-4 (autoloading) — OBLIGATORIO, ya provisto por Composer/Laravel; no modificar composer.json sin justificar.
PHP moderno (8.1+): usar tipado estricto, readonly en DTOs, enums nativos de PHP para catálogos cerrados, match en vez de switch cuando aplique — RECOMENDADO.
declare(strict_types=1); al inicio de cada archivo de clase — RECOMENDADO (AVANZADO si el equipo aún no domina el tipado, pero se recomienda adoptarlo cuanto antes).
│ ├── Controllers/Api/V1/ # Controladores delgados, un recurso por archivo
│ ├── Requests/ # FormRequests: TODA validación de entrada vive aquí
│ ├── Resources/ # Transformación de salida (JSON API)
│ └── Middleware/
├── Models/ # Eloquent models
├── Services/ # Lógica de negocio que no pertenece al Model ni al Controller
├── Policies/ # Autorización por modelo
├── Jobs/ # Trabajos en cola (AVANZADO, cuando aplique)
├── Events/ & Listeners/ # Solo si hay un flujo realmente desacoplado (AVANZADO)
├── Exceptions/ # Excepciones de dominio propias
└── DTOs/ # Solo si se pasa >3 datos relacionados entre capas (opcional)
Justificación de cada carpeta (ninguna se incluye “porque sí”):
Controllers: obligatoria, punto de entrada HTTP. Deben ser delgados: reciben Request, delegan a Service o Model, devuelven Resource.
Requests: obligatoria desde Fase 2. Centraliza validación; evita if de validación dentro del controlador.
Resources: obligatoria para cualquier endpoint que devuelva datos a un frontend distinto del propio Blade (que es el caso aquí, con frontend separado).
Services: se usa solo cuando la lógica de negocio no cabe razonablemente en el Model ni en el Controller (p. ej. orquesta varios modelos, llama a una API externa, aplica reglas complejas). No crear un Service vacío que solo llama a Model::create().
Policies: obligatoria en cuanto exista más de un rol de usuario.
Jobs/Events/Listeners: AVANZADO. Solo si hay una necesidad real de asincronía o desacoplamiento (ej. enviar correos, generar reportes pesados). No se usan para “parecer más profesional”.
DTOs: opcionales. Se usan si transportar un array asociativo entre capas se vuelve confuso o propenso a errores; si el equipo aún no domina readonly class, un array tipado con FormRequest basta.
Repository Pattern: en Laravel, Eloquent implementa el patrón Active Record (el modelo encapsula acceso a datos y comportamiento). Añadir además una capa Repository propia sobre Eloquent no se implementa en este proyecto, salvo que exista una necesidad real de intercambiar la fuente de datos (por ejemplo, alternar entre PostgreSQL y una API externa) — eso se documenta con ADR. Para el 95% de los casos del proyecto, Model::query()... dentro de un Service es suficiente y más legible para el nivel del equipo.
Factory Pattern (de diseño, no las Model Factories de testing): no se introduce salvo que exista más de una familia real de objetos intercambiables en tiempo de ejecución (por ejemplo, más de una pasarela de pago). Las Model Factories de Laravel para testing sí son obligatorias (Doc. 08) — son un concepto distinto.
CQRS: fuera de alcance. Es una solución para sistemas con cargas de lectura/escritura muy asimétricas y complejas; el proyecto no tiene esa escala. No se implementa.
Event Sourcing: fuera de alcance total. Añade complejidad de infraestructura (event store, proyecciones) que no se justifica en un proyecto académico de un semestre.
Regla general: si no puedes explicar en una frase el problema concreto que el patrón resuelve en este proyecto, no lo implementes.
Resources: transforman el modelo a la forma exacta que el frontend necesita; no exponer campos sensibles (password, tokens) — P0/OBLIGATORIO.
Policies: una policy por modelo con autorización condicional (ej. “solo el dueño puede editar su registro”) — P1/OBLIGATORIO en cuanto exista autenticación multiusuario.
Middleware: se usa para preocupaciones transversales (autenticación, rate limiting, logging de requests); no se usa para lógica de negocio — P1/OBLIGATORIO.
Se usa el Service Container de Laravel (type-hinting en constructores o métodos de controlador) en vez de instanciar clases con new dentro de la lógica de negocio — P2/RECOMENDADO, AVANZADO si implica bindings personalizados en AppServiceProvider.
14. SOLID, DRY, KISS, YAGNI aplicados con realismo
Un Controller atiende un recurso; un Service resuelve un caso de uso, no “todo lo relacionado a X”.
Open/Closed
Si algo cambia mucho (ej. reglas de descuento), extraer a una clase separada en vez de llenar de if un método existente.
Liskov
Si una clase extiende otra, debe poder sustituirla sin romper el comportamiento esperado.
Interface Segregation
No forzar una interfaz con 10 métodos si una clase solo necesita 2.
Dependency Inversion
Depender de una interfaz (PaymentGatewayInterface) solo si realmente habrá más de una implementación; si no, se puede depender de la clase concreta sin culpa.
DRY
Si copias/pegas el mismo bloque una tercera vez, extráelo a un método/trait. Copiarlo dos veces no es automáticamente una falta.
KISS
La solución más simple que resuelve el problema real gana, aunque no sea la “más elegante”.
YAGNI
No construyas la opción de “por si en el futuro necesitamos multi-tenant” si nadie lo pidió.
Además de las reglas STD-BE-C0x (controllers), STD-BE-R0x (requests), STD-BE-M0x (models) y STD-BE-E0x (errores) de las secciones 7–11, este documento fija estas reglas generales, para su referencia desde la Matriz de Cumplimiento (Doc. 14):
ID
Regla
Prioridad
Sección
STD-BE-G01
El código sigue el estilo de Laravel (preset laravel de Pint, base PSR-12/PER-CS); PSR-1 y PSR-4 obligatorios.
P1
3
STD-BE-G02
Se respetan las convenciones de nombres de la sección 4 (clases, métodos, variables, tablas, rutas, variables de entorno).
P1
4
STD-BE-G03
Los Resources no exponen campos sensibles (password, tokens).
P0
10
STD-BE-G04
Una Policy por modelo en cuanto exista autenticación multiusuario.
P1
10
STD-BE-G05
El middleware se usa para preocupaciones transversales, no para lógica de negocio.
P1
10
STD-BE-G06
Se usa Log::*, nunca dd()/var_dump()/echo en código que llega a main.
P0
12
STD-BE-G07
Los logs incluyen contexto y nunca datos sensibles.