This page covers the developer tooling. For running the stack itself, see the
README. All recipes below are listed by just (run just with
no arguments to see them).
PHPStan checks the PHP code for type errors and other
bugs without running it. It is a require-dev dependency and runs inside the
php container (which has the mongodb extension the analysis needs):
just php-analyzeThe configuration lives in app/phpstan.neon. The code
is kept passing at level 8 (PHPStan's strictest level).
PHP CS Fixer checks the PHP code
for consistent formatting and style. Like PHPStan it is a require-dev
dependency and runs inside the php container:
just php-format-checkTo apply the fixes automatically:
just php-formatThe ruleset lives in
app/.php-cs-fixer.dist.php (tab indentation
plus a curated set of whitespace, casing, import and trailing-comma rules — not
a full reformat preset).
Twig CS Fixer checks the Twig
templates for consistent formatting and style. Like PHPStan it is a require-dev
dependency and runs inside the php container:
just twig-format-checkTo apply the fixes automatically:
just twig-formatThe ruleset lives in
app/.twig-cs-fixer.dist.php (tab indentation
plus delimiter/operator/punctuation spacing and trailing-whitespace rules).
The live-status UI is built from the TypeScript/React sources in
app/frontend/, bundled by esbuild
into app/public/assets/frontend/ (generated; not committed). Everything runs
in an ephemeral Node.js container (bin/node), so there are no host dependencies.
just js-buildThe first just run builds the bundles automatically; a
app/public/assets/frontend/completed marker file then prevents rebuilds on
subsequent runs. This means that after pulling changes to app/frontend/
(including when upgrading a deployment), you need to run just js-build
yourself.
While developing, rebuild on every change:
just js-build-continuouslyLinting (ESLint 9) and type-checking (strict TypeScript) together:
just js-analyzejust js-autofix applies the auto-fixable ESLint fixes, and
just js-pull-dependencies populates app/frontend/node_modules on the host
so IDE autocompletion works.
prek runs a set of quick checks before each
commit. The hooks are defined in
.pre-commit-config.yaml: built-in checks
(trailing whitespace, final newlines, YAML/JSON validity, merge-conflict
markers, accidentally-committed large files or private keys) plus the PHPStan
analysis, PHP CS Fixer, Twig CS Fixer and JS/TS analysis checks above.
prek itself is pinned and provided through mise, so the
only prerequisite is having mise installed; the recipes install prek into a
project-local data directory (var/mise) on first use.
Install the git hook so the checks run automatically on git commit:
just prek-install-git-pre-commit-hookSome hooks fix issues in place (e.g. trailing whitespace). When that happens the commit is aborted so you can review and stage the fixes, then commit again.
Run the hooks manually anytime:
just prek-run-on-staged # only the staged files
just prek-run-on-all # the whole repositoryLogging goes through Monolog and is written
to the container's stderr — never to log files — so it flows to
systemd-journald (via the devture-nagadmin service) like every other container's
output, and the journal handles rotation/retention.
In dev the application logs live at notice level, so a docker compose logs -f php tail shows warnings, errors and uncaught exceptions as they happen without
the per-request router/security debug chatter. In prod the logs are buffered
and only flushed when an error occurs (so a clean request logs nothing), then the
full debug trail for that request is emitted. Tune both in
app/config/packages/monolog.yaml.
The php-fpm pool sets catch_workers_output so the application's stderr is
emitted on the php container (not bounced back through nginx as [error]).