diff --git a/config/autoload/local.php.dist b/config/autoload/local.php.dist index 61e7f8df..1ff23477 100644 --- a/config/autoload/local.php.dist +++ b/config/autoload/local.php.dist @@ -80,7 +80,13 @@ return [ // and is routed in Light\App\RoutesDelegator. Re-adding it here registers the path twice. 'routes' => [ 'page' => [ - 'contact' => 'contact', + 'contact' => 'contact', + 'api' => 'api', + 'admin' => 'admin', + 'queue' => 'queue', + 'light' => 'light', + 'frontend' => 'frontend', + 'dotboost' => 'dotboost', ], ], 'twig' => [ diff --git a/src/App/templates/app/index.html.twig b/src/App/templates/app/index.html.twig index 0654e52f..97f2dcc4 100644 --- a/src/App/templates/app/index.html.twig +++ b/src/App/templates/app/index.html.twig @@ -119,6 +119,7 @@

REST APIs on a readable PSR-15 middleware pipeline - no kernel, no facades, no runtime magic. OAuth2, RBAC, and OpenAPI included.

+ Read more GitHub Demo Docs @@ -138,6 +139,7 @@

A ready-to-go admin skeleton - table-based CRUD screens for your records, plus the pieces for reports and dashboards.

+ Read more GitHub Demo Docs @@ -157,6 +159,7 @@

Background job processing for the platform - dispatch work from API or Admin and run it in a separate worker. Built on Symfony Messenger.

+ Read more GitHub Docs
@@ -187,11 +190,12 @@
-
Tooling · AI Context

Dotkernel Boost

+
Tooling · AI Context

Dotboost

Faster AI-assisted development, grounded in Dotkernel's own standards.

Dotkernel context for AI coding tools - current standards, architectural patterns, and framework idioms, so generated code matches the ecosystem instead of guessing at it.

+ Read more GitHub
@@ -222,6 +226,7 @@

The smallest complete Mezzio application - PSR-15 pipeline, routing, and templating, nothing to strip out. A real starting point for a simple site.

+ Read more GitHub Demo Docs @@ -241,6 +246,7 @@

A web starter skeleton for full-stack applications on Mezzio and Laminas - server-rendered Twig views, forms, sessions, and RBAC-guarded routes.

+ Read more GitHub Demo Docs diff --git a/src/Page/templates/page/admin.html.twig b/src/Page/templates/page/admin.html.twig new file mode 100644 index 00000000..5b499761 --- /dev/null +++ b/src/Page/templates/page/admin.html.twig @@ -0,0 +1,607 @@ +{% extends '@layout/default.html.twig' %} + +{% set routeName = 'page::admin' %} +{% set meta = { + title: 'Dotkernel Admin | Open-source PHP admin application', + description: 'Dotkernel Admin is an open-source admin application (skeleton) built on Mezzio, Laminas and Doctrine. ' + ~ 'Table-based record management, RBAC guards, CSRF-protected forms and 2FA, over the same Core as Dotkernel API.', +} %} + +{% block title %}Dotkernel Admin{% endblock %} + +{% block stylesheets %} + +{% endblock %} + +{% block content %} + +
+
+
+ Admin application · Server-rendered +

Dotkernel Admin

+

+ An open-source application skeleton for standing up the administration site behind your platform. + A fast, reliable way to manage the records in your database with a simple table-based approach, and + to build the reports and graphs that let you monitor what is happening - with the graphical + components for an intuitive experience already in place. +

+ +
+ PHP version for dotkernel/admin + Latest release of dotkernel/admin + License of dotkernel/admin + GitHub stars for dotkernel/admin +
+
+
Runtime Mezzio + Laminas
+
Templating Twig
+
License MIT
+
+
+ +
+
Request lifecycle
+
+ +
Sessiondot-session
+
Routerdot-router
+
Authenticationlaminas-authentication
+
RBAC guarddot-rbac-guard
+
Your handlerPSR-15
+
ResponseTwig template
+
+
+
+
+ +
+
+
+ What it is +

The back office, not a framework to learn

+

+ Dotkernel Admin is the complementary application of the Dotkernel Headless Platform: an independent + app built on the same Mezzio and Laminas foundation as Dotkernel API, sharing the same tech stack so + the two form one consistent system rather than two codebases that merely talk to each other. +

+

+ Authentication, role-based access control, CSRF-protected forms, validation, navigation and a + dashboard are already assembled. What you add is your own screens for your own entities. +

+
+ Extending the power of + +
+
+
+
+ +

Table-based record management

+
+ +
+ +

Every shipped form validated and CSRF-guarded

+
+ +
+ +

Shares the Core module with API

+
+ +
+ +

Twig templates, npm asset pipeline

+
+
+
+
+ +
+
+
+ What ships wired up +

The unglamorous parts, already done

+

Everything below works in a fresh install. The default modules are configured; your custom + functionality needs the same configuration entries, and the docs say exactly which ones.

+
+ +
+ +
+
+
Security · Access control

RBAC guards

+
+

Permissions declared in config, enforced per route handler.

+

+ dot-rbac and dot-rbac-guard work together: roles and their permissions + live in authorization.global.php, while + authorization-guards.global.php maps each route handler to the permissions it + requires. Add a route, add its rule - access control never drifts into your handlers. +

+
+ +
+
+
Security · 2FA

TOTP two-factor

+
+

A password plus a code that expires in 30 seconds.

+

+ dot-totp adds time-based one-time passwords following the industry standard: + administrators authenticate with their password and a 6-digit code from an authenticator app. + Installation is a documented set of forms, handlers, middleware and three new columns. +

+ +
+ +
+
+
Security · Forms

CSRF protection

+
+

A fresh token per render, on every form that ships.

+

+ Built from the laminas-form CSRF element, the laminas-session CSRF + validator and the formElement view helper. Tokens are not reusable between forms + and expire after a configurable timeout, defaulting to one hour. +

+
+ +
+
+
Input · Validation

Forms & input filters

+
+

Validation rules that live beside the form, not in the handler.

+

+ laminas-form bridges your domain models and the view layer, while + laminas-inputfilter normalizes and validates the submitted set. Every form in the + skeleton has its inputs filtered, so your own forms have a pattern to copy. +

+
+ +
+
+
Data · Persistence

Doctrine ORM

+
+

Migrations and fixtures, both driven from the CLI.

+

+ Doctrine ORM 3 and DBAL 4 over MariaDB or PostgreSQL, with UUID identifiers via + ramsey/uuid-doctrine. Generate a migration with + doctrine-migrations diff, apply it with migrate, then seed the tables + with bin/doctrine fixtures:execute. +

+
+ +
+
+
Wiring · DI

Attribute injection

+
+

Constructor injection declared where the constructor is.

+

+ dot-dependency-injection reads an #[Inject] attribute on the + constructor and resolves each listed dependency - including values from a configuration key, by + dot notation. Register the class against AttributedServiceFactory and you are done + writing factories by hand. +

+
+ +
+
+
Interface · Navigation

Menus & UI components

+
+

Configuration-driven menus, ready-made interface pieces.

+

+ dot-navigation defines and parses the top menu from + navigation.global.php. The Page module carries reusable dropdowns, + modal popups, error displays and tooltips; the Dashboard module holds the landing + page layout and its widgets. +

+
+ +
+
+
Operations · CLI

Commands & lock files

+
+

Cron-safe console commands out of the box.

+

+ dot-cli builds the console application on top of laminas-cli, writing lock files + into data/lock so a scheduled command cannot overlap with itself. GeoLite2 + databases sync through bin/cli.php geoip:synchronize, quiet mode included for + cron jobs. +

+
+ +
+
+
Operations · Mail & logs

Mail and error handling

+
+

Transactional mail configured in one file, errors in another.

+

+ dot-mail handles sendmail or SMTP delivery, sender identity and CC lists from + mail.global.php. dot-errorhandler writes daily log files to + log/, with the format set in error-handling.global.php. +

+
+
+
+
+ +
+
+
+ Structure +

Modules you can name before you read them

+

Admin follows PSR-4, with one folder per module. Each module keeps its handlers, input filters and + services together, plus a ConfigProvider and a RoutesDelegator - so the + second module you write looks like the first.

+
+ +
+ Shared domain layer + Core\Admin Core\App Core\Security + Core\Setting Core\User +

The Core module is a common codebase shared with the other applications in your project. Each + submodule holds its entities, repositories and its own ConfigProvider, so a user means the same + thing to the admin screen and to the API endpoint.

+
+ +
+
+

Admin

+

Managing the users that hold the admin role - the accounts stored in the + admin database table.

+
+
+

User

+

Managing the platform's own users, stored separately in the user table. Two + audiences, two models, no overloaded role column.

+
+
+

App

+

Core application functionality: authentication, rendering and error reporting.

+
+
+

Dashboard

+

The default landing page - its layout, widgets and rendering logic.

+
+
+

Page

+

Reusable interface elements: dropdowns, modals, error displays, tooltips.

+
+
+

Setting

+

Saving and reading display settings for the administration interface.

+
+
+
+
+ +
+
+
+ Installation +

From clone to login page

+

The full walkthrough, with expected output for every command, is in the documentation. This is the + shape of it.

+
+ +
+
+

1 · Clone the project

+

Into an empty directory of your choosing.

+ git clone https://github.com/dotkernel/admin.git . +
+
+

2 · Install dependencies

+

Run it from the CLI so the setup prompts stay interactive. Decline the ConfigProvider injection - + Dotkernel ships its own.

+ composer install +
+
+

3 · Enable development mode

+

For local work only. composer development-status tells you where you stand, and it + must stay off in production.

+ composer development-enable +
+
+

4 · Configure the database

+

Fill in the credentials in config/autoload/local.php. Both a MariaDB and a + PostgreSQL connection are pre-declared; one is active at a time.

+
+
+

5 · Migrate and seed

+

Migrations build the schema; fixtures populate the default roles, OAuth clients and accounts.

+ php ./vendor/bin/doctrine-migrations migrate
php ./bin/doctrine fixtures:execute
+
+
+

6 · Build the assets

+

npm run watch recompiles while you work; npm run prod minifies for + release.

+ npm install && npm run prod +
+
+ +

+ Open the virtual host in your browser and the Dotkernel Admin login page is waiting. If the fixtures + ran, sign in with user admin and password dotadmin - the same credentials as + the public demo, and the first thing to change before going live. +

+
+
+ +
+
+
+ Requirements +

What the server needs

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ComponentRequirement
Operating systemA *nix based system is strongly recommended for production.
PHP8.2 or newer, mod_php or FCGI (FPM). memory_limit at least 128M; + upload_max_filesize and post_max_size at least 100M depending + on your data.
Web serverApache 2.2+ with mod_rewrite and .htaccess support + (AllowOverride All) - a default .htaccess ships in + public/. On Nginx, translate it into server configuration.
DatabaseMariaDB 10.7, 10.11 LTS, 11.4 LTS and 11.8 LTS, or PostgreSQL 13 and above. + MySQL is not supported, as it has no UUID support.
Required extensionsmbstring, the CLI SAPI for cron jobs, and Composer available on + $PATH.
Recommended extensionsopcache; pdo_mysql, pdo_pgsql or + mysqli to match your database; dom and + simplexml for markup; gd and exif for images; + zlib, zip, bz2 for compression; + curl when calling APIs; sqlite3 for the test suite.
+
+

+ On Windows, WSL2 is the recommended development environment - Dotkernel provides an AlmaLinux + distro implementation and an install script for the whole local stack. +

+
+
+ +
+
+
+ Going live +

The checklist nobody writes down

+

+ Admin gives you the tools to build a safe application, and the documentation is explicit that some + of them are yours to apply. These are the ones worth checking off before the first deploy. +

+ +
+
+

Before you go to production

+
    +
  • Change or remove the demo admin account - its identity and password are public.
  • +
  • Review cookie_httponly, cookie_samesite and + cookie_secure in session.global.php.
  • +
  • Confirm development mode is off with composer development-status.
  • +
  • Set your allowed origins in cors.global.php.
  • +
  • Keep secrets in *.local.php - the *.global.php and + *.php.dist files are committed.
  • +
  • Add CSRF fields and authorization rules to every form and route you add.
  • +
  • Watch dependencies on both sides: Composer advisories and npm audit.
  • +
+
+
+
+ +
+
+
+ Staying current +

Upgrades you can read before you run them

+

+ Admin does not ship an automatic upgrade path, and that is deliberate: you implement the + modifications listed for each release, in a codebase you already understand, instead of handing a + migration script control over your customizations. +

+

+ A CHANGELOG.md in the project root lists implemented features in reverse chronological + order, so it doubles as your version marker. From version 6.2 onward, the procedure is documented + version to version, and releases are also published as an RSS feed. +

+ +
+
+

Coming from Admin 6.x?

+

+ Version 7 bumped dependencies, synchronised the Core module and refreshed the codebase to stay + compatible with Dotkernel API v7 - the release that moved identifiers to native database UUIDs and + dropped MySQL. +

+

+ Work through the pull requests listed for 7.0, then copy the release notes into your own changelog + so your project keeps tracking upstream. +

+
+
+
+ +
+
+
+ The ecosystem +

Better with an API in front of it

+

Admin installs and runs on its own. Paired with Dotkernel API over the same Core + namespaces, Admin manages the data while the API exposes it to third-party frontends and backends - + and neither one disagrees about what an entity is. The rest of the ecosystem is below.

+
+ +
+
+
+
Pair with · HTTP surface

API

+
+

Expose the data you manage here to any client.

+

A REST API on a PSR-15 middleware pipeline, with OAuth 2.0, RBAC, HAL payloads and + an OpenAPI 3.0 specification wired up on install.

+ +
+ +
+
+
Pair with · Async work

Queue

+
+

Queue a bulk operation from an admin screen.

+

Background workers on Symfony Messenger - a TCP listener, Valkey streams, retries + and a dead letter queue for what still fails.

+ +
+ +
+
+
Instead · Public-facing

Frontend

+
+

The site your users log into, not your staff.

+

A web starter skeleton - user accounts, a contact form, sessions and RBAC-guarded + controller actions, rendered on the server.

+
+ Read more + Demo +
+
+ +
+
+
Smaller · Minimal

Light

+
+

No records to manage, just pages.

+

The smallest complete Mezzio application - routing, pipeline and Twig, six direct + dependencies and no database layer.

+
+ Read more + Demo +
+
+ +
+
+
Tooling · AI context

Dotboost

+
+

Teach your AI tools this architecture.

+

Drop-in Claude Code configuration - ten commands, seventeen skills and permission + guardrails that keep your secrets out of the context window.

+ +
+
+ +

+ New modules start with dot-maker, + which knows which files an Admin needs versus an API. Support status for every layer is on the + packages lifecycle page. +

+
+
+ + {% if posts is defined and posts is iterable %} +
+
+
+ From the blog +

Go deeper

+
+
+ {% for post in posts %} + + +

{{ post.title }}

+

{{ post.excerpt }}

+ Read more → +
+ {% else %} +

No recent posts.

+ {% endfor %} +
+
+
+ {% endif %} + +
+
+
+ Open source, in production +

Try it with the demo, keep it under MIT.

+
+
+

Sign in to the public demo with admin / dotadmin to see + the interface before you install anything. Dotkernel Admin is developed and led by the dev team at + Apidemia, and released as open source for the community.

+ +
+
+
+{% endblock %} diff --git a/src/Page/templates/page/api.html.twig b/src/Page/templates/page/api.html.twig new file mode 100644 index 00000000..95096da0 --- /dev/null +++ b/src/Page/templates/page/api.html.twig @@ -0,0 +1,579 @@ +{% extends '@layout/default.html.twig' %} + +{% set routeName = 'page::api' %} +{% set meta = { + title: 'Dotkernel API | Open-source REST API skeleton for PHP', + description: 'Dotkernel API is an open-source REST API skeleton built on Mezzio, Laminas and Doctrine. ' + ~ 'OAuth2, RBAC, HAL, problem details and OpenAPI 3.0 come wired together on install. MIT licensed.', +} %} + +{% block title %}Dotkernel API{% endblock %} + +{% block stylesheets %} + +{% endblock %} + +{% block content %} + +
+
+
+ REST API skeleton · PSR-15 middleware +

Dotkernel API

+

+ An open-source REST API skeleton for PHP, built on the Mezzio microframework and Laminas components + over a Doctrine domain layer. OAuth 2.0, RBAC authorization, HAL payloads, standardized error + responses and an OpenAPI 3.0 specification are assembled on install - not left as decisions for + your first sprint. +

+ +
+ PHP version for dotkernel/api + Latest release of dotkernel/api + License of dotkernel/api + GitHub stars for dotkernel/api +
+
+
Runtime Mezzio + Laminas
+
Persistence Doctrine ORM
+
License MIT
+
+
+ +
+
Request lifecycle
+
+ +
CORSmezzio-cors
+
RouterFastRoute
+
AuthenticationOAuth 2.0
+
RBAC guardper route name
+
Your handlerPSR-15
+
ResponseHAL / problem+json
+
+
+
+
+ +
+
+
+ What it is +

A REST API you own from the first commit

+

+ Dotkernel API is the root of the Dotkernel Headless Platform: a REST API based on the Mezzio + skeleton, using a PSR-compliant middleware stack as defined by the PHP Framework Interop Group. + Rather than relying on elements built into a framework, business logic is built explicitly - from + handlers to dependencies - so you keep full control over your business logic and data architecture. +

+

+ It scales down to a single microservice and up to an enterprise-grade API, and it has been + developed and released continuously since 2018. +

+
+ Extending the power of + +
+
+
+
+ +

Doctrine ORM, not Active Record

+
+ +
+ +

Explicit wiring, no runtime magic

+
+ +
+ +

Auth, docs and errors on install

+
+ +
+ +

MIT licensed, actively maintained

+
+
+
+
+ +
+
+
+ What ships wired up +

The parts every API needs, already connected

+

Each of these is configured and working in a fresh install. Nothing here is a placeholder you have + to research and assemble before you can serve your first authenticated endpoint.

+
+ +
+ +
+
+
Security · Authentication

OAuth 2.0

+
+

Bearer tokens, issued and validated by the API itself.

+

+ Authentication runs on mezzio-authentication-oauth2, which wraps + league/oauth2-server to provide OAuth 2.0 for PSR-7 / PSR-15 applications. + Endpoints marked as authenticated require a valid Bearer token and answer + 401 Unauthorized without one. +

+
+ +
+
+
Security · Authorization

RBAC per route

+
+

Three levels of protection: none, authenticated, authorized.

+

+ Roles and their permissions are declared in configuration and allocated per route name, with + role inheritance supported. An authenticated request that lacks the required permission gets a + 403 Forbidden - decided by config, not scattered through your handlers. +

+
+ +
+
+
Contract · Documentation

OpenAPI 3.0

+
+

A machine-readable contract, generated from the code that serves it.

+

+ Every module documents its endpoints in an OpenAPI.php file, which + zircote/swagger-php turns into a specification rendered through Swagger UI or + Redoc. A Postman collection and environment ship alongside it, so every endpoint is ready to + call by hand. +

+
+ +
+
+
Data · Persistence

Doctrine ORM

+
+

Your domain in entities, not in the query layer.

+

+ Doctrine ORM handles persistence, so you can focus on object-oriented business logic and treat + storage as a secondary concern. Migrations, fixtures via dot-data-fixtures, and + multiple database connections are part of the setup. +

+
+ +
+
+
Contract · Responses

HAL & problem details

+
+

One predictable shape for resources, one for failures.

+

+ Payloads are built with mezzio-hal, describing each resource together with its + relational links and embedded child resources. Errors return problem details responses via + mezzio-problem-details, giving clients standardized error codes system-wide. +

+
+ +
+
+
Contract · Negotiation

Content negotiation

+
+

Client and server agree on format and language up front.

+

+ Content negotiation is implemented out of the box through the Content-Type and + Accept headers, so diverse systems can consume the same API without custom glue on + either side. CORS preflight requests are recognized and configured by + mezzio-cors. +

+
+ +
+
+
Operations · Feedback

Error reporting endpoint

+
+

A channel for the bugs that never reach your logs.

+

+ Frontend developers can report incorrect behaviour by posting to /error-report with + a token header. The API validates the request against configured tokens, domains and IPs before + logging it - useful precisely when nothing fatal was thrown. +

+
+ +
+
+
Operations · CLI

Commands & file locker

+
+

Scheduled work that refuses to trample itself.

+

+ Console commands are registered through dot-cli on top of Symfony Console. The file + locker, enabled by default, writes a lock file per command so a second instance cannot start + while the previous run is still going - the safeguard cron jobs usually lack. +

+
+ +
+
+
Productivity · Scaffolding

dot-maker

+
+

New modules that already match the house style.

+

+ dot-maker generates project files and directories following the Dotkernel structure, + and knows which files each application type needs. It replaces hand-copied boilerplate with + consistent, standardized scaffolding. +

+
+ Docs +
+
+
+
+
+ +
+
+
+ Current release +

What version 7 changed

+

The latest release moves identifiers to native database UUIDs and broadens platform support.

+
+ +
+
+

Native UUID v7

+

Identifier columns use the database's uuid type instead of binary, with + values generated by ramsey/uuid. You keep full control of the UUID version without + depending on database extensions.

+
+
+

PostgreSQL support

+

PostgreSQL joins the supported databases. Because native UUID is required, you need PostgreSQL or + MariaDB 10.7 or later; MySQL is no longer supported, as it has no UUID data type.

+
+
+

PHP 8.5

+

The API targets PHP 8.5, with Dotkernel Admin on 8.4. Dependencies are kept current, and the + ecosystem's own packages track the versions Laminas and Doctrine support.

+
+
+

Table prefixes

+

A configurable string can be prepended to every table name - the practical requirement when an + API shares a database with an existing application.

+
+
+

Clearer database configuration

+

Multi-connection setups spell out which connection is the default and how to switch to another, + based on scenarios from real projects.

+
+
+

Shared Core module

+

Common logic lives in a Core module kept as its own Git repository, which can be added as a + submodule to any Dotkernel application so entities and queries stay consistent.

+
+
+
+
+ +
+
+
+ Change management +

Evolution, not a wall of versions

+

+ Dotkernel API favours an evolution pattern with a sunsetting mechanism over maintaining parallel + API versions. The same codebase evolves gradually and clients are given notice, instead of every + change forking into another branch you have to keep alive. +

+

+ Full versioning stays reserved for major, format-level changes - the cases where it genuinely earns + its maintenance cost. The two approaches are not mutually exclusive. +

+ +
+
+

Coming from Laminas API Tools?

+

+ API Tools (formerly Apigility) is archived. Dotkernel API is an actively maintained alternative + with a middleware architecture, a permissive MIT license and a Doctrine data layer. +

+

+ The comparison below is drawn from the full side-by-side write-up on our blog. +

+
+
+
+ +
+
+
+ Comparison +

Dotkernel API vs Laminas API Tools

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
FeatureAPI Tools (formerly Apigility)Dotkernel API
First release20122018
ArchitectureMVC, event drivenMiddleware
OSS lifecycleArchivedOSS lifecycle for dotkernel/api
PHP version≤ 8.2PHP version for dotkernel/api
StyleREST, RPCREST
Change managementVersioningDeprecations (API evolution)
DocumentationSwagger (automated)OpenAPI 3.0 (Swagger) and Postman (manual)
LicenseBSD-3MIT
Default DB layerlaminas-dbdoctrine-orm 3.x
AuthorizationACLRBAC guard
AuthenticationHTTP Basic / Digest, OAuth 2.0OAuth 2.0
Endpoint generatorYesdot-maker
PSR standardsPSR-7PSR-7, PSR-15
+
+

+ Comparison drawn against Dotkernel API v7. Read the reasoning behind each row in + Dotkernel API versus Laminas API Tools. +

+
+
+ +
+
+
+ The ecosystem +

Runs alone, or as one of three

+

Dotkernel API is a complete application on its own. When you add Admin or Queue, all three declare the + same Core namespaces, so a User means the same thing to the endpoint that + creates it, the admin screen that moderates it, and the worker that emails it. The rest of the + ecosystem is below.

+
+ +
+ Shared domain layer + Core\App Core\Admin Core\User + Core\Security Core\Setting +

One set of entities and repositories, committed in each repository so a single-component start just + works. Having many entities in Core does not oblige you to implement handlers for all of them - + each application handles only what it needs.

+
+ +
+
+
+
Pair with · Back office

Admin

+
+

Manage the same data your API serves.

+

Table-based record management with RBAC guards, CSRF-protected forms and 2FA, over + the same Core module. Start with either one and add the other later.

+ +
+ +
+
+
Pair with · Async work

Queue

+
+

Move slow work off the request cycle.

+

Background workers on Symfony Messenger - a TCP listener, Valkey streams, retries + and a dead letter queue for what still fails.

+ +
+ +
+
+
Instead · Server-rendered

Frontend

+
+

When your users want pages, not payloads.

+

A web starter skeleton - user accounts, a contact form, sessions and RBAC-guarded + controller actions, rendered on the server.

+
+ Read more + Demo +
+
+ +
+
+
Smaller · Minimal

Light

+
+

A presentation site with no API behind it.

+

The smallest complete Mezzio application - routing, pipeline and Twig, six direct + dependencies and no database layer.

+
+ Read more + Demo +
+
+ +
+
+
Tooling · AI context

Dotboost

+
+

Teach your AI tools this architecture.

+

Drop-in Claude Code configuration - ten commands, seventeen skills and permission + guardrails that keep your secrets out of the context window.

+ +
+
+ +

+ Every layer is also available on its own - see the + packages lifecycle for the support + status of each dot-* package. +

+
+
+ +
+
+
+ Standards & quality +

Built on interfaces, checked on every change

+
+ +
+
+

PSR-15 & PSR-7

+

Handlers implement RequestHandlerInterface and return ResponseInterface. + The whole request path is middleware you can read top to bottom.

+
+
+

PSR-11 & PSR-4

+

The application is container-based, with dependencies declared in each module's + ConfigProvider, and classes located by autoloader.

+
+
+

PSR-3 logging

+

Errors are logged through LoggerInterface via + dot-errorhandler, centralizing how failures are recorded.

+
+
+

PHPStan at level 8

+

Static analysis runs at a strict rule level, in line with the choice made by projects like + Doctrine and Composer.

+
+
+

Functional & unit tests

+

The skeleton ships with a test suite you extend rather than start, so new endpoints have + somewhere to be tested from day one.

+
+
+

An active community

+

Updates arrive with bugfixes and improvements from the PHP community, and breaking changes come + with companion articles and upgrade steps.

+ +
+
+
+
+ +
+
+
+ Get started +

Install it and call an endpoint

+

+ Create the project with Composer, point it at PostgreSQL or MariaDB 10.7+, run the migrations, and + you have an authenticated REST API with a browsable OpenAPI specification. +

+ +
+
+

composer create-project dotkernel/api

+

+ The installer walks through database credentials and the initial configuration. Follow the + installation guide for the exact command and post-install steps for your target version, then use + dot-maker to scaffold your first module. +

+

+ Questions along the way go to + Dotkernel Discussions + - the team answers issues on both Dotkernel and Laminas components. +

+
+
+
+ + {% if posts is defined and posts is iterable %} +
+
+
+ From the blog +

Go deeper

+
+
+ {% for post in posts %} + + +

{{ post.title }}

+

{{ post.excerpt }}

+ Read more → +
+ {% else %} +

No recent posts.

+ {% endfor %} +
+
+
+ {% endif %} + +
+
+
+ Open source, in production +

An API foundation you can read, audit and keep.

+
+
+

Dotkernel API is developed and led by the dev team at Apidemia - built first as an + internal tool for handling complex architectures, released under MIT as our way of giving back to + the community.

+ +
+
+
+{% endblock %} diff --git a/src/Page/templates/page/dotboost.html.twig b/src/Page/templates/page/dotboost.html.twig new file mode 100644 index 00000000..1991f572 --- /dev/null +++ b/src/Page/templates/page/dotboost.html.twig @@ -0,0 +1,625 @@ +{% extends '@layout/default.html.twig' %} + +{% set routeName = 'page::dotboost' %} +{% set meta = { + title: 'dotboost | Claude Code configuration for Dotkernel projects', + description: 'dotboost is a drop-in .claude/ directory that teaches Claude Code the conventions of any Dotkernel ' + ~ 'application - ten commands, seventeen skills, six hooks, and permission guardrails that keep secrets out of the context.', +} %} + +{% block title %}dotboost{% endblock %} + +{% block stylesheets %} + +{% endblock %} + +{% block content %} + +
+
+
+ Developer tooling · AI context +

Dotboost

+

+ Drop-in configuration that teaches Claude Code the conventions of any Dotkernel application - API, + Admin, Frontend, Light, Queue, or a project derived from one of them. Every skill detects the variant + first and applies the matching dialect, so generated code follows your architecture instead of + guessing at it. +

+ +
+ License of dotkernel/dotboost + GitHub stars for dotkernel/dotboost + Last commit to dotkernel/dotboost +
+
+
Payload One .claude/ directory
+
Commands Ten /dk-*
+
Skills Seventeen
+
+
+ +
+
What happens in a session
+
+ +
Session startvariant briefing
+
Skill loadsby description
+
Plan modeproposes first
+
Guard hooksEdit · Bash
+
NormaliseBOM · CRLF · EOF
+
Lintphp -l · markdown
+
+
+
+
+ +
+
+
+ What it is +

Not an application - a configuration payload

+

+ Dotboost is not itself a Dotkernel application. Its entire payload is the .claude/ + directory: settings, hooks, a status line, a review subagent, ten /dk-* commands and + seventeen skills. You install it by copying that directory into the Dotkernel project you are + working on. +

+

+ There is no routing table telling Claude which skill to pick - each one loads from its own + description. Ask where a new Doctrine entity goes and it should reach for the module-structure + skill rather than answering from general framework knowledge. +

+
+ Maintained by + +
+
+
+
+ +

Detects the variant before it answers

+
+ +
+ +

Secrets never enter the context window

+
+ +
+ +

Guards catch compound commands globs miss

+
+ +
+ +

Copy it in - nothing to build or install

+
+
+
+
+ +
+
+
+ Guardrails +

The reason to adopt the file

+

The permission rules in settings.json fall into four tiers. The first one is the + headline: these are Read denies, not write protection, so the contents never enter the + context window at all.

+
+ +
+
+
+
Tier · Never read

Your secrets

+
+

Not redacted - never loaded.

+

+ .env, every *.local.php, + config/autoload/local.php, local.test.php and + data/oauth/. Database credentials, OAuth signing keys and environment secrets stay + out of the transcript. +

+
+ +
+
+
Tier · Never written

Generated & vendored

+
+

The files a diff should never touch by accident.

+

+ Dependency manifests - composer.json, composer.lock, + package.json, package-lock.json - plus vendor/, + node_modules/, data/, log/, + public/uploads/ and anything under Migration/. +

+
+ +
+
+
Tier · Never run

Installs & destructive git

+
+

Commands that change your tree without a diff.

+

+ composer require, remove, update, + install, global; the npm, yarn and pnpm install verbs; + git push, reset --hard, clean, + submodule; and rm -rf. +

+
+ +
+
+
Tier · Ask & allow

Your call

+
+

Preference, not policy - override per machine.

+

+ Ask: migrations, bin/doctrine, database clients, git commits and + merges, pipeline and authorization config, the QA config files. + Allow: the Composer QA scripts, vendor/bin tools, + php -l, and read-only git. Layer changes in + settings.local.json, never the shared file. +

+
+ +
+
+
Hooks · Six

Where globs cannot see

+
+

Path patterns miss what a shell can hide.

+

+ guard-bash.sh inspects the command itself, so + cd src && composer require foo is caught where a path-based rule would let + it through. guard-protected-paths.sh covers edits, and redirects a blocked + *.local.php edit to its .dist template. +

+
+ +
+
+
Hooks · Report only

Linters that do not rewrite

+
+

Deliberately no phpcbf, no --fix.

+

+ php-lint.sh and markdown-lint.sh report and stop, because + reformatting a file right after it is written invalidates the in-memory copy and breaks the next + targeted edit. Bulk formatting belongs at the end of a task. Both skip silently when their tool + is missing. +

+
+
+ +

+ settings.json is a committed file carrying opinions, not only guardrails: sessions start in + plan mode, the terminal UI is full screen, the theme is dark, and Composer runs without + a memory ceiling. Know what you are adopting. +

+
+
+ +
+
+
+ Stricter than documented +

Where the hooks overrule the tiers

+

Some commands marked ask in settings.json are refused outright by + guard-bash.sh, because the hook sees compound commands the permission globs cannot. The + prompt you would expect never appears - you get a refusal. This is deliberate, and worth knowing + before it surprises you.

+
+ +
+ + + + + + + + + + + + + + + +
Commandsettings.json saysguard-bash.sh does
git rebaseaskblocks
doctrine-migrations migrate / executeaskblocks
fixtures:execute, schema:drop, schema:updateask, via bin/cli.phpblocks
composer development-enable / -disableblocks
pip install, git checkout --, git filter-branchblocks
+
+

+ Everything else under ask - commits, database clients, the config and QA files - prompts as + documented. To get a blocked command back you edit the hook; relaxing + settings.local.json will not reach it. +

+
+
+ +
+
+
+ Commands +

Ten /dk-* commands

+

Each one runs only when you ask for it.

+
+ +
+ + + + + + + + + + + + + + + + + + + +
CommandWhat it does
/dk-bootstrapFresh clone to a running install.
/dk-modulePlan a new module - dot-maker first.
/dk-routeAdd a fully wired endpoint or page.
/dk-traceTrace a request through pipeline, handler and response.
/dk-testWrite and run tests.
/dk-documentWrite or update a feature doc.
/dk-checkRun and fix the QA gate.
/dk-deprecateMake an evolution-pattern breaking change.
/dk-reviewPre-PR convention review - read-only by design.
/dk-hygieneEncoding and line-ending audit.
+
+
+
+ +
+
+
+ Skills +

Seventeen skills, loaded on demand

+

Sixteen dotkernel-* skills plus dependency-policy. Each is a living + document - when a review turns up the same mistake twice, that is a missing line in a skill.

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SkillCovers
application-variantsDetecting API vs Admin vs Frontend vs Light vs Queue.
module-structureWhere code goes: application module vs Core, and the wiring.
handler-namingBoth naming dialects, routes, authorization keys.
doctrine-entitiesEntities, enums and DBAL types, repositories, migrations.
input-validationInputFilters, Inputs, forms, CSRF, query whitelisting.
responsesHAL and collections, or templates and redirects; errors.
openapiswagger-php attributes, for apps that publish OpenAPI.
feature-docsFeature docs: template, where they live, staleness.
testingUnit and functional patterns, test config, coverage matrix.
evolution-patternSunset headers instead of versioning.
securityAuth, authorization, secrets, CORS, dependencies.
dot-makercomposer make … and the manual steps after it.
core-submoduleCore layering rules and git submodule mechanics.
psr-standardsPSR-1/3/4/6/7/11/12/15/16/17 as applied here.
qa-gatecs-check, static analysis, tests, and forbidden "fixes".
troubleshootingA symptom to cause table.
dependency-policyThe ladder from installed packages to hand-rolled code, and the proposal format.
+
+

+ A review subagent, dotkernel-reviewer, runs the convention review in its own context so the + main one stays clean. +

+
+
+ +
+
+
+ Dependency policy +

Never name a package from memory

+

+ The ladder is: already in composer.lock, then dotkernel/*, then + laminas/* and mezzio/*, then a vetted community package, and only then + hand-rolled code. Stop at the first hit. +

+

+ A skill's description decides whether it can load, not whether Claude stops to think before + naming a package. The rule that makes it reach for the skill has to be always loaded - which means + it lives in your project's own CLAUDE.md, not in the skill. +

+ +
+
+

Three things about how that behaves

+
    +
  • The dotkernel/* manifest is generated on first use, not shipped - the first package + question runs the sync script itself. It needs curl, jq and network; + without them Claude is told to call a package name unverified rather than + assert it.
  • +
  • Neither that script nor composer show --available is in the allow or deny list, so + both prompt. That is deliberate - expect a prompt the first time.
  • +
  • "How do I send mail from here?" is a package question. Implicit ones count.
  • +
+
+
+
+ +
+
+
+ Install +

Copy one directory into your project

+

The payload has to sit at the root of your project. Two routes to the same files - pick whichever + suits the machine you are on.

+
+ +
+
+

1 · Clone it inside the project

+

Shallow, because only the current state of main is any use in a target project. The + clone goes away right after the copy.

+ git clone --depth 1 \ + https://github.com/dotkernel/dotboost.git .dotboost +cp -r .dotboost/.claude .claude +rm -rf .dotboost +
+
+

1b · Or download the zip

+

No git needed, which is the point. The archive unpacks to dotboost-main/ and does + carry the dotfiles.

+ curl -L -o dotboost.zip https://github.com/\ +dotkernel/dotboost/archive/refs/heads/main.zip +unzip -q dotboost.zip +cp -r dotboost-main/.claude .claude +
+
+

2 · Restore the executable bits

+

Nothing is committed executable, and a zip extracted on Windows carries no permission bits at + all. The sync script is the one called by its own name.

+ chmod +x .claude/hooks/*.sh .claude/statusline.sh \ + .claude/skills/dependency-policy/scripts/*.sh +
+
+

3 · Keep local overrides out of git

+

Then copy the example file if you want personal settings that survive an update.

+ echo '.claude/settings.local.json' \ + >> .git/info/exclude +
+
+

4 · Optional: markdown linting

+

Not bundled - install it yourself, globally or as a project devDependency. Until the binary + resolves, the hook exits silently.

+ npm install -g markdownlint-cli2 +
+
+

5 · Paste the CLAUDE.md block

+

The dependency policy and, if you want feature docs actually read, the feature-docs block + alongside it.

+
+
+ +

+ If the project already has its own .claude/settings.json or + .claude/commands/, merge by hand rather than running cp -r blind - same-named + files are overwritten. To update later, run the whole install again over the top; anything you changed + in the project's copy is lost, which is exactly why personal changes belong in + settings.local.json. +

+
+
+ +
+
+
+ Also in the box +

The parts you notice on day two

+
+ +
+
+
+
Docs · /dk-document

Feature documentation

+
+

The part a cleared session cannot reconstruct from src/.

+

+ One markdown file per feature - what it does, why, the routes and the roles that reach them, the + data added, how to exercise it. Where it lands is detected, not assumed: + documentation/features/ when that directory exists, + docs/features/ otherwise, never a second documentation root beside an existing one. + The frontmatter is load-bearing - /dk-review greps routes: and + handlers: to decide whether a new route in the diff is documented. +

+
+ +
+
+
Status line

Real usage, not guesses

+
+

The same numbers /usage reports.

+

+ 5h and 7d account usage in the status bar, read from the rate-limit payload Claude Code 2.1+ + passes on stdin. Pure bash and awk - no jq, no python, no transcript scanning or + guessed token budgets, so it works in Git Bash on Windows. +

+
+ +
+
+
Session start

A briefing, every time

+
+

What it detected, before you ask anything.

+

+ Which variant, the root namespace, the authorization style, the branch, which config files are + still missing - and a CRLF warning when it finds one. The same hook prints the feature-docs + directory and a doc count, so the files are discoverable even without the CLAUDE.md block. +

+
+ +
+
+
Windows · Line endings

CRLF, handled

+
+

Dotkernel repos ship * text eol=lf.

+

+ Belt and braces, configure the client so nothing converts: + core.autocrlf false, core.eol lf, + core.safecrlf warn. Already committed CRLF? Renormalise once with + git add --renormalize .. normalize-file.sh keeps new writes clean. +

+
+
+
+
+ +
+
+
+ Works with +

Every variant, one payload

+

The application-variants skill detects which Dotkernel application it is looking at - including a + project derived from one - and every other skill applies the matching dialect. Handler naming, + response shape and authorization keys all differ between them, which is the whole reason the + detection runs first.

+
+ +
+ Detected variants + API Admin Frontend + Light Queue +

Before adapting the skills to a new Dotkernel application, the advice from its maintainer is to spend + an hour reading that repo and correcting them against what is actually there. A skill written from + framework docs rather than the codebase produces confident wrong answers, which is worse than no + skill.

+
+ +
+
+
+
Variant · Detected

API

+
+

Handlers, HAL collections, OpenAPI attributes.

+

A REST API on a PSR-15 middleware pipeline, with OAuth 2.0, RBAC, HAL payloads and + an OpenAPI 3.0 specification wired up on install.

+ +
+ +
+
+
Variant · Detected

Admin

+
+

Forms, CSRF, route-name authorization keys.

+

Table-based record management with RBAC guards, CSRF-protected forms and 2FA, over + the shared Core module.

+ +
+ +
+
+
Variant · Detected

Frontend

+
+

Action controllers and action-level guards.

+

A web starter skeleton - user accounts, a contact form, sessions and RBAC-guarded + controller actions, rendered on the server.

+ +
+ +
+
+
Variant · Detected

Light

+
+

Minimal modules, config-declared template routes.

+

The smallest complete Mezzio application - routing, pipeline and Twig, six direct + dependencies and no database layer.

+ +
+ +
+
+
Variant · Detected

Queue

+
+

Message handlers and background workers.

+

Background workers on Symfony Messenger - a TCP listener, Valkey streams, retries + and a dead letter queue for what still fails.

+ +
+
+
+
+ + {% if posts is defined and posts is iterable %} +
+
+
+ From the blog +

Go deeper

+
+
+ {% for post in posts %} + + +

{{ post.title }}

+

{{ post.excerpt }}

+ Read more → +
+ {% else %} +

No recent posts.

+ {% endfor %} +
+
+
+ {% endif %} + +
+
+
+ Open source, in production +

Context your AI tools do not have to guess at.

+
+
+

Dotboost is maintained by Borsan Sergiu and released as open source alongside the + rest of the Dotkernel ecosystem. Treat the skills as living documents - the repository is where + corrections belong.

+ +
+
+
+{% endblock %} diff --git a/src/Page/templates/page/frontend.html.twig b/src/Page/templates/page/frontend.html.twig new file mode 100644 index 00000000..bc7841af --- /dev/null +++ b/src/Page/templates/page/frontend.html.twig @@ -0,0 +1,564 @@ +{% extends '@layout/default.html.twig' %} + +{% set routeName = 'page::frontend' %} +{% set meta = { + title: 'Dotkernel Frontend | Server-rendered PHP web starter', + description: 'Dotkernel Frontend is a web starter skeleton on Mezzio and Laminas - user accounts, a contact form, ' + ~ 'RBAC guards, CSRF-protected forms, flash messages and GDPR account anonymization, server-rendered in Twig.', +} %} + +{% block title %}Dotkernel Frontend{% endblock %} + +{% block stylesheets %} + +{% endblock %} + +{% block content %} + +
+
+
+ Web starter · Server-rendered +

Dotkernel Frontend

+

+ A web starter skeleton on the Mezzio microframework and Laminas components, for the applications + people log into. User accounts, a working contact form and a content page ship as proof of concept - + real, running features whose only job is to show you where your own code goes. +

+ +
+ PHP version for dotkernel/frontend + Latest release of dotkernel/frontend + License of dotkernel/frontend + OSS lifecycle for dotkernel/frontend +
+
+
Runtime Mezzio + Laminas
+
Pattern Action controllers
+
Templating Twig
+
+
+ +
+
Request lifecycle
+
+ +
Sessiondot-session
+
RouterFastRoute
+
AuthenticationUser identity
+
RBAC guardroute + action
+
Controller actiondot-controller
+
ResponseTwig + flash
+
+
+
+
+ +
+
+
+ What it is +

The web application half of the stack

+

+ Frontend is the skeleton for a server-rendered application with users in it. Where Light gives you + pages, Frontend gives you the machinery around them: sessions, authentication, registration, + validated forms, flash messages between redirects, and role-based access to individual controller + actions. +

+

+ The shipped features - contact us, a generic content page, user accounts - are deliberately + presented as building blocks rather than a finished product. They exist to showcase the file + architecture and to be copied. +

+
+ Extending the power of + +
+
+
+
+ +

User accounts, from register to unregister

+
+ +
+ +

Action controllers, not request handlers

+
+ +
+ +

CSRF and reCAPTCHA on public forms

+
+ +
+ +

GDPR anonymization out of the box

+
+
+
+
+ +
+
+
+ What ships wired up +

Everything a logged-in site needs first

+

These are the parts you would otherwise spend your first two weeks assembling, already working + together in a fresh install.

+
+ +
+ +
+
+
Users · Accounts

Registration & login

+
+

The whole account lifecycle, already routed.

+

+ Login, registration and account management, including avatar upload, password change and + unregistering. Password reset and account activation emails are part of the flow, which is why + the skeleton stores a name and an email address and nothing more. +

+
+ +
+
+
Security · Access control

Guards per action

+
+

Permissions applied to individual controller actions.

+

+ dot-rbac-guard and dot-rbac read roles and permissions from + authorization.global.php, then authorization-guards.global.php maps + rules onto a route and a named list of its actions - or an empty list to cover all of them. + Fine-grained without being scattered. +

+
+ +
+
+
Security · Forms

CSRF tokens

+
+

A new token per render, validated on submit.

+

+ Built from the laminas-form CSRF element, a laminas-session CSRF + validator in the input filter, and the formElement view helper in the template. + Tokens expire after a configurable timeout - one hour by default - and are never reusable + between forms. +

+
+ +
+
+
Public · Contact

Contact form with reCAPTCHA

+
+

A public form that does not become a spam relay.

+

+ The contact form uses Google reCAPTCHA, with the site and secret keys read from local + configuration and the message recipients - to and any number of + cc addresses - configured alongside them. Whitelist localhost while + developing, and take it out again for production. +

+
+ +
+
+
UX · Feedback

Flash messages

+
+

The message survives the redirect.

+

+ dot-flashmessenger carries session messages across redirects - the small piece that + makes post-then-redirect flows feel finished. dot-session extends laminas-session + underneath, configured in session.global.php. +

+
+ +
+
+
Wiring · DI

Attribute injection

+
+

Constructor injection declared on the constructor.

+

+ dot-dependency-injection reads an #[Inject] attribute and resolves + each listed dependency - a service, the whole config array, or a single key by dot + notation. Register the class against AttributedServiceFactory and stop writing + factories. +

+
+ +
+
+
Data · Persistence

Doctrine ORM

+
+

Migrations and fixtures, driven from the CLI.

+

+ Doctrine through roave/psr-container-doctrine, with UUIDs as a field type via + ramsey/uuid-doctrine. Migrations live in data/doctrine/migrations; + bin/doctrine fixtures:execute seeds the default roles. +

+
+ +
+
+
Delivery · HTTP

Headers & CORS

+
+

Response headers declared per route.

+

+ dot-response-header sets custom headers per route from + response-header.global.php, while mezzio-cors handles origins, headers + and cookies from cors.global.php. +

+
+ +
+
+
Content · Presentation

Menus, templates, i18n

+
+

Navigation from configuration, translation when you need it.

+

+ dot-navigation defines and parses menus inside templates from configuration. + dot-twigrenderer adds Dotkernel's Twig extensions, and + laminas-i18n is present for a complete translation suite. The + Plugin module carries dynamic forms and templates. +

+
+
+
+
+ +
+
+
+ Compliance +

Account anonymization, not just deletion

+

+ Under the GDPR, a company recording personal data from EU citizens must delete it on request - + or anonymize it, which the European Commission accepts as an alternative. Frontend implements the + second option, because deleting a user row is rarely what your foreign keys want. +

+

+ The skeleton stores only what it needs to run those flows: first name, last name and the email + address used as the identity, for password reset and account activation. Anonymizing replaces + exactly those. +

+ +
+
+

What anonymization changes

+
    +
  • First and last name become anonymous plus the current UNIX timestamp - for example + anonymous1725980747.
  • +
  • The email becomes the same value plus whatever you set in userAnonymizeAppend - + anonymous1725980747@example.com.
  • +
  • The avatar image and its database record are deleted.
  • +
+

+ Point userAnonymizeAppend at a domain you control and it doubles as a catch-all + address, if your mail provider supports one. Leave it empty and the local part stands alone. +

+
+
+
+ +
+
+
+ Structure +

Five modules, PSR-4 throughout

+

Each module keeps its controllers, entities, repositories and services together, alongside a + ConfigProvider and a RoutesDelegator - so a new feature has an obvious + shape before you write it.

+
+ +
+
+

User

+

Login, registration and account management - the largest module, and the one worth reading + first.

+
+
+

App

+

Core functionality: authentication, rendering and error reporting.

+
+
+

Contact

+

The contact us form, from validation through to the outgoing mail.

+
+
+

Page

+

Displaying a page - the minimal case, for static copy.

+
+
+

Plugin

+

Plugin functionality for dynamic forms and templates.

+
+
+

Module contents

+

Controller, Entity, Repository and + Service folders, plus InputFilter, EventListener, + Helper, Command or Factory as needed.

+
+
+
+
+ +
+
+
+ Installation +

From clone to welcome page

+

The documentation walks through every command with its expected output. This is the sequence.

+
+ +
+
+

1 · Clone into an empty folder

+

Git refuses a non-empty directory, and you need write permissions on it.

+ git clone https://github.com/dotkernel/frontend.git . +
+
+

2 · Install dependencies

+

From the CLI, so the prompts stay interactive. Decline the config provider injection - Frontend + ships its own.

+ composer install +
+
+

3 · Enable development mode

+

Sets debug on, configuration caching off, and clears any existing cache.

+ composer development-enable +
+
+

4 · Prepare the config files

+

Copy the .dist files into place - local.php, + development.local.php, mail.local.php, + debugbar.local.php - then fill in the database, SMTP and reCAPTCHA details.

+
+
+

5 · Migrate and seed

+

Migrations build the schema and are logged so none runs twice; the fixtures populate the default + user roles.

+ php vendor/bin/doctrine-migrations migrate
php bin/doctrine fixtures:execute
+
+
+

6 · Fix permissions and open it

+

Three writable paths cover almost every first-run error.

+ chmod -R 777 data log public/uploads +
+
+ +

+ Two local-only notes worth keeping: session.cookie_secure has to be + false in your own local.php - never in local.php.dist, where it + stays true for production - and a stale + data/cache/config-cache.php is loaded regardless of + ConfigAggregator::ENABLE_CACHE, so clear it with + bin/clear-config-cache.php when services go missing. Duplicating + local.test.php.dist gives your tests an in-memory database. +

+
+
+ +
+
+
+ Requirements +

What the server needs

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ComponentRequirement
Operating systemA *nix based system is strongly recommended for production.
PHP8.2 or newer, mod_php or FCGI (FPM). memory_limit at least 128M; + upload_max_filesize and post_max_size at least 100M depending + on your data.
Web serverApache 2.2+ with mod_rewrite and .htaccess support + (AllowOverride All); a default .htaccess ships in + public/. On Nginx, translate it into server configuration.
DatabaseTested with MariaDB 10.11 LTS and 11.4 LTS, and with MySQL 8.4 LTS. For MySQL 8.4, + my.cnf needs mysql_native_password=ON.
Required extensionsmbstring, the CLI SAPI for cron jobs, and Composer on + $PATH.
Recommended extensionsopcache; pdo_mysql or mysqli; + dom and simplexml for markup; gd and + exif for images; zlib, zip, + bz2 for compression; curl when calling APIs; + sqlite3 for the test suite.
+
+

+ Note that Frontend still supports MySQL - unlike API and Admin v7, which require native UUID support and + therefore PostgreSQL or MariaDB 10.7+. +

+
+
+ +
+
+
+ Choosing +

Where Frontend sits

+

Frontend stands on its own, outside the Headless Platform. It is the right starting point when your + users log in and your pages are rendered on the server - and the wrong one in both directions from + there.

+
+ +
+
+
+
Smaller · Minimal

Light

+
+

No users, no database, no forms to protect.

+

The smallest complete Mezzio application - routing, pipeline and Twig, six direct + dependencies. Right for a presentation site.

+
+ Read more + Demo +
+
+ +
+
+
Different · HTTP surface

API

+
+

Your frontend is someone else's framework.

+

A REST API on a PSR-15 middleware pipeline, with OAuth 2.0, RBAC, HAL payloads and + an OpenAPI 3.0 specification wired up on install.

+
+ Read more + Demo +
+
+ +
+
+
Bigger · Platform

Admin

+
+

You need a back office over a shared domain.

+

Table-based record management with RBAC guards, CSRF-protected forms and 2FA, over a + Core module shared with API and Queue.

+
+ Read more + Demo +
+
+ +
+
+
Alongside · Async work

Queue

+
+

Move the registration email off the request.

+

Background workers on Symfony Messenger - a TCP listener, Valkey streams, retries + and a dead letter queue for what still fails.

+ +
+ +
+
+
Tooling · AI context

Dotboost

+
+

Teach your AI tools this architecture.

+

Drop-in Claude Code configuration - ten commands, seventeen skills and permission + guardrails that keep your secrets out of the context window.

+ +
+
+
+
+ + {% if posts is defined and posts is iterable %} +
+
+
+ From the blog +

Go deeper

+
+
+ {% for post in posts %} + + +

{{ post.title }}

+

{{ post.excerpt }}

+ Read more → +
+ {% else %} +

No recent posts.

+ {% endfor %} +
+
+
+ {% endif %} + +
+
+
+ Open source, in production +

Accounts, forms and compliance - already handled.

+
+
+

Dotkernel Frontend is developed and led by the dev team at Apidemia and released + as open source for the community. Try the demo to see the account flows before you install + anything.

+ +
+
+
+{% endblock %} diff --git a/src/Page/templates/page/light.html.twig b/src/Page/templates/page/light.html.twig new file mode 100644 index 00000000..a1720c12 --- /dev/null +++ b/src/Page/templates/page/light.html.twig @@ -0,0 +1,553 @@ +{% extends '@layout/default.html.twig' %} + +{% set routeName = 'page::light' %} +{% set meta = { + title: 'Dotkernel Light | Minimal PSR-15 site skeleton for PHP', + description: 'Dotkernel Light is a minimal PSR-15 application skeleton on Mezzio and Laminas, for presentation ' + ~ 'sites and small services. Six direct dependencies, Twig templating, Vite assets, no database layer.', +} %} + +{% block title %}Dotkernel Light{% endblock %} + +{% block stylesheets %} + +{% endblock %} + +{% block content %} + +
+
+
+ Minimal skeleton · PSR-15 +

Dotkernel Light

+

+ A PSR-15 compliant application skeleton on the Mezzio microframework and Laminas components, + designed as a minimal project for generating a simple website - a presentation site, a landing page, + a small service. Six direct dependencies, two modules, and nothing to delete before you start. +

+ +
+ PHP version for dotkernel/light + Latest release of dotkernel/light + License of dotkernel/light + OSS lifecycle for dotkernel/light +
+
+
Runtime Mezzio + Laminas
+
Templating Twig
+
Direct deps Six
+
+
+ +
+
Request lifecycle
+
+ +
index.phpbootstrap
+
Containerfactories · aliases
+
RoutingFastRoute
+
Pipelinepipeline.php
+
HandlerPSR-15
+
Twiglayout · blocks
+
EmitterHtmlResponse
+
+
+
+
+ +
+
+
+ What it is +

The smallest complete Mezzio application

+

+ Light is what remains when you take a real PSR-15 application and remove everything a presentation + site does not need. There is no ORM, no authentication stack, no admin scaffolding - not disabled, + simply not installed. What you get is routing, a middleware pipeline, Twig, and error logging. +

+

+ That makes it two things at once: a genuine starting point for a small site, and the clearest way to + read how a Mezzio application is put together, because there is almost nothing else in the way. +

+
+ Extending the power of + +
+
+
+
+ +

Six direct dependencies

+
+ +
+ +

No database layer to configure

+
+ +
+ +

A new page is one config line and one template

+
+ +
+ +

Twig layout, Vite asset pipeline

+
+
+
+
+ +
+
+
+ What's in the box +

Six packages, and you can name all of them

+

This is the entire direct dependency list. Every one of them is doing a job you would have had to + solve anyway.

+
+ +
+
+

mezzio/mezzio

+

The PSR-15 middleware microframework the whole application runs on.

+
+
+

mezzio-fastroute

+

FastRoute integration - matches the URL and method against your registered routes.

+
+
+

mezzio-twigrenderer

+

Twig integration for Mezzio. Every template is a .html.twig file.

+
+
+

dot-errorhandler

+

Logging error handler for middleware applications - daily log files, configured in one place.

+
+
+

laminas-config-aggregator

+

Collects and merges configuration from every source into one array.

+
+
+

laminas-component-installer

+

The Composer plugin that injects modules and config providers during installation.

+
+
+ +

+ Two modules ship in src/: App for core functionality - rendering and error + reporting - and Page for displaying a page. Each module keeps its + Handler, Factory and Service folders next to a + ConfigProvider and a RoutesDelegator, following PSR-4. +

+
+
+ +
+
+
+ How it works +

A request, end to end

+

Eleven steps from the browser to the rendered page, with nothing hidden behind a kernel. This is the + sequence you can follow in the source.

+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
#StepWhat happens
1HTTP requestpublic/index.php bootstraps the application, loads configuration, and creates the Mezzio application instance.
2Service containerFactories, aliases and delegators are registered; every service is configured and ready to use.
3Route registrationAll available routes and their allowed methods are read and registered dynamically, managed by FastRoute.
4Middleware pipelineconfig/pipeline.php defines the order middleware runs in, and so how requests travel and responses come back.
5RoutingFastRoute matches the URL and method against the registered routes to find the handler.
6Handler invocationThe matched route name is pulled off the request and passed to the renderer - page::about becomes the template to render.
7Custom logicYour business logic runs in the handler, calling whatever services it needs.
8Template renderingTwig loads the template, applies the layout, renders the blocks and includes the partials.
9Response creationAn HtmlResponse is built with status, headers and the rendered HTML body.
10Response pipelineThe response flows back out through the middleware stack, which can still change headers, cookies or compression.
11Response emitterThe final response is sent to the browser.
+
+

+ Handlers, not controllers - that is what keeps the application PSR-15 compliant. Each module's + RoutesDelegator reads the route config from the container and registers the routes it + finds, so adding a page never means touching the framework. +

+
+
+ +
+
+
+ Day-to-day +

Adding a page is two files

+

+ Routes live in configuration as slug => template pairs. Append a line, create the + matching Twig template in src/Page/templates/page/, and add a link to the menu in the + layout. The handler works out which template to render from the matched route name, so there is no + handler to write. +

+

+ Want your templates in more than one folder? Add another entry under paths in the + Page module's ConfigProvider - the key does not have to match the folder name. +

+ +
+
+

One route, one template

+

In config/autoload/local.php, under the routespage key:

+ 'example-page' => 'example-template', +

Then create the template it names:

+ src/Page/templates/page/example-template.html.twig +

+ The key is the page slug, the value is the template. Your new page answers at + /page/example-page, under the route name page::example-template. +

+
+
+
+ +
+
+
+ Front end +

Assets, menus and social cards

+

The parts you actually edit on a presentation site, and where each of them lives.

+
+ +
+
+
+
Build · Vite

Asset pipeline

+
+

One command while you work, one before you ship.

+

+ Vite concatenates and compresses CSS and JavaScript, preprocesses SCSS, and copies fonts and + images - avoiding the network bottleneck of many separate files. npm run watch + recompiles on change; npm run build compiles once. Node.js v20 is the minimum + supported version. +

+
+ +
+
+
Build · Source of truth

assets → public

+
+

Edit the source, never the output.

+

+ Images, fonts, JavaScript and SCSS live in src/App/assets/. The build deletes and + rebuilds css, js, fonts and images under + public/ - anything you edit there by hand is lost on the next run. Everything else + in public/ is left alone. +

+
+ +
+
+
Build · Caching

Cache busting

+
+

The oldest bug in web deployment, solved in one character.

+

+ Browsers cache your built CSS and JS, so a deploy can leave visitors on the old file. Add a + version parameter to the asset URL in the layout - app.css?v=3 - and increment it + whenever you commit a change to that file. +

+
+ +
+
+
Content · Navigation

Menu and footer

+
+

Plain Twig in one layout file.

+

+ The top menu is the list under id="navbarHeader" in + src/App/templates/layout/default.html.twig; each li is one item, and + items can be grouped into dropdowns or styled as buttons. The footer is the + app-footer element in the same file. +

+
+ +
+
+
Content · Sharing

Twitter & OpenGraph

+
+

Cards for when your pages get posted elsewhere.

+

+ Add the card meta tags to the layout head, generating URLs with the same helper the canonical + block uses - {{ '{{ url(routeName ?? null) }}' }} - which also keeps mistyped URLs + from breaking the page. +

+
+ +
+
+
Operations · Logs

Errors and logs

+
+

A log file per day, from the first request.

+

+ dot-errorhandler writes daily files into log/, in the format set + under the stream key of error-handling.global.php. Development mode + adds the error handlers you want locally and nowhere else. +

+
+
+
+
+ +
+
+
+ Installation +

Running in minutes, honestly

+

No database to create, no fixtures to seed. Clone, install, set a URL, open it.

+
+ +
+
+

1 · Clone into an empty folder

+

Git refuses a directory that is not empty, and you need write permissions on it.

+ git clone https://github.com/dotkernel/light.git . +
+
+

2 · Install dependencies

+

Run it from the CLI so the prompts stay interactive. Decline the config provider injection - + Light already includes its own.

+ composer install +
+
+

3 · Enable development mode

+

Local work only. composer development-status reports where you stand.

+ composer development-enable +
+
+

4 · Set the base URL

+

Point $baseUrl in config/autoload/local.php at your virtual host.

+
+
+

5 · Fix the writable folders

+

The two directories the application writes to. Most first-run errors are this and nothing + else.

+ chmod -R 777 ./data ./log +
+
+

6 · Open it in a browser

+

The Dotkernel Light welcome page is waiting. Errors about missing services usually mean a stale + config cache.

+ php ./bin/clear-config-cache.php +
+
+ +

+ A cached data/cache/config-cache.php is loaded regardless of the + ConfigAggregator::ENABLE_CACHE setting - which is exactly why clearing it fixes so much. + On Windows, WSL2 with AlmaLinux is the recommended development environment. +

+
+
+ +
+
+
+ Requirements +

What the server needs

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ComponentRequirement
Operating systemA *nix based system is strongly recommended for production.
PHP8.2, 8.3 or 8.4, with mod_php or FCGI (FPM). memory_limit at least + 128M.
Web serverApache 2.2+ with mod_rewrite and .htaccess support + (AllowOverride All); a default .htaccess ships in + public/. On Nginx, translate it into server configuration.
DatabaseNone. Light has no persistence layer - which is the point.
Required extensionsmbstring, plus Composer available on $PATH.
Recommended extensionsopcache; dom and simplexml for markup; + gd and exif for images; zlib, + zip, bz2 for compression; curl if you call + APIs.
+
+
+
+ +
+
+
+ Choosing +

When Light is the wrong answer

+

Light sits outside the Headless Platform on purpose. It has no sessions, no forms, no authentication + and no database - so the moment you need those, start from a skeleton that already has them rather + than growing them here.

+
+ +
+
+
+
Instead · Full-stack web

Frontend

+
+

You need logins, forms and sessions.

+

A server-rendered web starter on Mezzio and Laminas - Twig views, forms, sessions + and RBAC-guarded routes, still standing on its own outside the platform.

+ +
+ +
+
+
Instead · HTTP surface

API

+
+

You are serving clients, not pages.

+

A REST API on a PSR-15 middleware pipeline, with OAuth 2.0, RBAC, HAL payloads and + an OpenAPI 3.0 specification wired up on install.

+ +
+ +
+
+
Instead · Back office

Admin

+
+

You need to manage records, not publish copy.

+

Table-based record management with RBAC guards, CSRF-protected forms and 2FA, over a + Core module shared with the rest of the platform.

+ +
+ +
+
+
Instead · Async work

Queue

+
+

You have work that outlives a request.

+

Background workers on Symfony Messenger - a TCP listener, Valkey streams, retries + and a dead letter queue for what still fails.

+ +
+ +
+
+
Tooling · AI context

dotboost

+
+

Teach your AI tools this architecture.

+

Drop-in Claude Code configuration - ten commands, seventeen skills and permission + guardrails that keep your secrets out of the context window.

+ +
+
+
+
+ + {% if posts is defined and posts is iterable %} +
+
+
+ From the blog +

Go deeper

+
+
+ {% for post in posts %} + + +

{{ post.title }}

+

{{ post.excerpt }}

+ Read more → +
+ {% else %} +

No recent posts.

+ {% endfor %} +
+
+
+ {% endif %} + +
+
+
+ Open source, in production +

Small enough to read, real enough to ship.

+
+
+

Dotkernel Light is developed and led by the dev team at Apidemia, and released as + open source for the community. If you want to see the whole application before you commit to it, + that is the entire promise of this skeleton.

+ +
+
+
+{% endblock %} diff --git a/src/Page/templates/page/queue.html.twig b/src/Page/templates/page/queue.html.twig new file mode 100644 index 00000000..a6c099f5 --- /dev/null +++ b/src/Page/templates/page/queue.html.twig @@ -0,0 +1,580 @@ +{% extends '@layout/default.html.twig' %} + +{% set routeName = 'page::queue' %} +{% set meta = { + title: 'Dotkernel Queue | Asynchronous task queue for PHP', + description: 'Dotkernel Queue runs time-consuming work on background workers instead of inside the request cycle. ' + ~ 'A Swoole TCP daemon, Valkey streams and Symfony Messenger, with retries, a dead letter queue and reporting commands.', +} %} + +{% block title %}Dotkernel Queue{% endblock %} + +{% block stylesheets %} + +{% endblock %} + +{% block content %} + +
+
+
+ Background workers · Symfony Messenger +

Dotkernel Queue

+

+ Some operations are time-consuming and resource-intensive, and they have no business inside a + request. Dotkernel Queue accepts them over a TCP connection, stores them, and runs them on + background workers - so your platform answers the next request instead of waiting for a video to + finish encoding. +

+ +
+ PHP version for dotkernel/queue + Latest release of dotkernel/queue + License of dotkernel/queue + OSS lifecycle for dotkernel/queue +
+
+
Listener Swoole on TCP
+
Store Valkey streams
+
Worker Symfony Messenger
+
+
+ +
+
Message lifecycle
+
+ +
Your applicationJSON payload
+
TCP :8556IP whitelisted
+
Swoole daemonaccepts & stores
+
messages streamValkey · FIFO
+
Messenger workeryour handler
+
failed streamafter 3 retries
+
+
+
+
+ +
+
+
+ What it is +

A separate machine for the slow work

+

+ Dotkernel Queue is built on Symfony Messenger, integrated into Mezzio and Laminas + applications through the netglue/laminas-messenger adapter for the Laminas Service + Manager container. Work runs decoupled from the regular request-response cycle, on background + workers that can live on their own hardware. +

+

+ The main platform returns its response and stays responsive to new requests. Tasks with long + execution times are scheduled to run when resources are available, oldest first. +

+
+ Extending the power of + +
+
+
+
+ +

High request rate without overloading

+
+ +
+ +

FIFO - the oldest message runs first

+
+ +
+ +

Retries with exponential backoff

+
+ +
+ +

Failures parked, never blocking the queue

+
+
+
+
+ +
+
+
+ What belongs here +

Work that should never block a response

+

Tasks suited to the queue take extended periods to execute and may be interrupted by PHP limits such + as max_execution_time; depend on external systems that add authentication delays, slow + replies, or fail outright when a server is offline; or simply are not part of the PHP response at + all.

+
+ +
+
+

Data processing

+

Big data analytics, scientific simulations, mathematical computations - anything where the data + size or the algorithm sets the clock.

+
+
+

File & media processing

+

Video and image processing, compressing and decompressing large files.

+
+
+

Networking

+

Uploading and downloading large files, where bandwidth rather than your code is the limit.

+
+
+

Database operations

+

Imports, exports and migrations that would otherwise hold a web request open.

+
+
+

System & infrastructure

+

OS updates, software compilation, CI pipelines triggered from your application.

+
+
+

Transactional email

+

The classic case: hand the message to the queue and let the worker compose and send it while the + server moves to the next task.

+ +
+
+
+
+ +
+
+
+ How it works +

Two daemons, one stream

+

A listener that accepts messages fast, and a worker that processes them carefully. They are separate + systemd services, so you can restart either one without losing the other.

+
+ +
+
+
+
Ingest · Swoole

The TCP listener

+
+

Accepts connections and gets out of the way.

+

+ An active daemon listens for TCP connections on a port - 8556 by default - and stores incoming + messages immediately. This supports a large number of requests per second without overloading, + because accepting a message is all it does. +

+
+ +
+
+
Store · Valkey

The messages stream

+
+

An open-source key/value datastore built for this shape of work.

+

+ Messages land in the messages stream, the main queue. The worker consumes from it + in FIFO order - the oldest request first, then newer ones - and processes each according to your + application logic. Valkey is BSD-licensed and handles caching, message queues, and primary + datastore workloads. +

+
+ +
+
+
Process · Messenger

The worker

+
+

Your handler, running outside the request cycle.

+

+ A Messenger worker consumes the stream and hands each message to your handler. Because it is a + separate service on a separate machine if you want one, a slow job costs you worker time rather + than user-facing latency. +

+
+ +
+
+
Resilience · DLQ

Dead letter queue

+
+

Failures get parked, not retried forever.

+

+ Each transport defines a retry strategy. When a message exceeds its allowed retries it is + forwarded automatically to the failure transport and stored in the failed stream - + so a message that cannot succeed never blocks the ones behind it. +

+
+ +
+
+
Security · Firewall

Whitelisted senders

+
+

The port is open to your servers, not to the internet.

+

+ The documented setup adds a firewall rich rule that accepts traffic on the queue's port only + from the source addresses you name. Fast to evaluate, and a small attack surface for a service + that takes instructions. +

+
+ +
+
+
Observability · Logs

Metrics you can query

+
+

Logging that answers the operational questions.

+

+ Processed and failed messages are logged, which is what makes the reporting commands possible: + queue length, processing time per job, error rates, and throughput in jobs per second. +

+
+
+
+
+ +
+
+
+ Retry strategy +

Backoff, configured in one place

+

The transport's retry_strategy decides how hard the worker tries before a message is + handed to the dead letter queue. These are the shipped defaults.

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SettingDefaultWhat it controls
max_retries3Attempts before the message moves to the failure transport.
delay1000Initial wait before retrying a failed message, in milliseconds.
multiplier2Each retry's delay is multiplied by this factor - exponential backoff.
max_delay0Ceiling on the wait between retries; 0 means unlimited or default behaviour.
failure_transportfailedWhere messages go once they exceed the retry limit.
+
+

+ Both transports are Redis-protocol DSNs pointing at a stream - messages for new work, + failed for what could not be processed - with the serializer configurable per transport. +

+
+
+ +
+
+
+ Operations +

Console commands, over CLI or TCP

+

The same three commands answer from the shell on the queue server or from a socket on another + machine. Every flag is optional; when both --start and --end are given, + --limit is ignored.

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CommandReturnsInvocation
failedLog entries for messages that failed to process.php bin/cli.php failed --start="yyyy-mm-dd" --end="yyyy-mm-dd" --limit=int
processedLog entries for messages processed successfully.php bin/cli.php processed --start="yyyy-mm-dd" --end="yyyy-mm-dd" --limit=int
inventoryEverything currently queued in the messages stream.php bin/cli.php inventory
controlA test message, logged as processed - the quickest end-to-end check.echo "control" | socat -t1 - TCP:host:port
+
+

+ Valkey itself stays inspectable: valkey-cli gives you PING, + INFO, KEYS *, and stream commands such as + XRANGE streamName - + to read entries oldest to newest, or + XTRIM streamName MAXLEN 0 to empty a stream while keeping the key. +

+
+
+ +
+
+
+ Integration +

Two ways to hand over a message

+

+ The procedural approach opens a TCP connection, writes the JSON payload, and closes + the socket. It is simple and quick to implement - and harder to reuse as the project grows. Make + sure the message ends with a newline, or the server will keep waiting for the rest of it. +

+

+ The object-oriented approach wraps the queue in a service - a small + NotificationSystem module under Core, built on clue/socket-raw, with its + connection details injected from configuration. Handlers then inject the service and call a method + that describes the intent, not the transport. +

+ +
+
+

Smoke-test the listener

+

From your local machine, with the daemon running and your IP whitelisted:

+ echo "Hello" | socat -T1 - TCP:SERVER-IP:8556 +

+ The -T1 timeout is optional but wise: without it, a server that never replies leaves + socat waiting indefinitely. +

+
+
+
+ +
+
+
+ Deployment +

A queue server, from a bare box

+

The documented path is AlmaLinux 9 or 10 with root access, adapted accordingly for other operating + systems. Everything runs as a non-root user.

+
+ +
+
+

1 · Prepare the server

+

Update the OS, create a user with sudo permissions, and install the utilities you will need - + including socat for testing.

+ dnf update -y && useradd dotkernel +
+
+

2 · Install the runtime

+

PHP from the Remi repository, plus the Swoole and Redis PECL extensions. Verify both are loaded + before moving on.

+ dnf module enable php:remi-8.5
dnf install php-pecl-swoole6 php-pecl-redis
+
+
+

3 · Install Valkey

+

Enable and start the service, then confirm it answers.

+ dnf install valkey
valkey-cli ping
+
+
+

4 · Clone and configure

+

Clone the queue branch, then copy each .dist configuration file into place - local, + log, messenger and swoole - and fill them in.

+ git clone -b default-queue https://github.com/dotkernel/queue.git
composer install --no-dev
+
+
+

5 · Register the daemons

+

Set the paths in the shipped unit files, copy them into /etc/systemd/system/, then + enable and start both.

+ systemctl enable --now swoole.service
systemctl enable --now messenger.service
+
+
+

6 · Close the door

+

Allow SSH before starting the firewall, then permit the queue port only from the addresses that + should reach it.

+ firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="YOUR_IP" port port="8556" protocol="tcp" accept' +
+
+ +

+ Full commands, expected output and the reasoning behind each step are in the + server setup + and installation + guides. +

+
+
+ +
+
+
+ Headless Platform +

The third deployable

+

Queue processes work produced by the rest of the platform. Share the Core module with it + - copied in or added as a submodule - and your worker has the same entities, services and mail + configuration as the application that queued the job.

+
+ +
+ Shared domain layer + Core\Admin Core\App Core\Security + Core\Setting Core\User +

Keep Core in sync between the main project and the queue and every class, service and configuration + needed for message processing is already there - which is what makes a worker able to compose an + email from your own templates.

+
+ +
+
+
+
Pair with · HTTP surface

API

+
+

Dispatch work from an endpoint, answer immediately.

+

A REST API on a PSR-15 middleware pipeline, with OAuth 2.0, RBAC, HAL payloads and + an OpenAPI 3.0 specification wired up on install.

+ +
+ +
+
+
Pair with · Back office

Admin

+
+

Queue a bulk operation from an admin screen.

+

Table-based record management with RBAC guards, CSRF-protected forms and 2FA, over + the same Core module.

+ +
+ +
+
+
Pair with · Public-facing

Frontend

+
+

Queue the email your signup form triggers.

+

A web starter skeleton - user accounts, a contact form, sessions and RBAC-guarded + controller actions, rendered on the server.

+
+ Read more + Demo +
+
+ +
+
+
Smaller · Minimal

Light

+
+

A site with nothing to run in the background.

+

The smallest complete Mezzio application - routing, pipeline and Twig, six direct + dependencies and no database layer.

+
+ Read more + Demo +
+
+ +
+
+
Tooling · AI context

Dotboost

+
+

Teach your AI tools this architecture.

+

Drop-in Claude Code configuration - ten commands, seventeen skills and permission + guardrails that keep your secrets out of the context window.

+ +
+
+ +

+ The queue's own dependencies are the same small dot-* components the rest of the platform + uses - each publishing its own support status on the + packages lifecycle page. +

+
+
+ + {% if posts is defined and posts is iterable %} +
+
+
+ From the blog +

Go deeper

+
+
+ {% for post in posts %} + + +

{{ post.title }}

+

{{ post.excerpt }}

+ Read more → +
+ {% else %} +

No recent posts.

+ {% endfor %} +
+
+
+ {% endif %} + +
+
+
+ Open source, in production +

Let the slow work happen somewhere else.

+
+
+

Dotkernel Queue is developed and led by the dev team at Apidemia - built to keep + real platforms responsive under real load, and released as open source for the community.

+ +
+
+
+{% endblock %}