Updates to README and MILESTONES. Add SPECS
This commit is contained in:
parent
a6888de9e8
commit
e0f34f6360
109
MILESTONES.md
109
MILESTONES.md
|
|
@ -1,5 +1,35 @@
|
||||||
# Phred Framework Milestones
|
# Phred Framework Milestones
|
||||||
|
|
||||||
|
[← Back to README](./README.md) | [SPECS.md](./SPECS.md)
|
||||||
|
|
||||||
Phred supports REST and JSON:API via env setting; batteries-included defaults, swappable components.
|
Phred supports REST and JSON:API via env setting; batteries-included defaults, swappable components.
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
|
## Table of Contents
|
||||||
|
- [~~M0 — Project bootstrap (repo readiness)~~](#m0-project-bootstrap-repo-readiness)
|
||||||
|
- [~~M1 — Core HTTP kernel and routing~~](#m1-core-http-kernel-and-routing)
|
||||||
|
- [~~M2 — Configuration and environment~~](#m2-configuration-and-environment)
|
||||||
|
- [~~M3 — API formats and content negotiation~~](#m3-api-formats-and-content-negotiation)
|
||||||
|
- [~~M4 — Error handling and problem details~~](#m4-error-handling-and-problem-details)
|
||||||
|
- [~~M5 — Dependency Injection and Service Providers~~](#m5-dependency-injection-and-service-providers)
|
||||||
|
- [~~M6 — MVC: Controllers, Views, Templates~~](#m6-mvc-controllers-views-templates)
|
||||||
|
- [~~M7 — Modules (Django‑style app structure)~~](#m7-modules-django-style-app-structure)
|
||||||
|
- [~~M8 — Database access, migrations, and seeds~~](#m8-database-access-migrations-and-seeds)
|
||||||
|
- [~~M9 — CLI (phred) and scaffolding~~](#m9-cli-phred-and-scaffolding)
|
||||||
|
- [~~M10 — Security middleware and auth primitives~~](#m10-security-middleware-and-auth-primitives)
|
||||||
|
- [~~M11 — Logging, HTTP client, and filesystem~~](#m11-logging-http-client-and-filesystem)
|
||||||
|
- [~~M12 — Serialization/validation utilities and pagination~~](#m12-serialization-validation-utilities-and-pagination)
|
||||||
|
- [M13 — OpenAPI and documentation](#m13-openapi-and-documentation)
|
||||||
|
- [M14 — Testing, quality, and DX](#m14-testing-quality-and-dx)
|
||||||
|
- [M15 — Caching and performance (optional default)](#m15-caching-and-performance-optional-default)
|
||||||
|
- [M16 — Production hardening and deployment](#m16-production-hardening-and-deployment)
|
||||||
|
- [M17 — JSON:API enhancements (optional package)](#m17-json-api-enhancements-optional-package)
|
||||||
|
- [M18 — Examples and starter template](#m18-examples-and-starter-template)
|
||||||
|
- [M19 — Documentation site](#m19-documentation-site)
|
||||||
|
- [M20 — Dynamic Command Help](#m20-dynamic-command-help)
|
||||||
|
- [M21 — Governance and roadmap tracking](#m21-governance-and-roadmap-tracking)
|
||||||
|
- [Notes on sequencing and parallelization](#notes-on-sequencing-and-parallelization)
|
||||||
|
|
||||||
## ~~M0 — Project bootstrap (repo readiness)~~
|
## ~~M0 — Project bootstrap (repo readiness)~~
|
||||||
* ~~Tasks:~~
|
* ~~Tasks:~~
|
||||||
* ~~Finalize `composer.json` (namespaces, scripts, suggests) and `LICENSE`.~~
|
* ~~Finalize `composer.json` (namespaces, scripts, suggests) and `LICENSE`.~~
|
||||||
|
|
@ -7,6 +37,8 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* ~~Set up CI (lint, static analysis, unit tests) and basic build badge.~~
|
* ~~Set up CI (lint, static analysis, unit tests) and basic build badge.~~
|
||||||
* ~~Acceptance:~~
|
* ~~Acceptance:~~
|
||||||
* ~~Fresh clone installs (without running suggested packages) and passes linters/analysis/tests.~~
|
* ~~Fresh clone installs (without running suggested packages) and passes linters/analysis/tests.~~
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## ~~M1 — Core HTTP kernel and routing~~
|
## ~~M1 — Core HTTP kernel and routing~~
|
||||||
* ~~Tasks:~~
|
* ~~Tasks:~~
|
||||||
* ~~Implement the HTTP kernel: `PSR-15` pipeline via `Relay`.~~
|
* ~~Implement the HTTP kernel: `PSR-15` pipeline via `Relay`.~~
|
||||||
|
|
@ -19,12 +51,16 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* ~~Sample route returning a JSON 200 via controller.~~
|
* ~~Sample route returning a JSON 200 via controller.~~
|
||||||
* ~~Controllers are invokable (`__invoke(Request)`), one route per controller.~~
|
* ~~Controllers are invokable (`__invoke(Request)`), one route per controller.~~
|
||||||
* ~~Route groups (prefix only) work and are tested.~~
|
* ~~Route groups (prefix only) work and are tested.~~
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## ~~M2 — Configuration and environment~~
|
## ~~M2 — Configuration and environment~~
|
||||||
* ~~Tasks:~~
|
* ~~Tasks:~~
|
||||||
* ~~Load `.env` via `vlucas/phpdotenv` and expose `Phred\Support\Config`.~~
|
* ~~Load `.env` via `vlucas/phpdotenv` and expose `Phred\Support\Config`.~~
|
||||||
* ~~Define configuration precedence and document keys (e.g., `API_FORMAT`, `APP_ENV`, `APP_DEBUG`).~~
|
* ~~Define configuration precedence and document keys (e.g., `API_FORMAT`, `APP_ENV`, `APP_DEBUG`).~~
|
||||||
* ~~Acceptance:~~
|
* ~~Acceptance:~~
|
||||||
* ~~App reads config from `.env`; unit test demonstrates override behavior.~~
|
* ~~App reads config from `.env`; unit test demonstrates override behavior.~~
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## ~~M3 — API formats and content negotiation~~
|
## ~~M3 — API formats and content negotiation~~
|
||||||
* ~~Tasks:~~
|
* ~~Tasks:~~
|
||||||
* ~~Finalize `ContentNegotiationMiddleware` using `.env` and `Accept` header.~~
|
* ~~Finalize `ContentNegotiationMiddleware` using `.env` and `Accept` header.~~
|
||||||
|
|
@ -32,6 +68,8 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* ~~Provide developer‑facing helpers for common responses (`ok`, `created`, `error`).~~
|
* ~~Provide developer‑facing helpers for common responses (`ok`, `created`, `error`).~~
|
||||||
* ~~Acceptance:~~
|
* ~~Acceptance:~~
|
||||||
* ~~Demo endpoints respond correctly as REST or JSON:API depending on `API_FORMAT` and `Accept`.~~
|
* ~~Demo endpoints respond correctly as REST or JSON:API depending on `API_FORMAT` and `Accept`.~~
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## ~~M4 — Error handling and problem details~~
|
## ~~M4 — Error handling and problem details~~
|
||||||
* ~~Tasks:~~
|
* ~~Tasks:~~
|
||||||
* ~~Finalize `ProblemDetailsMiddleware` with RFC7807 (REST) and JSON:API error documents.~~
|
* ~~Finalize `ProblemDetailsMiddleware` with RFC7807 (REST) and JSON:API error documents.~~
|
||||||
|
|
@ -39,6 +77,8 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* ~~Map common exceptions to HTTP status codes; include correlation/request IDs in responses/logs.~~
|
* ~~Map common exceptions to HTTP status codes; include correlation/request IDs in responses/logs.~~
|
||||||
* ~~Acceptance:~~
|
* ~~Acceptance:~~
|
||||||
* ~~Throwing an exception yields a standards‑compliant error response; debug mode shows Whoops page.~~
|
* ~~Throwing an exception yields a standards‑compliant error response; debug mode shows Whoops page.~~
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## ~~M5 — Dependency Injection and Service Providers~~
|
## ~~M5 — Dependency Injection and Service Providers~~
|
||||||
* ~~Tasks:~~
|
* ~~Tasks:~~
|
||||||
* ~~Define Service Provider interface and lifecycle (register, boot).~~
|
* ~~Define Service Provider interface and lifecycle (register, boot).~~
|
||||||
|
|
@ -50,6 +90,8 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* ~~Acceptance:~~
|
* ~~Acceptance:~~
|
||||||
* ~~Providers can contribute bindings and routes; order is deterministic and tested.~~
|
* ~~Providers can contribute bindings and routes; order is deterministic and tested.~~
|
||||||
* ~~Drivers can be switched via `.env`/config without changing controllers/services; example provider route covered by tests.~~
|
* ~~Drivers can be switched via `.env`/config without changing controllers/services; example provider route covered by tests.~~
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## ~~M6 — MVC: Controllers, Views, Templates~~
|
## ~~M6 — MVC: Controllers, Views, Templates~~
|
||||||
* ~~Tasks:~~
|
* ~~Tasks:~~
|
||||||
* ~~Controller base class and conventions (request/response helpers).~~
|
* ~~Controller base class and conventions (request/response helpers).~~
|
||||||
|
|
@ -58,6 +100,8 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* ~~Acceptance:~~
|
* ~~Acceptance:~~
|
||||||
* ~~Example page rendered through View → Template; API coexists with full‑site rendering.~~
|
* ~~Example page rendered through View → Template; API coexists with full‑site rendering.~~
|
||||||
* ~~Rendering works via RendererInterface and can be swapped (e.g., Eyrie → Twig demo) with only configuration/provider changes.~~
|
* ~~Rendering works via RendererInterface and can be swapped (e.g., Eyrie → Twig demo) with only configuration/provider changes.~~
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## ~~M7 — Modules (Django‑style app structure)~~
|
## ~~M7 — Modules (Django‑style app structure)~~
|
||||||
* ~~Tasks:~~
|
* ~~Tasks:~~
|
||||||
* ~~Define module filesystem layout (Nested Controllers/Views/Services/Models/Templates/Routes/Tests).~~
|
* ~~Define module filesystem layout (Nested Controllers/Views/Services/Models/Templates/Routes/Tests).~~
|
||||||
|
|
@ -73,6 +117,8 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* ~~Acceptance:~~
|
* ~~Acceptance:~~
|
||||||
* ~~Creating a module with the CLI makes it discoverable; routes/templates work without manual wiring.~~
|
* ~~Creating a module with the CLI makes it discoverable; routes/templates work without manual wiring.~~
|
||||||
* ~~Switching `ORM_DRIVER` between `pairity` and `eloquent` requires no changes to services/controllers; providers bind repository interfaces to driver implementations.~~
|
* ~~Switching `ORM_DRIVER` between `pairity` and `eloquent` requires no changes to services/controllers; providers bind repository interfaces to driver implementations.~~
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## ~~M8 — Database access, migrations, and seeds~~
|
## ~~M8 — Database access, migrations, and seeds~~
|
||||||
* ~~Tasks:~~
|
* ~~Tasks:~~
|
||||||
* ~~Integrate `getphred/pairity` for ORM/migrations/seeds.~~
|
* ~~Integrate `getphred/pairity` for ORM/migrations/seeds.~~
|
||||||
|
|
@ -86,6 +132,8 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* ~~Acceptance:~~
|
* ~~Acceptance:~~
|
||||||
* ~~Running migrations modifies a test database; seeds populate sample data; CRUD demo works.~~
|
* ~~Running migrations modifies a test database; seeds populate sample data; CRUD demo works.~~
|
||||||
* ~~All persistence usage in examples goes through Orm contracts; can be swapped (Pairity → Doctrine adapter demo optional).~~
|
* ~~All persistence usage in examples goes through Orm contracts; can be swapped (Pairity → Doctrine adapter demo optional).~~
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## ~~M9 — CLI (phred) and scaffolding~~
|
## ~~M9 — CLI (phred) and scaffolding~~
|
||||||
* ~~Tasks:~~
|
* ~~Tasks:~~
|
||||||
* ~~Implement Symfony Console app in `bin/phred`.~~ ✓
|
* ~~Implement Symfony Console app in `bin/phred`.~~ ✓
|
||||||
|
|
@ -93,6 +141,8 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* ~~Utility commands: `test[:<module>]`, `run`, `db:backup`, `db:restore`.~~ ✓
|
* ~~Utility commands: `test[:<module>]`, `run`, `db:backup`, `db:restore`.~~ ✓
|
||||||
* ~~Acceptance:~~
|
* ~~Acceptance:~~
|
||||||
* ~~Commands generate files with correct namespaces/paths and pass basic smoke tests.~~
|
* ~~Commands generate files with correct namespaces/paths and pass basic smoke tests.~~
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## ~~M10 — Security middleware and auth primitives~~
|
## ~~M10 — Security middleware and auth primitives~~
|
||||||
* ~~Tasks:~~
|
* ~~Tasks:~~
|
||||||
* ~~Add CORS, Secure Headers middlewares; optional CSRF for template routes.~~ ✓
|
* ~~Add CORS, Secure Headers middlewares; optional CSRF for template routes.~~ ✓
|
||||||
|
|
@ -101,6 +151,8 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* ~~Bind FeatureFlagClientInterface with a default adapter (Flagpole); add small sample usage and env config.~~ ✓
|
* ~~Bind FeatureFlagClientInterface with a default adapter (Flagpole); add small sample usage and env config.~~ ✓
|
||||||
* ~~Acceptance:~~
|
* ~~Acceptance:~~
|
||||||
* ~~CORS preflight and secured endpoints behave as configured; JWT‑protected route example works.~~ ✓
|
* ~~CORS preflight and secured endpoints behave as configured; JWT‑protected route example works.~~ ✓
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## ~~M11 — Logging, HTTP client, and filesystem~~
|
## ~~M11 — Logging, HTTP client, and filesystem~~
|
||||||
* ~~Tasks:~~
|
* ~~Tasks:~~
|
||||||
* ~~Monolog setup with handlers and processors (request ID, memory, timing).~~ ✓
|
* ~~Monolog setup with handlers and processors (request ID, memory, timing).~~ ✓
|
||||||
|
|
@ -108,18 +160,25 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* ~~Flysystem integration with local adapter; abstraction for storage disks.~~ ✓
|
* ~~Flysystem integration with local adapter; abstraction for storage disks.~~ ✓
|
||||||
* ~~Standardize all core service providers with robust driver validation (similar to OrmServiceProvider).~~ ✓
|
* ~~Standardize all core service providers with robust driver validation (similar to OrmServiceProvider).~~ ✓
|
||||||
* ~~Opportunity Radar: Multiple storage disks, log channel management, and HTTP client middleware.~~ ✓
|
* ~~Opportunity Radar: Multiple storage disks, log channel management, and HTTP client middleware.~~ ✓
|
||||||
|
* ~~Opportunity Radar 2: Storage Disk "Cloud" Adapters (S3), Advanced HTTP Middleware (Circuit Breaker), and Log Alerting (Slack/Sentry).~~ ✓
|
||||||
|
* ~~Opportunity Radar 3: Githook Integration, Breadcrumb Automation, and TOC for MILESTONES.md.~~ ✓
|
||||||
* ~~Acceptance:~~
|
* ~~Acceptance:~~
|
||||||
* ~~Logs include correlation IDs; sample outbound HTTP call via client; file upload/storage demo works.~~ ✓
|
* ~~Logs include correlation IDs; sample outbound HTTP call via client; file upload/storage demo works.~~ ✓
|
||||||
## M12 — Serialization/validation utilities and pagination
|
|
||||||
* Tasks:
|
[↑ Back to Top](#table-of-contents)
|
||||||
* REST default: Symfony Serializer normalizers/encoders; document extension points.
|
## ~~M12 — Serialization/validation utilities and pagination~~
|
||||||
* Add simple validation layer using `Phred\Http\Middleware\Middleware` base.
|
* ~~Tasks:~~
|
||||||
* Pagination helpers (links/meta), REST and JSON:API compatible outputs.
|
* ~~REST default: Symfony Serializer normalizers/encoders; document extension points.~~ ✓
|
||||||
* URL extension negotiation: add XML support
|
* ~~Add simple validation layer using `Phred\Http\Middleware\Middleware` base.~~ ✓
|
||||||
* Provide `XmlResponseFactory` (or encoder) and integrate with negotiation.
|
* ~~Pagination helpers (links/meta), REST and JSON:API compatible outputs.~~ ✓
|
||||||
* Enable `xml` in `URL_EXTENSION_WHITELIST` by default.
|
* ~~URL extension negotiation: add XML support~~ ✓
|
||||||
* Acceptance:
|
* ~~Provide `XmlResponseFactory` (or encoder) and integrate with negotiation.~~ ✓
|
||||||
* Example endpoint validates input, returns 422 with details; paginated listing includes links/meta.
|
* ~~Enable `xml` in `URL_EXTENSION_WHITELIST` by default.~~ ✓
|
||||||
|
* ~~Opportunity Radar: Storage URL generation, Circuit Breaker persistence (PSR-16), and HTTP client profiling.~~ ✓
|
||||||
|
* ~~Acceptance:~~
|
||||||
|
* ~~Example endpoint validates input, returns 422 with details; paginated listing includes links/meta.~~ ✓
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## M13 — OpenAPI and documentation
|
## M13 — OpenAPI and documentation
|
||||||
* Tasks:
|
* Tasks:
|
||||||
* Integrate `zircote/swagger-php` annotations.
|
* Integrate `zircote/swagger-php` annotations.
|
||||||
|
|
@ -127,6 +186,8 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* Document auth, pagination, error formats.
|
* Document auth, pagination, error formats.
|
||||||
* Acceptance:
|
* Acceptance:
|
||||||
* Generated OpenAPI document validates; matches sample endpoints.
|
* Generated OpenAPI document validates; matches sample endpoints.
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## M14 — Testing, quality, and DX
|
## M14 — Testing, quality, and DX
|
||||||
* Tasks:
|
* Tasks:
|
||||||
* Establish testing structure with Codeception (unit, integration, API suites).
|
* Establish testing structure with Codeception (unit, integration, API suites).
|
||||||
|
|
@ -138,6 +199,8 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* `composer test` runs green across suites; static analysis passes.
|
* `composer test` runs green across suites; static analysis passes.
|
||||||
* CLI tests run via TestRunnerInterface;
|
* CLI tests run via TestRunnerInterface;
|
||||||
* CLI tests run green per module and across suites.
|
* CLI tests run green per module and across suites.
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## M15 — Caching and performance (optional default)
|
## M15 — Caching and performance (optional default)
|
||||||
* Tasks:
|
* Tasks:
|
||||||
* Provide `PSR-16` cache interface binding; suggest `symfony/cache` when enabled.
|
* Provide `PSR-16` cache interface binding; suggest `symfony/cache` when enabled.
|
||||||
|
|
@ -145,6 +208,8 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* Rate limiting middleware (token bucket) suggestion/integration point.
|
* Rate limiting middleware (token bucket) suggestion/integration point.
|
||||||
* Acceptance:
|
* Acceptance:
|
||||||
* Sample endpoint demonstrates cached responses and conditional requests.
|
* Sample endpoint demonstrates cached responses and conditional requests.
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## M16 — Production hardening and deployment
|
## M16 — Production hardening and deployment
|
||||||
* Tasks:
|
* Tasks:
|
||||||
* Config for envs (dev/test/stage/prod), error verbosity, trusted proxies/hosts.
|
* Config for envs (dev/test/stage/prod), error verbosity, trusted proxies/hosts.
|
||||||
|
|
@ -152,12 +217,16 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* Healthcheck endpoint, readiness/liveness probes.
|
* Healthcheck endpoint, readiness/liveness probes.
|
||||||
* Acceptance:
|
* Acceptance:
|
||||||
* Containerized demo serves both API and template pages; healthchecks pass.
|
* Containerized demo serves both API and template pages; healthchecks pass.
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## M17 — JSON:API enhancements (optional package)
|
## M17 — JSON:API enhancements (optional package)
|
||||||
* Tasks:
|
* Tasks:
|
||||||
* If enabled, integrate `neomerx/json-api` fully: includes, sparse fieldsets, relationships, sorting, filtering, pagination params.
|
* If enabled, integrate `neomerx/json-api` fully: includes, sparse fieldsets, relationships, sorting, filtering, pagination params.
|
||||||
* Adapters/Schema providers per resource type.
|
* Adapters/Schema providers per resource type.
|
||||||
* Acceptance:
|
* Acceptance:
|
||||||
* JSON:API conformance tests for selected endpoints pass; docs updated.
|
* JSON:API conformance tests for selected endpoints pass; docs updated.
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## M18 — Examples and starter template
|
## M18 — Examples and starter template
|
||||||
* Tasks:
|
* Tasks:
|
||||||
* Create `examples/blog` module showcasing controllers, views, templates, ORM, auth, pagination, and both API formats.
|
* Create `examples/blog` module showcasing controllers, views, templates, ORM, auth, pagination, and both API formats.
|
||||||
|
|
@ -165,18 +234,34 @@ Phred supports REST and JSON:API via env setting; batteries-included defaults, s
|
||||||
* Provide `composer create-project` skeleton template instructions.
|
* Provide `composer create-project` skeleton template instructions.
|
||||||
* Acceptance:
|
* Acceptance:
|
||||||
* New users can scaffold a working app in minutes following README.
|
* New users can scaffold a working app in minutes following README.
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## M19 — Documentation site
|
## M19 — Documentation site
|
||||||
* Tasks:
|
* Tasks:
|
||||||
* Expand README into a docs site (MkDocs or similar): getting started, concepts, reference, guides.
|
* Build the official documentation site (getphred.com) using the Phred framework.
|
||||||
|
* Internal Documentation API: Design a "Documentation Module" that parses Markdown files from the repo to serve them dynamically.
|
||||||
|
* ~~Automated TOC Generation: Script to regenerate SPECS.md Table of Contents.~~ ✓
|
||||||
* Versioned docs and upgrade notes.
|
* Versioned docs and upgrade notes.
|
||||||
* Acceptance:
|
* Acceptance:
|
||||||
* Docs published; links in README; examples maintained.
|
* Docs published; links in README; examples maintained.
|
||||||
## M20 — Governance and roadmap tracking
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
|
## M20 — Dynamic Command Help
|
||||||
|
* Tasks:
|
||||||
|
* Implement a `docs` command in `phred` (e.g., `php phred docs <command>`) that opens the relevant documentation page in the user's browser.
|
||||||
|
* Build the `docs` command logic after the documentation site (getphred.com) is functional.
|
||||||
|
* Acceptance:
|
||||||
|
* `php phred docs create:module` opens the correct URL in the default browser.
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
|
## M21 — Governance and roadmap tracking
|
||||||
* Tasks:
|
* Tasks:
|
||||||
* Define contribution guide, issue templates, RFC process for changes.
|
* Define contribution guide, issue templates, RFC process for changes.
|
||||||
* Public roadmap (this milestone list) tracked as GitHub Projects/Issues.
|
* Public roadmap (this milestone list) tracked as GitHub Projects/Issues.
|
||||||
* Acceptance:
|
* Acceptance:
|
||||||
* Contributors can propose features via RFC; roadmap is visible and updated.
|
* Contributors can propose features via RFC; roadmap is visible and updated.
|
||||||
|
|
||||||
|
[↑ Back to Top](#table-of-contents)
|
||||||
## Notes on sequencing and parallelization
|
## Notes on sequencing and parallelization
|
||||||
* M0–M4 are critical path for the HTTP core and should be completed sequentially.
|
* M0–M4 are critical path for the HTTP core and should be completed sequentially.
|
||||||
* M5–M8 can progress in parallel with M9 (CLI) once the kernel is stable.
|
* M5–M8 can progress in parallel with M9 (CLI) once the kernel is stable.
|
||||||
|
|
|
||||||
387
README.md
387
README.md
|
|
@ -1,329 +1,94 @@
|
||||||
# Phred
|
# Phred
|
||||||
|
|
||||||
A PHP MVC framework:
|
A PHP MVC framework intended for projects of all sizes, designed for both solo and team development.
|
||||||
* Intended for projects of all sizes, and solo or team development.
|
|
||||||
* The single router call per controller style makes it easy for teamwork without stepping on each others toes.
|
|
||||||
* REQUIREMENTS
|
|
||||||
* PHP 8.1+
|
|
||||||
* Primarily meant for Apache/Nginx webservers, will look into supporting other webservers in the future.
|
|
||||||
* PSR-4 autoloading.
|
|
||||||
* Installed through Composer (`composer create-project getphred/phred`)
|
|
||||||
* Environment variables (.env) for configuration.
|
|
||||||
* Supports two API formats (with content negotiation)
|
|
||||||
* Pragmatic REST (default)
|
|
||||||
* JSON:API
|
|
||||||
* Choose via .env:
|
|
||||||
* `API_FORMAT=rest` (plain JSON responses, RFC7807 error format)
|
|
||||||
* `API_FORMAT=jsonapi` (JSON:API compliant documents and error objects)
|
|
||||||
* Or negotiate per request using the `Accept` header:
|
|
||||||
* `Accept: application/vnd.api+json` forces JSON:API for that request
|
|
||||||
* TESTING environment variables (.env)
|
|
||||||
* `TEST_RUNNER=codeception`
|
|
||||||
* `TEST_PATH=tests`
|
|
||||||
* `TEST_PATH` is relative to both project root and each module root.
|
|
||||||
* Dependency Injection
|
|
||||||
* Fully Pluggable, but ships with defaults:
|
|
||||||
* Pluggability model (M5)
|
|
||||||
* Core depends on Phred contracts and PSRs; concrete implementations are provided by Service Providers.
|
|
||||||
* Providers implement `Phred\Support\Contracts\ServiceProviderInterface` with `register(ContainerBuilder)` and `boot(Container)` methods.
|
|
||||||
* Providers are loaded in deterministic order: core → app → modules, configured in `config/providers.php`.
|
|
||||||
* Swap packages by changing `.env` / `config/app.php` drivers and enabling a provider.
|
|
||||||
* Driver keys (examples)
|
|
||||||
* `ORM_DRIVER=pairity|doctrine`
|
|
||||||
* `TEMPLATE_DRIVER=eyrie|twig|plates`
|
|
||||||
* `FLAGS_DRIVER=flagpole|unleash`
|
|
||||||
* `TEST_RUNNER=codeception`
|
|
||||||
* Primary contracts
|
|
||||||
* `Template\Contracts\RendererInterface`
|
|
||||||
* `Orm\Contracts\ConnectionInterface` (or repositories in future milestones)
|
|
||||||
* `Flags\Contracts\FeatureFlagClientInterface`
|
|
||||||
* `Testing\Contracts\TestRunnerInterface`.
|
|
||||||
* Default Plug-ins
|
|
||||||
* Feature Flags through `getphred/flagpole`
|
|
||||||
* ORM through `getphred/pairity` (handles migrations, seeds, and db access)
|
|
||||||
* Unit Testing through `codeception/codeception`
|
|
||||||
* Testing is provided as a CLI dev capability only; it is not part of the HTTP request lifecycle.
|
|
||||||
* Template Engine through `getphred/eyrie`
|
|
||||||
* Other dependencies:
|
|
||||||
* Dependency Injection through `php-di/php-di`
|
|
||||||
* Static Analysis through `phpstan/phpstan`
|
|
||||||
* Code Style Enforcement through `friendsofphp/php-cs-fixer`
|
|
||||||
* Logging through `monolog/monolog`
|
|
||||||
* Config and environment handling through `vlucas/phpdotenv`
|
|
||||||
* HTTP client through `guzzlehttp/guzzle`
|
|
||||||
* URL extension negotiation (optional)
|
|
||||||
* Opt-in middleware that parses a trailing URL extension and hints content negotiation.
|
|
||||||
* Enable via env: `URL_EXTENSION_NEGOTIATION=true` (default true)
|
|
||||||
* Control allowed extensions via: `URL_EXTENSION_WHITELIST="json|php|none"`
|
|
||||||
* Defaults to `json|php|none`. XML support will be added in M12.
|
|
||||||
* Examples:
|
|
||||||
* `/users/1.json` → JSON response
|
|
||||||
* `/users/1` or `/users/1.php` → HTML (views) by convention
|
|
||||||
* Extensible: future formats can be added with a factory and whitelisting.
|
|
||||||
* CONTROLLERS
|
|
||||||
* Invokable controllers (Actions),
|
|
||||||
* Single router call per controller,
|
|
||||||
* `public function __invoke(Request $request)` method entry point on controller class,
|
|
||||||
* Response helpers via dependency injection:
|
|
||||||
* Inject `Phred\Http\Contracts\ApiResponseFactoryInterface` to build responses consistently across formats.
|
|
||||||
* The factory is negotiated per request (env default or `Accept` header) and sets appropriate `Content-Type`.
|
|
||||||
* Common methods: `ok(array $data)`, `created(array $data, ?string $location)`, `noContent()`, `error(int $status, string $title, ?string $detail, array $extra = [])`.
|
|
||||||
* Example:
|
|
||||||
```php
|
|
||||||
use Phred\Http\Contracts\ApiResponseFactoryInterface as Responses;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
|
||||||
use Phred\Http\Middleware\ContentNegotiationMiddleware as Negotiation;
|
|
||||||
|
|
||||||
final class ExampleController {
|
## Requirements
|
||||||
public function __construct(private Responses $responses) {}
|
|
||||||
public function __invoke(Request $request) {
|
|
||||||
$format = $request->getAttribute(Negotiation::ATTR_API_FORMAT, 'rest');
|
|
||||||
return $this->responses->ok(['format' => $format]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* MVC controller bases (M6)
|
|
||||||
* For API endpoints inside modules, extend `Phred\Mvc\APIController` and use response helpers:
|
|
||||||
```php
|
|
||||||
use Phred\Mvc\APIController;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
|
||||||
|
|
||||||
final class UserShowController extends APIController {
|
* **PHP**: 8.2+
|
||||||
public function __invoke(Request $request) {
|
* **Web Server**: Apache/Nginx (recommended)
|
||||||
$user = ['id' => 123, 'name' => 'Ada'];
|
* **Package Manager**: Composer
|
||||||
return $this->ok(['user' => $user]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* For HTML endpoints inside modules, extend `Phred\Mvc\ViewController` and delegate to a module `View`:
|
|
||||||
```php
|
|
||||||
use Phred\Mvc\ViewController;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
|
||||||
|
|
||||||
final class HomePageController extends ViewController {
|
## Installation
|
||||||
public function __invoke(Request $request, HomePageView $view) {
|
|
||||||
// domain data (normally from a Service)
|
|
||||||
$data = ['title' => 'Welcome', 'name' => 'world'];
|
|
||||||
// Use the view's default template by omitting the template param
|
|
||||||
return $this->renderView($view, $data);
|
|
||||||
// Or override template explicitly via 3rd param:
|
|
||||||
// return $this->renderView($view, $data, 'home');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* VIEWS
|
|
||||||
* Classes for data manipulation/preparation before rendering Templates,
|
|
||||||
* `$this->render(<template_name>, <data_array>);` to render a template.
|
|
||||||
* Base class (M6): extend `Phred\Mvc\View` in your module and optionally override `transformData()`:
|
|
||||||
```php
|
|
||||||
use Phred\Mvc\View;
|
|
||||||
|
|
||||||
final class HomePageView extends View {
|
Install Phred via Composer:
|
||||||
protected string $template = 'home'; // default template
|
|
||||||
protected function transformData(array $data): array {
|
|
||||||
$data['upper'] = strtoupper($data['name'] ?? '');
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* With the default Eyrie renderer, a simple template string `"<h1>Hello {{upper}}</h1>"` would produce `<h1>Hello WORLD</h1>`.
|
|
||||||
* Template selection conventions (M6)
|
|
||||||
* Controllers always call `renderView($view, $data, ?$templateOverride)`:
|
|
||||||
- Use default template: `renderView($view, $data)` (no third parameter)
|
|
||||||
- Override template explicitly: `renderView($view, $data, 'template_name')`
|
|
||||||
* Views own default template selection and presentation logic:
|
|
||||||
- Declare `protected string $template = 'default_name';` or override `defaultTemplate()` for dynamic selection
|
|
||||||
- The `View` decides which template to use when the controller does not pass an override
|
|
||||||
* Rationale: keeps template/presentation decisions in the View layer; controllers only make explicit overrides when necessary (flags, A/B tests, special flows).
|
|
||||||
* SERVICES
|
|
||||||
* for business logic.
|
|
||||||
* MODULES (M7)
|
|
||||||
* Django-style: all user Controllers, Views, Templates, Services, etc. live inside modules.
|
|
||||||
* Suggested module layout (ORM-agnostic):
|
|
||||||
- `modules/<Module>/Controllers/`
|
|
||||||
- `modules/<Module>/Views/`
|
|
||||||
- `modules/<Module>/Templates/`
|
|
||||||
- `modules/<Module>/Services/`
|
|
||||||
- `modules/<Module>/Models/` (domain models, ORM-neutral)
|
|
||||||
- `modules/<Module>/Repositories/` (interfaces consumed by services)
|
|
||||||
- `modules/<Module>/Persistence/Pairity/` (DAOs, DTOs, mappers, repo implementations)
|
|
||||||
- `modules/<Module>/Persistence/Eloquent/` (Eloquent models, repo implementations)
|
|
||||||
- `modules/<Module>/Database/Migrations/` (canonical migrations for the module)
|
|
||||||
- `modules/<Module>/Routes/web.php` and `api.php`
|
|
||||||
- `modules/<Module>/Providers/*ServiceProvider.php`
|
|
||||||
* Swap ORM driver (`ORM_DRIVER=pairity|eloquent`) without changing services/controllers: providers bind repository interfaces to driver-specific implementations. Migrations remain a single canonical set per module.
|
|
||||||
* Creating a Module
|
|
||||||
- With prompt (interactive):
|
|
||||||
```bash
|
|
||||||
php phred create:module Blog
|
|
||||||
# Enter URL prefix for module 'Blog' [/blog]:
|
|
||||||
```
|
|
||||||
- The command will scaffold `modules/Blog/*`, register the provider in `config/providers.php` (modules section), and append an inclusion snippet to `routes/web.php` mounting the module at `/blog`.
|
|
||||||
- Without prompt (explicit prefix argument):
|
|
||||||
```bash
|
|
||||||
php phred create:module Blog /blog
|
|
||||||
# or
|
|
||||||
php phred create:module Blog --prefix=/blog
|
|
||||||
```
|
|
||||||
- After creation, add PSR-4 to `composer.json` and dump autoload:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Project\\\\Modules\\\\Blog\\\\": "modules/Blog/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
```bash
|
|
||||||
composer dump-autoload
|
|
||||||
```
|
|
||||||
- Route inclusion pattern in `routes/web.php` (added automatically):
|
|
||||||
```php
|
|
||||||
use Phred\\Http\\Routing\\RouteGroups;
|
|
||||||
use Phred\\Http\\Router;
|
|
||||||
|
|
||||||
// Module 'Blog' mounted at '/blog'
|
```bash
|
||||||
RouteGroups::include($router, '/blog', function (Router $router) {
|
composer create-project getphred/phred
|
||||||
/** @noinspection PhpIncludeInspection */
|
|
||||||
(static function ($router) { require __DIR__ . '/../modules/Blog/Routes/web.php'; })($router);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
- Define module-local routes relative to the module in `modules/Blog/Routes/web.php`:
|
|
||||||
```php
|
|
||||||
use Phred\\Http\\Router;
|
|
||||||
use Project\\Modules\\Blog\\Controllers as C;
|
|
||||||
|
|
||||||
$router->get('/', C\\HomeController::class); // -> /blog
|
|
||||||
$router->get('/posts', C\\PostIndexController::class); // -> /blog/posts
|
|
||||||
```
|
|
||||||
* SERVICE PROVIDERS (M5)
|
|
||||||
* for dependency injection and runtime bootstrapping.
|
|
||||||
* Configure providers in `config/providers.php`:
|
|
||||||
```php
|
|
||||||
return [
|
|
||||||
'core' => [
|
|
||||||
Phred\Providers\Core\RoutingServiceProvider::class,
|
|
||||||
Phred\Providers\Core\TemplateServiceProvider::class,
|
|
||||||
Phred\Providers\Core\OrmServiceProvider::class,
|
|
||||||
Phred\Providers\Core\FlagsServiceProvider::class,
|
|
||||||
Phred\Providers\Core\TestingServiceProvider::class,
|
|
||||||
],
|
|
||||||
'app' => [
|
|
||||||
Phred\Providers\AppServiceProvider::class,
|
|
||||||
],
|
|
||||||
'modules' => [],
|
|
||||||
];
|
|
||||||
```
|
|
||||||
* Add routes from a provider using the `RouteRegistry` helper:
|
|
||||||
```php
|
|
||||||
use Phred\Http\Routing\RouteRegistry;
|
|
||||||
use Phred\Http\Router;
|
|
||||||
|
|
||||||
RouteRegistry::add(static function ($collector, Router $router): void {
|
|
||||||
$router->get('/hello', fn() => ['message' => 'Hello from a provider']);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
* Select drivers via env or `config/app.php` under `drivers`:
|
|
||||||
- `TEMPLATE_DRIVER=eyrie`
|
|
||||||
- `ORM_DRIVER=pairity`
|
|
||||||
- `FLAGS_DRIVER=flagpole`
|
|
||||||
- `TEST_RUNNER=codeception`
|
|
||||||
* Defaults are provided by core providers and can be swapped by changing these keys and adding alternate providers.
|
|
||||||
* MIGRATIONS
|
|
||||||
* for database changes.
|
|
||||||
* Modular separation, similar to Django apps.
|
|
||||||
* Nested Models
|
|
||||||
* Nested Controllers
|
|
||||||
* Nested Views
|
|
||||||
* Nested Services
|
|
||||||
* Nested Migrations
|
|
||||||
* Nested Service Providers
|
|
||||||
* Nested Routes
|
|
||||||
* Nested Templates
|
|
||||||
* Nested Tests
|
|
||||||
* CLI Helper called phred
|
|
||||||
* `php phred create:command <name>` // Creates a CLI command under `console/commands
|
|
||||||
* `php phred create:module <name>` // Creates a module
|
|
||||||
* `php phred create:<module>:controller` // Creates a controller in the specified module
|
|
||||||
* `php phred create:<module>:model` // Creates a model in the specified module
|
|
||||||
* `php phred create:<module>:migration` // Creates a migration in the specified module
|
|
||||||
* `php phred create:<module>:seed` // Creates a seeder in the specified module
|
|
||||||
* `php phred create:<module>:test` // Creates a test in the specified module
|
|
||||||
* `php phred create:<module>:view` / Creates a view in the specified module
|
|
||||||
* `php phred db:backup` // Backup the database
|
|
||||||
* `php phred db:restore -f <db_backup_file>` // Restore the database from the specified backup file
|
|
||||||
* `php phred migrate [-m <module>]` // Migrate entire project or module
|
|
||||||
* `php phred migration:rollback [-m <module>]` // Rollback entire project or module
|
|
||||||
* `php phred seed`
|
|
||||||
* `php phred seed:rollback`
|
|
||||||
* `php phred test[:<module>]` // Test entire project or module
|
|
||||||
* Runs tests using the configured test runner (dev only).
|
|
||||||
* Requires `require-dev` dependencies.
|
|
||||||
* `php phred run [-p <port>]`
|
|
||||||
* Spawns a local PHP webserver on port 8000 (unless specified otherwise using `-p`)
|
|
||||||
* CLI Helper is extendable through CLI Commands.
|
|
||||||
|
|
||||||
Command discovery
|
|
||||||
|
|
||||||
* Core commands (bundled with Phred) are discovered from `src/commands`.
|
|
||||||
* User/project commands are discovered from `console/commands` in your project root.
|
|
||||||
|
|
||||||
Run the CLI:
|
|
||||||
|
|
||||||
```
|
|
||||||
php phred list
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Add your own command by creating a PHP file under `console/commands`, returning an instance of `Phred\Console\Command` (or an anonymous class extending it).
|
## Getting Started
|
||||||
|
|
||||||
(Or by running `php phred create:command <name>`)
|
### Creating a Module
|
||||||
|
|
||||||
Example:
|
Phred uses a modular (Django-style) architecture. All your application logic lives inside modules.
|
||||||
|
|
||||||
```
|
To scaffold a new module:
|
||||||
<?php
|
|
||||||
use Phred\Console\Command;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface as Input;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface as Output;
|
|
||||||
|
|
||||||
return new class extends Command {
|
```bash
|
||||||
protected string $command = 'hello:world';
|
php phred create:module Blog
|
||||||
protected string $description = 'Example user command';
|
|
||||||
public function handle(Input $in, Output $out): int { $out->writeln('Hello!'); return 0; }
|
|
||||||
};
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Configuration and environment
|
This will create the module structure under `modules/Blog`, register the service provider, and mount the routes.
|
||||||
|
|
||||||
- Phred uses `vlucas/phpdotenv` to load a `.env` file from your project root (loaded in `bootstrap/app.php`).
|
After creating a module, update your `composer.json` to include the new namespace:
|
||||||
- Access configuration anywhere via `Phred\Support\Config::get(<key>, <default>)`.
|
|
||||||
- Precedence: environment variables > config files > provided default.
|
|
||||||
- Keys may be provided in either UPPER_SNAKE (e.g., `APP_ENV`) or dot.notation (e.g., `app.env`).
|
|
||||||
- Config files live under `config/*.php` and return arrays; dot keys are addressed as `<file>.<path>` (e.g., `app.timezone`).
|
|
||||||
|
|
||||||
Common keys
|
```json
|
||||||
|
{
|
||||||
- `APP_ENV` (default from config/app.php: `local`)
|
"autoload": {
|
||||||
- `APP_DEBUG` (`true`/`false`)
|
"psr-4": {
|
||||||
- `APP_TIMEZONE` (default `UTC`)
|
"Project\\\\Modules\\\\Blog\\\\": "modules/Blog/"
|
||||||
- `API_FORMAT` (`rest` | `jsonapi`; default `rest`)
|
}
|
||||||
|
}
|
||||||
API formats and negotiation
|
}
|
||||||
|
|
||||||
- Middleware `ContentNegotiationMiddleware` determines the active API format per request.
|
|
||||||
- Precedence:
|
|
||||||
1. `Accept: application/vnd.api+json` → JSON:API
|
|
||||||
2. `.env`/config `API_FORMAT` (fallback to `rest`)
|
|
||||||
- The chosen format is stored on the request as `phred.api_format` and used by the injected `ApiResponseFactoryInterface` to produce the correct response shape and `Content-Type`.
|
|
||||||
- Demo endpoint: `GET /_phred/format` responds with the active format; `GET /_phred/health` returns a simple JSON 200.
|
|
||||||
|
|
||||||
Examples
|
|
||||||
|
|
||||||
```php
|
|
||||||
use Phred\Support\Config;
|
|
||||||
|
|
||||||
$env = Config::get('APP_ENV', 'local'); // reads from env, then config/app.php, else 'local'
|
|
||||||
$tz = Config::get('app.timezone', 'UTC'); // reads nested key from config files
|
|
||||||
$fmt = strtolower(Config::get('API_FORMAT', 'rest'));
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Then run:
|
||||||
|
```bash
|
||||||
|
composer dump-autoload
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running the Application
|
||||||
|
|
||||||
|
Start the local development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php phred run
|
||||||
|
```
|
||||||
|
|
||||||
|
The application will be available at `http://localhost:8000`.
|
||||||
|
|
||||||
|
## CLI Usage (phred)
|
||||||
|
|
||||||
|
The `phred` binary provides several utility and scaffolding commands.
|
||||||
|
|
||||||
|
### Generators
|
||||||
|
* `php phred create:module <name>` — Create a new module.
|
||||||
|
* `php phred create:command <name>` — Create a custom CLI command.
|
||||||
|
* `php phred create:<module>:controller <name>` — Create a controller.
|
||||||
|
* `php phred create:<module>:view <name>` — Create a view and template.
|
||||||
|
* `php phred create:<module>:model <name>` — Create a domain model.
|
||||||
|
* `php phred create:<module>:migration <name>` — Create a migration.
|
||||||
|
* `php phred create:<module>:seed <name>` — Create a database seeder.
|
||||||
|
* `php phred create:<module>:test <name>` — Create a test.
|
||||||
|
|
||||||
|
### Database
|
||||||
|
* `php phred migrate` — Run database migrations.
|
||||||
|
* `php phred migration:rollback` — Rollback migrations.
|
||||||
|
* `php phred seed` — Seed the database.
|
||||||
|
* `php phred db:backup` — Backup the database.
|
||||||
|
* `php phred db:restore` — Restore the database.
|
||||||
|
|
||||||
|
### Testing & Utilities
|
||||||
|
* `php phred test` — Run tests for the entire project.
|
||||||
|
* `php phred test:<module>` — Run tests for a specific module.
|
||||||
|
* `php phred list` — List all available commands.
|
||||||
|
|
||||||
|
## Technical Specifications
|
||||||
|
|
||||||
|
For detailed information on the framework architecture, service providers, configuration, and MVC components, please refer to:
|
||||||
|
|
||||||
|
👉 **[SPECS.md](./SPECS.md)** | [MILESTONES.md](./MILESTONES.md)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Phred is open-source software licensed under the MIT license.
|
||||||
|
|
|
||||||
161
SPECS.md
Normal file
161
SPECS.md
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
# 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';
|
||||||
|
});
|
||||||
|
```
|
||||||
Loading…
Reference in a new issue