История коммитов

.
fix(security): add CSRF tokens to all POST forms
60 POST forms in 58 templates had no csrf_token field, among them login, registration, password restore and the whole downloads, library, mail and album modules. Adds the hidden field to every one of them, a csrf-token meta tag to both layouts and an X-CSRF-Token axios default in both globals.js so JSON requests can carry the token too. Behaviour is unchanged until the CSRF middleware is enabled.
.
chore: drop unused laminas packages
laminas-servicemanager and laminas-uri were required directly but never used in code; laminas-escaper leaves as a transitive dependency of laminas-uri.
.
chore: delete the plans of finished refactorings
The admin, album, collections, profile and pagination migrations are done, and the
guestbook analysis records its own completion. Nothing in these documents is still
open, so they have nothing left to track.
.
docs: update the documentation submodule
Broken code samples in the configuration article, and the test.php recipe now points
at the public directory.
.
docs: update the documentation submodule
The raw tags around the Twig examples were printed on the pages instead of being
honoured, so they are gone.
.
docs: update the documentation submodule
Two pages of the guide: the module creation walkthrough no longer wires the
translation domain from a controller constructor, and the theme build entries are
declared in the theme manifest rather than in vite.config.js.
.
chore: ignore the guestbook uploads
Attachments of guestbook posts are runtime data, like the uploads of the other
modules already listed here.
.
chore: delete the twig migration plan
The migration is finished, so the working document has nothing left to track.
.
refactor(http): enter the module context from the route, not the constructor
A controller is a shared service, so its constructor runs once per process while
the page it builds is answered many times. initModule() lived there, and with it
the default translation domain of the page: every request after the first one in a
process rendered with the domain of whichever controller was constructed last, so
pages came out half translated. AdminControllerContext added the first breadcrumb
of the panel from the same place, with the same result. Under FPM the process ends
with the request and none of this shows; RequestIsolationTest has been red on it.

The setup a page needs because of where it lives now belongs to the request cycle:

* every route a module declares is stamped with that module, taken from the path
of the file declaring it (RouteCollectorFactory -> RouteCollection::setModule()
-> Route::MODULE_ATTRIBUTE), and the matcher reports it apart from the action
parameters;
* the kernel enters ModuleContext for the matched route before anything renders,
so a guard rejecting the request answers in the right language too;
* AdminAreaContext (the panel domain and its first breadcrumb) is entered by the
access guards of the panel. The two routes declared outside them keep working:
the login screen needs only the domain of its own module, and the system check
enters the area itself.

ControllerContext and AdminControllerContext are deleted along with all 214 calls
to initModule(). Six news controllers built breadcrumbs in their constructors —
those moved into the actions. ControllerConstructorTest keeps the rule: a
controller constructor declares dependencies and calls none of them.

The .pot files carry no new messages; their source references moved with the code.
.
fix(http): keep the 404 status when the error template fails
A theme may override the error page, and a broken override turned every 404 into a
500. The render is now guarded: the failure is logged and the page degrades to plain
text, so the status a crawler and a browser act on survives.