Phred/SPECS.md

162 lines
6.4 KiB
Markdown

# 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/<Module>/Controllers/`
* `modules/<Module>/Views/`
* `modules/<Module>/Templates/`
* `modules/<Module>/Services/`
* `modules/<Module>/Models/` (Domain models, pure PHP)
* `modules/<Module>/Repositories/` (Interfaces consumed by services)
* `modules/<Module>/Persistence/Pairity/` (Driver-specific implementations)
* `modules/<Module>/Persistence/Eloquent/` (Driver-specific implementations)
* `modules/<Module>/Database/Migrations/` (Canonical migrations)
* `modules/<Module>/Routes/web.php` and `api.php`
* `modules/<Module>/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(<key>, <default>)`.
* **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';
});
```