1. Architectural Overview
The application follows a lightweight MVC structure with explicit HTTP dispatch.
public/index.phpis the front controller.router/Router.phpwraps AltoRouter and dispatches controller targets.routes/*.phpdefine routes by HTTP verb.controllers/contains application and API entry points.models/encapsulates persistence concerns.core/centralizes request, response, auth, and configuration services.utils/contains reusable infrastructure helpers.
2. Runtime Flow
2.1 Bootstrap
- Load Composer autoloading.
- Load environment variables.
- Create the core response and orchestration services.
- Initialize the router and controller dispatcher.
- Load route files and dispatch the request.
2.2 Route Resolution
Routes may point either to a closure or to a controller target such as [ControllerClass::class, 'method']. The direct controller target is the recommended production style.
2.3 Controller Dispatch
Controller instances are built through Core\Core::makeController(), which injects shared request and response objects and provides a clean seam for future dependency injection improvements.
3. Core Services
Core\AppConfig
Provides access to environment variables and helpers for environment, debug mode, and allowed origins.
Core\Request
Encapsulates raw body access, JSON decoding, headers, method, URI, and uploaded files.
Core\Response
Standardizes JSON status codes, output, and optional request termination.
Core\AuthService
Validates bearer tokens, requires HS256, verifies signatures, and checks temporal claims.
Core\Core
Acts as an orchestration layer for route loading, CORS, authenticated user extraction, and controller creation.
4. Controllers
Controllers\Controller is the base class for concrete controllers.
- Keep HTTP orchestration in controllers.
- Keep SQL and persistence in models.
- Use
jsonResponse()andjsonError()for API consistency. - Read JSON bodies through
$this->request->json().
Router\Router::get('/api/articles', [Controllers\ArticleController::class, 'apiIndex']);
Router\Router::post('/api/articles', [Controllers\ArticleController::class, 'apiStore']);
Router\Router::put('/api/articles/[i:id]', [Controllers\ArticleController::class, 'apiUpdate']);
Router\Router::delete('/api/articles/[i:id]', [Controllers\ArticleController::class, 'apiDestroy']);5. Models
Models\DataModel
- Provides centralized PDO access.
- Initializes lazily.
- Reads database settings from
config/config.php. - Uses exception mode and associative fetch mode.
Domain Models
Domain models should remain focused on persistence. Avoid placing request parsing, response formatting, or authentication logic in models.
6. Views
Views remain standard PHP templates under views/, using the convention views/<resource>/<template>.php. Use render('articles/index', [...]) from controllers. API-only endpoints should return JSON instead of rendering views.
7. Utilities
Utils\Security
Provides sanitation, HTML escaping, password hashing, CSRF helpers, and lightweight session rate limiting.
Utils\UploadHandler
Provides safer uploads with server-side validation, size limits, MIME and extension allowlists, and randomized filenames.
Utils\Mailer
Uses PHPMailer when available and falls back to mail() otherwise.
8. Route Organization
routes/get.phproutes/post.phproutes/put.phproutes/delete.php
This split is acceptable for a small codebase. For larger applications, consider evolving toward domain-based route modules or grouped route registration.
9. Code Generation with automat
The built-in scaffolding tool generates models and controllers aligned with the project conventions.
php automat list
php automat create:model Article
php automat create:controller ArticleControllerGenerated controllers include MVC actions, API actions, JSON-aware request parsing, and route examples using direct controller-target dispatch.
10. Security Considerations
- Never deploy with placeholder JWT secrets.
- Restrict
CORS_ALLOWED_ORIGINSexplicitly in production. - Do not trust client-provided filenames for uploads.
- Keep
APP_DEBUG=falseoutside development. - Extend
AuthServiceinstead of bypassing it.
11. Testing Strategy
The repository includes a lightweight test runner in tests/run.php.
- JSON request decoding
- JWT acceptance and rejection behavior
- Router dispatch to controller targets
Recommended next additions include controller behavior tests, model integration tests, and route coverage for generated CRUD controllers.
12. Recommended Contribution Rules
- Keep bootstrap logic inside
public/index.phpminimal. - Add behavior to services before duplicating logic in controllers.
- Prefer controller targets over route closures.
- Keep models focused on persistence.
- Document new environment variables in
.env.example. - Update both documentation pages when architecture changes materially.
13. Future Improvements
- A proper dependency injection container
- Middleware support
- Richer exception mapping
- Typed DTOs or request validators
- A dedicated test framework configuration
The current structure is already a solid foundation for these upgrades because responsibilities are more clearly separated than in the initial project state.