jardiscore / app
Jardis App-Layer - HTTP delivery for Jardis domains: FastRoute router behind own interface, PSR-15 pipeline, canonical DomainResponse-to-PSR-7 mapper, kernel bootstrap bridge
Requires
- php: >=8.3
- jardiscore/kernel: ^2.0
- jardissupport/contract: ^2.1
- nikic/fast-route: ^1.3
- nyholm/psr7: ^1.8
- nyholm/psr7-server: ^1.1
- psr/http-factory: ^1
- psr/http-message: ^2
- psr/http-server-handler: ^1
- psr/http-server-middleware: ^1
Requires (Dev)
- ext-pdo: *
- jardissupport/data: ^1.0
- jardissupport/dbquery: ^1.0
- jardissupport/repository: ^1.0
- jardissupport/validation: ^1.0
- jardissupport/workflow: ^1.0
- middlewares/client-ip: ^2.1
- phpstan/phpstan: ^2.0.4
- phpunit/phpunit: ^11.0
- squizlabs/php_codesniffer: ^3.11.2
This package is auto-updated.
Last update: 2026-07-17 05:26:25 UTC
README
Part of Jardis — the Domain-Driven Design platform for PHP. You model your domain; Jardis generates the production-ready hexagonal code.
jardiscore/kernelis the runtime the generated code runs on; this package is the HTTP delivery layer around it.
The Request/Response-Handling offer for Jardis-generated domains. FastRoute
behind an own, narrow interface, a PSR-15 middleware pipeline, one canonical
DomainResponse → PSR-7 mapper, and a thin bootstrap bridge around the
Koffer (BuildDomainKernelFromEnv) — nothing more.
Bleiben ist der erwartete Normalfall — Wechseln ist die garantierte
Freiheit. No Jardis domain ever imports this package (a maschinell prüfbare
Struktur-Eigenschaft, not a promise — see Wandfreiheit
below); a fremd-framework can answer the exact same client-facing envelope
contract this package implements, without depending on it at all (see
examples/symfony-demo/).
Why Jardis App?
Between "an HTTP request arrives" and "$domain->…->process(…) gets called"
there was no Jardis offer — building a Jardis-backed HTTP API meant pulling
in Laravel or Symfony just for routing and response mapping. This package
closes that gap with a deliberately small core:
- FastRoute, but swappable.
nikic/fast-routesits behindContract\RouterInterface— an implementation detail, not a commitment. - PSR-15 pipeline. Global and per-route middleware, Chain-of-Responsibility ordering (global wraps route-specific), deterministic within each group. Any PSR-15-conformant ecosystem package (auth, CORS, request-id, …) runs without an adapter.
- One canonical mapper. Every
DomainResponseInterface— success or error, domain- or boundary-produced — becomes the same{status, data, errors, meta}JSON envelope (vendor/jardissupport/contract/docs/response-envelope.md). No consumer builds this translation by hand again. - A thin bootstrap bridge. Wraps the Koffer's own
BuildDomainKernelFromEnv(ENV →DomainKernel) and the Builder-generated domain composition (App/bootstrap.php) with the one thing missing: an HTTP entry point around them. - A defined boundary-error contract. 404/405 (with a spec-correct
Allowheader)/500 all answer in the same envelope as a domain error — a client never has to guess whether "404" came from the domain or from no route matching at all. - A Raw-Body invariant. The request body is read from
php://inputexactly once, into a seekable stream; JSON parsing is lazy and never replaces it —getBody()stays byte-identical for the whole pipeline (the webhook-HMAC case).
Wandfreiheit
The "no domain depends on this package" guarantee is a structural property,
not an example: tests/Acceptance/WallFreedomHarnessTest.php checks every
vendored domain's composer dependencies and namespace imports for a
dependency on jardiscore/app — none exists, and none may. examples/symfony-demo/
illustrates what that freedom buys a consumer: the same generated domain,
answering the same envelope contract, behind Symfony instead of this
package's own router — with zero jardiscore/app import anywhere in that
demo's composer.json or code.
Installation
composer require jardiscore/app
Quickstart
See docs/getting-started.md for the full,
runnable public/index.php recipe (install → ENV/Koffer-Bootstrap → domain
registration → first route + handler → start → first request — under 15
minutes with a prepared environment, K6). It also covers API versioning
(M9), the jardissupport/validation growth path, and the N1 deployment
stellschrauben (body-size limits, Trusted-Proxy, display_errors).
Examples
examples/basic/— the recipe above wired against a REAL Builder-generated domain (Ecommerce/Sales) over MySQL:GET/POST/PATCH /orders, the422rule-violation payload, 404/405/500 boundary cases, and a real PSR-15 ecosystem middleware.examples/symfony-demo/— the N3 austauschbarkeits-illustration: the same fixture domain behind a Symfony front controller, fulfilling the same envelope contract, without importing this package.
Requirements
- PHP
>=8.3 jardiscore/kernel ^2.0jardissupport/contract ^2.1
Related Packages
| Package | Purpose |
|---|---|
jardiscore/kernel |
The Koffer (DomainKernel) + ENV-Packer this package's bootstrap bridge builds on |
jardissupport/contract |
DomainResponseInterface, ResponseStatus, the response-envelope contract doc |
jardissupport/validation |
Object-graph validation — the growth path beyond the handler's own trivial type coercion (F8) |
Documentation
Full documentation, guides, and API reference:
License
Jardis is open source under the MIT License. Free for any purpose — commercial or non-commercial.
Jardis — Development with Passion Built by Headgent Development
AI-Assisted Development
This package ships with a skill for Claude Code, Cursor, Continue, and Aider. Install it in your consuming project:
composer require --dev jardis/dev-skills
More details: https://docs.jardis.io/en/skills