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.
A ready-to-go admin skeleton - table-based CRUD screens for your records, plus the pieces for reports and dashboards.
Background job processing for the platform - dispatch work from API or Admin and run it in a separate worker. Built on Symfony Messenger.
@@ -187,11 +190,12 @@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.
The smallest complete Mezzio application - PSR-15 pipeline, routing, and templating, nothing to strip out. A real starting point for a simple site.
A web starter skeleton for full-stack applications on Mezzio and Laminas - server-rendered Twig views, forms, sessions, and RBAC-guarded routes.
+ 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. +
+ ++ 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. +
+Table-based record management
+Every shipped form validated and CSRF-guarded
+Shares the Core module with API
+Twig templates, npm asset pipeline
+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.
+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.
+
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.
+
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.
+
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.
+
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.
+
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.
+
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.
+
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.
+
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.
+
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.
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.
+AdminManaging the users that hold the admin role - the accounts stored in the
+ admin database table.
UserManaging the platform's own users, stored separately in the user table. Two
+ audiences, two models, no overloaded role column.
AppCore application functionality: authentication, rendering and error reporting.
+DashboardThe default landing page - its layout, widgets and rendering logic.
+PageReusable interface elements: dropdowns, modals, error displays, tooltips.
+SettingSaving and reading display settings for the administration interface.
+The full walkthrough, with expected output for every command, is in the documentation. This is the + shape of it.
+Into an empty directory of your choosing.
+git clone https://github.com/dotkernel/admin.git .
+ Run it from the CLI so the setup prompts stay interactive. Decline the ConfigProvider injection - + Dotkernel ships its own.
+composer install
+ For local work only. composer development-status tells you where you stand, and it
+ must stay off in production.
composer development-enable
+ 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.
Migrations build the schema; fixtures populate the default roles, OAuth clients and accounts.
+php ./vendor/bin/doctrine-migrations migrate
php ./bin/doctrine fixtures:execute
+ 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.
+
| Component | +Requirement | +
|---|---|
| Operating system | +A *nix based system is strongly recommended for production. | +
| PHP | +8.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 server | +Apache 2.2+ with mod_rewrite and .htaccess support
+ (AllowOverride All) - a default .htaccess ships in
+ public/. On Nginx, translate it into server configuration. |
+
| Database | +MariaDB 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 extensions | +mbstring, the CLI SAPI for cron jobs, and Composer available on
+ $PATH. |
+
| Recommended extensions | +opcache; 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. +
++ 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. +
+cookie_httponly, cookie_samesite and
+ cookie_secure in session.global.php.composer development-status.cors.global.php.*.local.php - the *.global.php and
+ *.php.dist files are committed.npm audit.+ 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.
+
+ 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. +
+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.
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.
+ +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.
+ +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.
+ +No records to manage, just pages.
+The smallest complete Mezzio application - routing, pipeline and Twig, six direct + dependencies and no database layer.
+ ++ 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. +
+{{ post.excerpt }}
+ Read more → + + {% else %} +No recent posts.
+ {% endfor %} +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.
+ 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. +
+ ++ 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. +
+Doctrine ORM, not Active Record
+Explicit wiring, no runtime magic
+Auth, docs and errors on install
+MIT licensed, actively maintained
+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.
+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.
+
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.
+
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.
+
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.
+
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.
+
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.
+
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.
+
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.
+
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.
+
The latest release moves identifiers to native database UUIDs and broadens platform support.
+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 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.
+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.
+A configurable string can be prepended to every table name - the practical requirement when an + API shares a database with an existing application.
+Multi-connection setups spell out which connection is the default and how to switch to another, + based on scenarios from real projects.
+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.
++ 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. +
+ ++ 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. +
+| Feature | +API Tools (formerly Apigility) | +Dotkernel API | +
|---|---|---|
| First release | 2012 | 2018 |
| Architecture | MVC, event driven | Middleware |
| OSS lifecycle | Archived | |
| PHP version | ≤ 8.2 | |
| Style | REST, RPC | REST |
| Change management | Versioning | Deprecations (API evolution) |
| Documentation | Swagger (automated) | OpenAPI 3.0 (Swagger) and Postman (manual) |
| License | BSD-3 | MIT |
| Default DB layer | laminas-db | doctrine-orm 3.x |
| Authorization | ACL | RBAC guard |
| Authentication | HTTP Basic / Digest, OAuth 2.0 | OAuth 2.0 |
| Endpoint generator | Yes | dot-maker |
| PSR standards | PSR-7 | PSR-7, PSR-15 |
+ Comparison drawn against Dotkernel API v7. Read the reasoning behind each row in + Dotkernel API versus Laminas API Tools. +
+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.
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.
+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.
+ +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.
+ +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.
+ +A presentation site with no API behind it.
+The smallest complete Mezzio application - routing, pipeline and Twig, six direct + dependencies and no database layer.
+ +
+ Every layer is also available on its own - see the
+ packages lifecycle for the support
+ status of each dot-* package.
+
Handlers implement RequestHandlerInterface and return ResponseInterface.
+ The whole request path is middleware you can read top to bottom.
The application is container-based, with dependencies declared in each module's
+ ConfigProvider, and classes located by autoloader.
Errors are logged through LoggerInterface via
+ dot-errorhandler, centralizing how failures are recorded.
Static analysis runs at a strict rule level, in line with the choice made by projects like + Doctrine and Composer.
+The skeleton ships with a test suite you extend rather than start, so new endpoints have + somewhere to be tested from day one.
+Updates arrive with bugfixes and improvements from the PHP community, and breaking changes come + with companion articles and upgrade steps.
+ ++ 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. +
+ +
+ 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. +
+{{ post.excerpt }}
+ Read more → + + {% else %} +No recent posts.
+ {% endfor %} +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.
++ 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. +
+ +
+ 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. +
+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
+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.
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.
+
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/.
+
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.
+
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.
+
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.
+
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.
+
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.
| Command | +settings.json says | +guard-bash.sh does | +
|---|---|---|
| git rebase | ask | blocks |
| doctrine-migrations migrate / execute | ask | blocks |
| fixtures:execute, schema:drop, schema:update | ask, via bin/cli.php | blocks |
| composer development-enable / -disable | — | blocks |
| pip install, git checkout --, git filter-branch | — | blocks |
+ 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.
+
/dk-* commandsEach one runs only when you ask for it.
+| Command | +What it does | +
|---|---|
| /dk-bootstrap | Fresh clone to a running install. |
| /dk-module | Plan a new module - dot-maker first. |
| /dk-route | Add a fully wired endpoint or page. |
| /dk-trace | Trace a request through pipeline, handler and response. |
| /dk-test | Write and run tests. |
| /dk-document | Write or update a feature doc. |
| /dk-check | Run and fix the QA gate. |
| /dk-deprecate | Make an evolution-pattern breaking change. |
| /dk-review | Pre-PR convention review - read-only by design. |
| /dk-hygiene | Encoding and line-ending audit. |
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.
| Skill | +Covers | +
|---|---|
| application-variants | Detecting API vs Admin vs Frontend vs Light vs Queue. |
| module-structure | Where code goes: application module vs Core, and the wiring. |
| handler-naming | Both naming dialects, routes, authorization keys. |
| doctrine-entities | Entities, enums and DBAL types, repositories, migrations. |
| input-validation | InputFilters, Inputs, forms, CSRF, query whitelisting. |
| responses | HAL and collections, or templates and redirects; errors. |
| openapi | swagger-php attributes, for apps that publish OpenAPI. |
| feature-docs | Feature docs: template, where they live, staleness. |
| testing | Unit and functional patterns, test config, coverage matrix. |
| evolution-pattern | Sunset headers instead of versioning. |
| security | Auth, authorization, secrets, CORS, dependencies. |
| dot-maker | composer make … and the manual steps after it. |
| core-submodule | Core layering rules and git submodule mechanics. |
| psr-standards | PSR-1/3/4/6/7/11/12/15/16/17 as applied here. |
| qa-gate | cs-check, static analysis, tests, and forbidden "fixes". |
| troubleshooting | A symptom to cause table. |
| dependency-policy | The 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.
+
+ 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.
+
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.composer show --available is in the allow or deny list, so
+ both prompt. That is deliberate - expect a prompt the first time.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.
+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
+ 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
+ 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
+ Then copy the example file if you want personal settings that survive an update.
+echo '.claude/settings.local.json' \
+ >> .git/info/exclude
+ Not bundled - install it yourself, globally or as a project devDependency. Until the binary + resolves, the hook exits silently.
+npm install -g markdownlint-cli2
+ 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.
+
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.
+
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.
+
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. +
+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.
+
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.
+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.
+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.
+ +Forms, CSRF, route-name authorization keys.
+Table-based record management with RBAC guards, CSRF-protected forms and 2FA, over + the shared Core module.
+ +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.
+ +Minimal modules, config-declared template routes.
+The smallest complete Mezzio application - routing, pipeline and Twig, six direct + dependencies and no database layer.
+ +{{ post.excerpt }}
+ Read more → + + {% else %} +No recent posts.
+ {% endfor %} +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.
+ ++ 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. +
+ ++ 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. +
+User accounts, from register to unregister
+Action controllers, not request handlers
+CSRF and reCAPTCHA on public forms
+GDPR anonymization out of the box
+These are the parts you would otherwise spend your first two weeks assembling, already working + together in a fresh install.
+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. +
+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.
+
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.
+
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.
+
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.
+
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.
+
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.
+
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.
+
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.
+
+ 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. +
+ +anonymous plus the current UNIX timestamp - for example
+ anonymous1725980747.userAnonymizeAppend -
+ anonymous1725980747@example.com.
+ 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.
+
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.
UserLogin, registration and account management - the largest module, and the one worth reading + first.
+AppCore functionality: authentication, rendering and error reporting.
+ContactThe contact us form, from validation through to the outgoing mail.
+PageDisplaying a page - the minimal case, for static copy.
+PluginPlugin functionality for dynamic forms and templates.
+Controller, Entity, Repository and
+ Service folders, plus InputFilter, EventListener,
+ Helper, Command or Factory as needed.
The documentation walks through every command with its expected output. This is the sequence.
+Git refuses a non-empty directory, and you need write permissions on it.
+git clone https://github.com/dotkernel/frontend.git .
+ From the CLI, so the prompts stay interactive. Decline the config provider injection - Frontend + ships its own.
+composer install
+ Sets debug on, configuration caching off, and clears any existing cache.
+composer development-enable
+ 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.
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
+ 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.
+
| Component | +Requirement | +
|---|---|
| Operating system | +A *nix based system is strongly recommended for production. | +
| PHP | +8.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 server | +Apache 2.2+ with mod_rewrite and .htaccess support
+ (AllowOverride All); a default .htaccess ships in
+ public/. On Nginx, translate it into server configuration. |
+
| Database | +Tested 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 extensions | +mbstring, the CLI SAPI for cron jobs, and Composer on
+ $PATH. |
+
| Recommended extensions | +opcache; 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+. +
+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.
+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.
+ +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.
+ +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.
+ +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.
+ +{{ post.excerpt }}
+ Read more → + + {% else %} +No recent posts.
+ {% endfor %} +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.
++ 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. +
+ ++ 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. +
+Six direct dependencies
+No database layer to configure
+A new page is one config line and one template
+Twig layout, Vite asset pipeline
+This is the entire direct dependency list. Every one of them is doing a job you would have had to + solve anyway.
+The PSR-15 middleware microframework the whole application runs on.
+FastRoute integration - matches the URL and method against your registered routes.
+Twig integration for Mezzio. Every template is a .html.twig file.
Logging error handler for middleware applications - daily log files, configured in one place.
+Collects and merges configuration from every source into one array.
+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.
+
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.
+| # | +Step | +What happens | +
|---|---|---|
| 1 | HTTP request | public/index.php bootstraps the application, loads configuration, and creates the Mezzio application instance. |
| 2 | Service container | Factories, aliases and delegators are registered; every service is configured and ready to use. |
| 3 | Route registration | All available routes and their allowed methods are read and registered dynamically, managed by FastRoute. |
| 4 | Middleware pipeline | config/pipeline.php defines the order middleware runs in, and so how requests travel and responses come back. |
| 5 | Routing | FastRoute matches the URL and method against the registered routes to find the handler. |
| 6 | Handler invocation | The matched route name is pulled off the request and passed to the renderer - page::about becomes the template to render. |
| 7 | Custom logic | Your business logic runs in the handler, calling whatever services it needs. |
| 8 | Template rendering | Twig loads the template, applies the layout, renders the blocks and includes the partials. |
| 9 | Response creation | An HtmlResponse is built with status, headers and the rendered HTML body. |
| 10 | Response pipeline | The response flows back out through the middleware stack, which can still change headers, cookies or compression. |
| 11 | Response emitter | The 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.
+
+ 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.
+
In config/autoload/local.php, under the routes → page 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.
+
The parts you actually edit on a presentation site, and where each of them lives.
+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.
+
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.
+
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.
+
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.
+
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.
+
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.
+
No database to create, no fixtures to seed. Clone, install, set a URL, open it.
+Git refuses a directory that is not empty, and you need write permissions on it.
+git clone https://github.com/dotkernel/light.git .
+ Run it from the CLI so the prompts stay interactive. Decline the config provider injection - + Light already includes its own.
+composer install
+ Local work only. composer development-status reports where you stand.
composer development-enable
+ Point $baseUrl in config/autoload/local.php at your virtual host.
The two directories the application writes to. Most first-run errors are this and nothing + else.
+chmod -R 777 ./data ./log
+ 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.
+
| Component | +Requirement | +
|---|---|
| Operating system | +A *nix based system is strongly recommended for production. | +
| PHP | +8.2, 8.3 or 8.4, with mod_php or FCGI (FPM). memory_limit at least
+ 128M. |
+
| Web server | +Apache 2.2+ with mod_rewrite and .htaccess support
+ (AllowOverride All); a default .htaccess ships in
+ public/. On Nginx, translate it into server configuration. |
+
| Database | +None. Light has no persistence layer - which is the point. | +
| Required extensions | +mbstring, plus Composer available on $PATH. |
+
| Recommended extensions | +opcache; dom and simplexml for markup;
+ gd and exif for images; zlib,
+ zip, bz2 for compression; curl if you call
+ APIs. |
+
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.
+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.
+ +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.
+ +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.
+ +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.
+ +{{ post.excerpt }}
+ Read more → + + {% else %} +No recent posts.
+ {% endfor %} +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.
++ 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. +
+ +
+ 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. +
+High request rate without overloading
+FIFO - the oldest message runs first
+Retries with exponential backoff
+Failures parked, never blocking the queue
+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.
Big data analytics, scientific simulations, mathematical computations - anything where the data + size or the algorithm sets the clock.
+Video and image processing, compressing and decompressing large files.
+Uploading and downloading large files, where bandwidth rather than your code is the limit.
+Imports, exports and migrations that would otherwise hold a web request open.
+OS updates, software compilation, CI pipelines triggered from your application.
+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.
+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.
+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. +
+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.
+
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. +
+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.
+
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. +
+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. +
+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.
| Setting | +Default | +What it controls | +
|---|---|---|
max_retries |
+ 3 | +Attempts before the message moves to the failure transport. | +
delay |
+ 1000 | +Initial wait before retrying a failed message, in milliseconds. | +
multiplier |
+ 2 | +Each retry's delay is multiplied by this factor - exponential backoff. | +
max_delay |
+ 0 | +Ceiling on the wait between retries; 0 means unlimited or default behaviour. | +
failure_transport |
+ failed |
+ Where 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.
+
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.
| Command | +Returns | +Invocation | +
|---|---|---|
failed |
+ Log entries for messages that failed to process. | +php bin/cli.php failed --start="yyyy-mm-dd" --end="yyyy-mm-dd" --limit=int |
+
processed |
+ Log entries for messages processed successfully. | +php bin/cli.php processed --start="yyyy-mm-dd" --end="yyyy-mm-dd" --limit=int |
+
inventory |
+ Everything currently queued in the messages stream. |
+ php bin/cli.php inventory |
+
control |
+ A 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.
+
+ 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.
+
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.
+
The documented path is AlmaLinux 9 or 10 with root access, adapted accordingly for other operating + systems. Everything runs as a non-root user.
+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
+ 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
+ Enable and start the service, then confirm it answers.
+dnf install valkey
valkey-cli ping
+ 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
+ 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
+ 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. +
+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.
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.
+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.
+ +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.
+ +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.
+ +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.
+ +
+ 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.
+
{{ post.excerpt }}
+ Read more → + + {% else %} +No recent posts.
+ {% endfor %} +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.
+