Decisions
One decision and the reasoning behind it. Narrower than a proposal: a decision settles a single question rather than proposing how a whole area should work.
Accepted
23 · frozen
ADR-0001
The panel is a single system, not a panel and an engine
The panel was first built as two systems: a panel, holding the frontend, and an engine behind it holding everything
else. Each had its own repository, and the p...
ADR-0002
Dependencies select their instance through parameter attributes
A dependency's type often does not determine which instance it needs. Several implementations or instances can
share one interface: every database connection is...
ADR-0003
Mutable registries are sealed into immutable catalogues
Several parts of the engine collect things while the panel boots and consult them afterwards: the container collects
bindings and resolvers, and the configurati...
ADR-0004
The container does not implement PSR-11
PSR-11 defines a common container interface: get() and has(), keyed by a string identifier. Its value is
interchangeability. A project can swap one container fo...
ADR-0005
Configuration is held in typed objects
The engine's components need configuration, and so do modules. The code that consumes a configuration needs to rely
on its shape and on the types of its values.
ADR-0006
Environment variables are only read during bootstrap
Some values the panel needs, such as secrets, come from environment variables, supplied either through the process
environment or through a local env file. They...
ADR-0007
MySQL and MariaDB are the default database
Obsoleted by ADR-0016, ADR-0023
The engine needs a database component: support for several simultaneous connections, one of them designated the
primary connection and used by default, an objec...
ADR-0008
Database access is built directly on PDO
The panel needs database access: connections, a way to build queries, and a way to build and change the schema.
Existing database abstraction layers provide all...
ADR-0009
The panel runs as a FrankenPHP worker in a single binary
The panel is one system, shipped as a single binary, per
ADR-0001.
The panel is installed and run by the people who host it. A PHP application is usually instal...
ADR-0010
Configuration files are TOML
The panel is distributed as a single binary running FrankenPHP, per
ADR-0009. Its configuration is held in typed
configuration objects, per RFC-0002, but nothin...
ADR-0011
Identifiers are ULIDs generated in PHP
Entities need an identity model, and every entity type needs an identifier of its own.
Some rows need their identifier to exist before they are inserted, as out...
ADR-0012
Modules are installed with Composer used as a library
Modules come from two sources: bundled modules, shipped inside the binary as part of the panel's own codebase, per
ADR-0009, and external modules, installed
alo...
ADR-0013
Core features are modules
The engine is the foundation the rest of the panel builds on, and the module system is its extension mechanism, open
to first-party and third-party modules alik...
ADR-0014
Class-level attributes are memoised as presence flags
The container consults its instance cache before it reflects on a class, so it cannot tell whether a class is
liminal at the point it checks the cache. A class...
ADR-0015
Dependencies are locked and Composer is pinned
composer.lock is gitignored, and every CI job runs composer self-update && composer install && composer dump-autoload. Each run resolves dependencies fresh, aga...
ADR-0016
PostgreSQL 16 is the only supported database
The panel assumes MySQL, or a compatible MariaDB, and supports other drivers inside the database component without
exposing them, per ADR-0007. MySQL was chosen...
ADR-0017
SQL is produced by a compiler, not by the query objects
Every object in the query and schema builders produces its own SQL, per
RFC-0003. Thirty-two classes each write their own, interpolating names
straight into the...
ADR-0018
HTTP messages are bespoke, not PSR-7
PSR-7 defines common HTTP message interfaces, and PSR-15 defines handler and middleware interfaces over them. Their
value is interchangeability: middleware writ...
ADR-0019
Twig is the template engine
The panel is one server-rendered system, per
ADR-0001, so the engine has to turn templates into
HTML.
Pages are not rendered whole every time. Hypermedia intera...
ADR-0020
Resolution data is not memoised per parameter
The container supplies a constructor's or method's parameters by reflecting on each one: its type, whether it is
optional, its default, and its attributes. Each...
ADR-0021
All file access goes through Flysystem
The engine reads files. Configuration loading is the only thing that touches one today, through PHP's own functions
and a path taken from Paths. More follows as...
ADR-0023
Replace MySQL and MariaDB with PostgreSQL
Updated by ADR-0028
The panel assumes MySQL, or a compatible MariaDB, as ADR-0007
records. MySQL is the most common database and the easiest for people installing the panel to set...
ADR-0029
Require a binding for named and qualified resolutions
A binding says how an abstract is produced. Where one abstract is
produced more than one way, such as a Cache with a decorator bound to it and the cache it deco...
Proposed
6 · open for comment
ADR-0022
Store client addresses truncated by default
Several records the panel keeps are worth reading afterwards. A session record is read to tell one session from another:
whose it is, when it was last used, and...
ADR-0024
Give each external module its own schema
PostgreSQL is the panel's only database, as ADR-0023 decides. Its
schemas give a set of tables a namespace of its own inside one database, and a schema can be c...
ADR-0025
Run migrations only from commands, under maintenance
A migration changes the schema, so whatever runs one needs credentials able to change it.
The panel serves every request from long-running worker processes that...
ADR-0026
Migrate each deployment in one transaction
Code reaches an installation in two units. A new binary brings every bundled module at
once, per ADR-0009, and cannot be split: going back
means going back to t...
ADR-0027
Downgrade external modules through a migration map
An external module is installed and updated through Composer, per
ADR-0012. A newer version can bring migrations an older
version does not know, such as a new t...
ADR-0028
Run migrations in module dependency order
Modules keep tables of their own, and one module's tables can refer to another's, such as an
invoice referring to the server it bills. A table has to exist befo...