# Phred Technical Specifications [← Back to README](./README.md) | [MILESTONES.md](./MILESTONES.md) ## Table of Contents - [1. Core Framework](#1-core-framework) - [1.1 API Formats and Content Negotiation](#1-1-api-formats-and-content-negotiation) - [1.2 Pluggability Model (M5)](#1-2-pluggability-model-m5) - [1.3 URL Extension Negotiation](#1-3-url-extension-negotiation) - [1.4 Dependencies](#1-4-dependencies) - [2. MVC Components](#2-mvc-components) - [2.1 Controllers](#2-1-controllers) - [2.2 Views (M6)](#2-2-views-m6) - [2.3 Services](#2-3-services) - [3. Modular Architecture (M7)](#3-modular-architecture-m7) - [3.1 Module Layout (ORM-Agnostic)](#3-1-module-layout-orm-agnostic) - [3.2 Modular Separation](#3-2-modular-separation) - [4. Infrastructure](#4-infrastructure) - [4.1 Service Providers (M5)](#4-1-service-providers-m5) - [4.2 Configuration and Environment](#4-2-configuration-and-environment) - [4.3 Command Discovery](#4-3-command-discovery) - [5. Technical Examples](#5-technical-examples) - [5.1 Configuration Access](#5-1-configuration-access) - [5.2 API Negotiation](#5-2-api-negotiation) - [5.3 Route Group Inclusion](#5-3-route-group-inclusion) This document outlines the technical specifications and architectural standards of the Phred framework. ## 1. Core Framework ### 1.1 API Formats and Content Negotiation Phred supports two primary API formats: * **Pragmatic REST (default)**: Plain JSON responses using RFC 7807 for error handling. * **JSON:API**: Compliant with the JSON:API specification for documents and error objects. Negotiation can be set globally via `.env`: * `API_FORMAT=rest` * `API_FORMAT=jsonapi` Clients can override the format per request using the `Accept` header: * `Accept: application/vnd.api+json` forces JSON:API. * `Accept: application/xml` or `text/xml` (M12+). ### 1.2 Pluggability Model (M5) The framework is fully pluggable. Core components depend on Phred contracts and PSRs; concrete implementations are provided by Service Providers. * Providers implement `Phred\Support\Contracts\ServiceProviderInterface`. * Lifecycle methods: `register(ContainerBuilder)` and `boot(Container)`. * Loading order: Core → App → Modules (defined in `config/providers.php`). **Primary Contracts:** * `Template\Contracts\RendererInterface` * `Orm\Contracts\ConnectionInterface` * `Flags\Contracts\FeatureFlagClientInterface` * `Testing\Contracts\TestRunnerInterface` ### 1.3 URL Extension Negotiation Optional middleware that hints content negotiation based on URL suffix. * Enabled via `URL_EXTENSION_NEGOTIATION=true` (default). * Whitelist via `URL_EXTENSION_WHITELIST` (default: "json|xml|php|none"). * **Mappings:** * `.json` → `application/json` * `.xml` → `application/xml` * `.php` or none → `text/html` (View convention) ### 1.4 Dependencies Phred leverages several industry-standard packages: * **Dependency Injection**: `php-di/php-di` * **Static Analysis**: `phpstan/phpstan` * **Code Style**: `friendsofphp/php-cs-fixer` * **Logging**: `monolog/monolog` * **Environment**: `vlucas/phpdotenv` * **HTTP Client**: `guzzlehttp/guzzle` * **CORS**: `middlewares/cors` * **Authentication**: `lcobucci/jwt` * **Feature Flags**: `getphred/flagpole` * **ORM**: `getphred/pairity` * **Template Engine**: `getphred/eyrie` * **Router**: `nikic/fast-route` * **PSR-7/15**: `relay/relay`, `nyholm/psr7` ## 2. MVC Components ### 2.1 Controllers * **Invokable**: Controllers are "Actions" with a single entry point: `public function __invoke(Request $request)`. * **Response Factories**: Injected via `Phred\Http\Contracts\ApiResponseFactoryInterface`. * **Base Classes (M6)**: * `Phred\Mvc\APIController`: For API-only endpoints. * `Phred\Mvc\ViewController`: For HTML/Template endpoints. ### 2.2 Views (M6) * Classes dedicated to data preparation before rendering. * Extend `Phred\Mvc\View`. * Methods: * `transformData(array $data)`: Manipulate data before it hits the template. * `defaultTemplate()`: Define the default template for the view. * **Conventions**: Controllers call `renderView($view, $data, ?$templateOverride)`. If no override is provided, the View decides the template. ### 2.3 Services * Business logic should reside in Service classes to keep controllers lean and models ORM-neutral. ## 3. Modular Architecture (M7) Phred follows a Django-style modular structure where all user code lives inside modules. ### 3.1 Module Layout (ORM-Agnostic) * `modules//Controllers/` * `modules//Views/` * `modules//Templates/` * `modules//Services/` * `modules//Models/` (Domain models, pure PHP) * `modules//Repositories/` (Interfaces consumed by services) * `modules//Persistence/Pairity/` (Driver-specific implementations) * `modules//Persistence/Eloquent/` (Driver-specific implementations) * `modules//Database/Migrations/` (Canonical migrations) * `modules//Routes/web.php` and `api.php` * `modules//Providers/*ServiceProvider.php` ### 3.2 Modular Separation Modules encapsulate their own: * Models, Controllers, Views, Services, Migrations, Providers, Routes, Templates, and Tests. ## 4. Infrastructure ### 4.1 Service Providers (M5) Providers are the glue of the framework. * **Configuration**: `config/providers.php` * **Route Registration**: Use `RouteRegistry::add(static function($collector, $router) { ... })`. ### 4.2 Configuration and Environment * **Dotenv**: Loads `.env` from the project root. * **Config Facade**: `Phred\Support\Config::get(, )`. * **Precedence**: Environment variables > Config files (`config/*.php`) > Defaults. * **Notation**: Supports both `UPPER_SNAKE` and `dot.notation`. ### 4.3 Command Discovery * **Core Commands**: Discovered from `src/commands`. * **User Commands**: Discovered from `console/commands`. * Custom commands must return an instance of `Phred\Console\Command`. ## 5. Technical Examples ### 5.1 Configuration Access ```php use Phred\Support\Config; $env = Config::get('APP_ENV', 'local'); // environment check $tz = Config::get('app.timezone', 'UTC'); // dotted notation from config/app.php ``` ### 5.2 API Negotiation The chosen format is stored on the request as `phred.api_format` and used by the `ApiResponseFactoryInterface` to determine the response shape. ### 5.3 Route Group Inclusion ```php use Phred\Http\Routing\RouteGroups; use Phred\Http\Router; RouteGroups::include($router, '/prefix', function (Router $router) { require __DIR__ . '/../path/to/routes.php'; }); ```