Migrate frontend to TypeScript with Deno-based tooling (#209)

* Migrate frontend to TypeScript with Deno-based tooling (#206)

Compiles assets/*.ts via sensiolabs/typescript-bundle (standalone SWC
binary) and adds Deno for formatting, linting, type-checking, and
tests, keeping the project's no-Node/npm approach intact. Wires all
four into CI, the Justfile, and the pre-commit hook.

* fix: build TypeScript assets before running PHPUnit in CI

The tests job ran bin/console sass:build but never typescript:build,
so var/typescript/ didn't exist and any page rendering the importmap
(e.g. backoffice/base.html.twig) errored during tests.

* test: add regression test for backoffice navbar-toggler dead target

Guards against the navbar-toggler button pointing at a collapse
target (#navbarSupportedContent) that isn't rendered for the current
user — the bug hit on the login page before #210 restructured the
nav to always render at least one item (the Releases link) regardless
of auth state.

* fix: stop hand-enumerating TS files for deno check

deno check assets/*.ts assets/controllers/*.ts assets/controllers/bo/*.ts
was duplicated in CI and the Justfile, and silently misses any new
controller subdirectory (fmt/lint/test already recurse assets/ via
deno.json). Add a top-level exclude for assets/vendor/ (respected by
all deno subcommands, unlike the per-task include/exclude blocks) so
deno check assets/ can recurse safely instead.

* fix: GitHubReleasesService date parsing and falsy release name

- Move the release-mapping array_map inside the try block so a
  malformed published_at (or any other parse failure) degrades to the
  same empty-list fallback as an HTTP failure, instead of throwing
  uncaught out of the cache callback.
- Stop treating a release literally named "0" as unnamed — the old
  `?:` fallback is falsy for that string and silently substituted the
  tag name instead.
- Render release dates in UTC explicitly; Twig's date filter otherwise
  silently converts to the app's default timezone (Europe/Amsterdam),
  which could show the wrong calendar day for releases near midnight.

* docs: add scope-creep-as-a-service rule to CLAUDE.md

Per user instruction: when a review turns up a real bug outside the
current task's scope, fix it in the same MR (with a regression test)
rather than just reporting it, unless it needs a human design call.
This commit is contained in:
2026-07-12 22:11:00 +02:00
committed by GitHub
parent 4e98909f11
commit b4a27a7c0d
44 changed files with 1473 additions and 509 deletions
+13 -2
View File
@@ -23,7 +23,7 @@ Tech Stack:
- **ORM**: Doctrine
- **Server**: FrankenPHP with Caddy
- **Container**: Docker Compose
- **Frontend**: Twig templates with SASS (via asset mapper)
- **Frontend**: Twig templates with SASS and TypeScript (via asset mapper)
- **Testing**: PHPUnit 13 with DAMA Doctrine test bundle
## Build & Development Commands
@@ -252,7 +252,8 @@ question counts as covered more than once).
- **Write the failing test first.** When fixing any PHP-reachable bug, write a PHPUnit test that reproduces the failure
before touching the production code. Fix the code until the test passes.
- Only skip a test if the bug is purely in JavaScript/frontend where PHPUnit cannot reach it.
- For bugs in `assets/*.ts` logic, write a `deno test` first instead — same TDD rule, different runner. Only skip a
test if the bug is in markup/DOM wiring that isn't worth a test per the rule below.
- Don't write tests for trivial presentational markup (e.g. asserting a tooltip/popover attribute or a CSS class exists
in a template). Tests cover behavior: routing, forms, persistence, authorization.
- Follow the pattern in `tests/Controller/Backoffice/` for controller/integration tests: log in, GET for CSRF token,
@@ -263,6 +264,11 @@ question counts as covered more than once).
- **Boy Scout Rule**: when you're already touching a file for an unrelated change, fix small nearby issues in the same
commit (e.g. a test that unnecessarily extends `WebTestCase`, a stale comment) rather than leaving them for later —
but don't let this balloon into an unrelated refactor.
- **Scope creep as a service**: when a review (yours or `/code-review`'s) turns up a real bug or gap outside the
original task's scope — even in already-merged code untouched by the current diff — fix it in the same MR rather
than just reporting it and moving on. Write a regression test first per the TDD rule above. Only leave something
unaddressed if fixing it would require a design decision only a human can make (e.g. reverting an intentional
security/access-control choice) — in that case, say so explicitly instead of silently skipping it.
### Code Style & Standards
@@ -276,6 +282,11 @@ question counts as covered more than once).
- **Twig-CS-Fixer**: Template style enforcement
- **Safe functions**: Use `thecodingmachine/safe` wrappers for standard PHP functions that return `false` on failure —
they throw exceptions instead
- **TypeScript (`assets/`)**: Compiled via `sensiolabs/typescript-bundle` (standalone SWC binary, no Node/npm).
Formatting, linting, type-checking, and tests use **Deno** (`deno fmt` / `deno lint` / `deno check` / `deno test`) —
a single standalone binary, kept dev-only (installed in the `frankenphp_dev` Docker stage, not prod), consistent
with the project's no-Node-anywhere approach. See `deno.json` for config; run via `just fix-ts` / `just check-ts` /
`just test-ts`. Tests live alongside their source as `*_test.ts` files
### Environment Configuration