chore: post-ExtJS consistency — remove leftovers, migrate stragglers, describe the present#490
Conversation
There was a problem hiding this comment.
Code Review
This pull request cleans up the codebase by removing all remaining references, comments, and configurations related to the legacy ExtJS frontend, finalizing the transition to the SolidJS UI. Key changes include updating documentation, Docker configurations, dependency manifests, and E2E tests, as well as refactoring the CSV export template. Feedback highlights an issue in the CSV export template where looping over external labels in the row data can lead to a variable number of columns and malformed CSVs, alongside a potential Twig runtime exception if the labels are null.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #490 +/- ##
============================================
+ Coverage 83.99% 84.14% +0.15%
+ Complexity 2816 2814 -2
============================================
Files 188 187 -1
Lines 7603 7588 -15
============================================
- Hits 6386 6385 -1
+ Misses 1217 1203 -14
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR performs a post-ExtJS cleanup/consistency pass after the SolidJS/Vite migration: removing stale stack references and leftover artifacts, moving remaining “build output” into proper source locations, and updating docs/config to reflect the current runtime/tooling contract.
Changes:
- Fold the previously-committed
public/buildheader CSS into the Vite/Solid frontend source tree, and remove remainingpublic/buildreferences (including CI artifacts). - Remove server-side nav “active” state (previously hardcoded) and rely on client-side route-based syncing; add coverage for drawer/icon/nav active state.
- Update configuration/docs/dependency wiring to reflect the current stack (logo location, Node version, remove
http_discovery, refresh e2e documentation).
Reviewed changes
Copilot reviewed 62 out of 65 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| templates/ui/index.html.twig | Drops legacy header.css asset; stops passing hardcoded active |
| templates/partials/theme-init.html.twig | Updates theming description for current shells/pages |
| templates/partials/header.html.twig | Removes server-side active markup; relies on data-nav syncing |
| templates/partials/header-behavior.html.twig | Updates header-behavior docs to current chrome-only usage |
| templates/partials/density-init.html.twig | Updates density docs to current Solid shell contract |
| templates/export.csv.twig | Removes dead labels header loop from CSV header |
| templates/bundles/TwigBundle/Exception/error403.html.twig | Restyles 403 page and applies saved theme pre-paint |
| symfony.lock | Removes stale Flex recipe entries (discovery, messenger) |
| src/Repository/EntryRepository.php | Updates comments to remove ExtJS terminology |
| src/EventSubscriber/ExceptionSubscriber.php | Updates comment describing JSON-error routing |
| src/Dto/InterpretationFiltersDto.php | Updates comment for start pagination meaning |
| src/Dto/EntrySaveDto.php | Updates comments to be client-agnostic (no ExtJS mention) |
| src/Controller/Tracking/SaveEntryAction.php | Updates comments describing save semantics |
| src/Controller/Default/IndexAction.php | Updates docs for root redirect into Solid SPA |
| src/Controller/Default/GetDataAction.php | Updates docs for row-wrapped response shape |
| src/Controller/Default/ExportCsvAction.php | Stops passing unused labels template variable |
| README.md | Updates stack description and Node requirement |
| public/images/logo-netresearch.svg | Adds/moves default logo into public/images/ |
| public/build/css/header.css | Removes committed Encore-era header CSS artifact |
| package.json | Tightens Node engine requirement for root tooling |
| frontend/vite.config.ts | Updates build-output comment to current directory structure |
| frontend/src/styles/header.css | Adds unminified header chrome CSS to Vite sources |
| frontend/src/styles/app.css | Imports header defaults before compaction overrides |
| frontend/src/pages/Tracking.tsx | Removes ExtJS references in comments/docs |
| frontend/src/pages/Tracking.test.tsx | Aligns test comments with current (non-ExtJS) behavior |
| frontend/src/nav.ts | Extends route-based active syncing to mobile drawer links |
| frontend/src/nav.test.ts | Adds tests covering active-state syncing across header variants |
| frontend/src/lib/timeParse.ts | Updates docs for date/row formats (non-ExtJS wording) |
| frontend/src/lib/shortcuts.ts | Drops obsolete Alt+D/E shortcuts and updates descriptions |
| frontend/src/lib/dateFormat.ts | Updates token-table comment wording |
| frontend/src/header.ts | Updates docs/comments to current SPA header behavior |
| frontend/src/header.test.ts | Updates test description wording |
| frontend/src/App.tsx | Updates theming comment to current ownership model |
| frontend/src/api/queries.ts | Updates docs for row-wrapped API response shapes |
| frontend/README.md | Updates frontend docs to current stack and build output path |
| frontend/messages/en.json | Removes unused shortcut strings |
| frontend/messages/de.json | Removes unused shortcut strings |
| e2e/worklog.spec.ts | Updates E2E description wording to current UI |
| e2e/settings.spec.ts | Updates E2E description wording; removes ExtJS references |
| e2e/navigation.spec.ts | Updates E2E description and removes ExtJS tab-bar assertions |
| e2e/interpretation.spec.ts | Updates E2E description wording |
| e2e/helpers/navigation.ts | Updates helper docs to current navigation model |
| e2e/helpers/grid.ts | Updates helper docs to current worklog grid model |
| e2e/helpers/date.ts | Removes outdated ExtJS reference from helper docs |
| e2e/helpers/auth.ts | Updates helper docs for current post-login landing |
| e2e/export.spec.ts | Updates E2E description wording for export flow |
| e2e/E2E_TEST_PLAN.md | Rewrites plan into an accurate suite map and current gaps |
| e2e/admin/admin-ui.spec.ts | Updates E2E description wording |
| e2e/admin-inline-edit.spec.ts | Updates E2E description wording |
| Dockerfile | Updates build comments to current Vite/Solid-only asset build |
| docker-bake.hcl | Aligns Node version default to 26 |
| config/services.yaml | Updates default logo URL path to /images/... |
| config/reference.php | Regenerates reference config types to remove Encore config |
| config/packages/twig.yaml | Removes unused bootstrap form theme configuration |
| config/packages/pentatrion_vite.yaml | Updates comments to reflect current single-frontend reality |
| config/packages/http_discovery.yaml | Removes unused PSR-17 discovery wiring |
| composer.json | Removes unused allow-plugin entry |
| .sonarcloud.properties | Updates analysis exclusions after old trees removal |
| .nvmrc | Aligns local Node version to 26 |
| .github/workflows/ci.yml | Removes public/build prep/artifacts; keeps Vite build step |
| .github/dependabot.yml | Updates root npm lockfile description to current usage |
| .github/copilot-instructions.md | Updates repo instructions to current SolidJS/Vite stack |
| .github/codeql/codeql-config.yml | Removes ignore entries for deleted ExtJS/build trees |
| .env | Updates default APP_LOGO_URL to new images path |
The ExtJS shell and its Encore build are gone; align docs and tool config with the SolidJS/Vite reality: - README.md: tech stack now lists SolidJS, TypeScript, Vite, Tailwind CSS instead of the removed ExtJS/Stimulus/SCSS/Encore stack. - CodeQL config: remove paths-ignore entries for the deleted assets/js/ext-js and public/build/js/ext-js trees. - SonarCloud: drop the assets/js/** exclusion (tree deleted) and the ExtJS rationale from the scope comment. - ci.yml / Dockerfile / pentatrion_vite.yaml: update comments that described the Encore build as still being retired. - twig.yaml: remove the unused bootstrap_4_layout form theme (no Twig form rendering exists; the login form is hand-written HTML). - config/reference.php: regenerate — drops the stale WebpackEncoreConfig shape and picks up the when@profiling env block. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
public/build/css/header.css was a frozen, minified Encore artifact with no source in the tree (committed static in 4112bc2) and the last live consumer of the legacy public/build CSS path. Header styling was split across two build systems: this file loaded first via a plain <link>, then overridden by app.css rules from the Vite bundle. Move it into the Vite build as frontend/src/styles/header.css: - un-minified 1:1 (re-minified output verified byte-identical), except the dropped '#header,#header-body{overflow:visible!important}' rule — those element IDs were the ExtJS viewport regions and match nothing in the SPA. The #nrnavi corporate-nav iframe rule is kept. - imported at the top of app.css so the compaction/sidebar overrides keep winning the cascade (verified in the emitted bundle: chrome defaults precede the ultra-compact overrides). - drop the legacy <link> from ui/index.html.twig; Vite emits the CSS via vite_entry_link_tags('app'). public/build now only holds the committed logo images. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
The header partials and their hydration code still described themselves as 'framework-neutral, shared by BOTH shells (ExtJS and SolidJS)'. The ExtJS shell is gone; reword the docblocks to describe the current architecture (server-rendered chrome that paints before the Vite bundle loads, hydrated by header.ts/nav.ts), aligned with font-init's wording. Comment-only: header.html.twig, header-behavior.html.twig, theme-init.html.twig, density-init.html.twig, App.tsx, header.ts, nav.ts. The re-include idempotency guard keeps its (now re-include-only) justification. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
The Help page and shortcuts dialog still listed Alt+D (delete) and Alt+E (edit) in the worklog accelerators. Those were 'classic-only' shortcuts of the removed ExtJS grid — Tracking.onGridShortcut handles only Alt+C/P/R/X/I (plus Alt+A via the header add shortcut), so the two entries documented shortcuts that no longer work anywhere. Drop them and their now-unused help_sc_delete/help_sc_edit messages (en+de). Also correct remaining comments that described ExtJS as still running (App.tsx theming note, header.ts shortcut docblock, Tracking.tsx grid docblock). Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
The header's server-side 'active' parameter was hardcoded to 'month' (ui/index.html.twig) and overwritten by nav.ts syncNav() within a tick of hydration — on any non-month route it briefly marked the WRONG item (including a wrong aria-current for screen readers). Drop the parameter and all its template conditionals; the route is the single source of truth. This also fixes a real bug it was masking: syncNav() never updated the mobile drawer links, so the drawer permanently highlighted 'Overview' regardless of route. Include .drawer-link[data-nav] in the sync and add nav.test.ts covering bar, icon and drawer links (346 frontend tests green). Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
public/build existed only to serve two images from the retired asset pipeline's output path. Give the logo a proper static home instead of explaining the old path in comments: - move logo-netresearch.svg to public/images/ and point the app_logo_url default (services.yaml) and APP_LOGO_URL (.env) at it - delete logo.png (referenced by nothing) - drop every remaining public/build reference: CodeQL + SonarCloud exclusions, the CI prepare/artifact steps, and the describing comments in ci.yml, Dockerfile, pentatrion_vite.yaml and header.css - copilot-instructions.md: the frontend section still described the Encore pipeline; describe the SolidJS/Vite build instead - frontend/README.md: correct the output path (public/build-ui) Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Comments and test names across the frontend and e2e suite still narrated
the ExtJS era ('the ExtJS shell was removed', 'migrated out of the ExtJS
shell', 'like the ExtJS header', 'shared with the ExtJS shell'). Rewrite
each to state the current contract instead: the wire format (row-wrapped
[{<rowKey>: {...}}]), the endpoint semantics (/tracking/delete reads
form params; /getData rows carry d/m/Y), and the current UI (worklog
grid at /ui/tracking).
Also drop navigation.spec.ts's assertion that no '.x-tab-bar' exists —
it guarded the removal of a component that can no longer reappear — and
the doc reference to a nonexistent keyboard.spec.ts.
The one remaining ExtJS mention (security.yaml logout comment) is
addressed by the logout-CSRF change.
Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
- config/packages/http_discovery.yaml wired Http\Discovery\Psr17Factory and six PSR-17 aliases, but php-http/discovery is not installed and nothing type-hints those interfaces (the Jira integration uses Guzzle, whose OAuth1 middleware ties it to Guzzle anyway) — the container only compiled because the unreferenced services were pruned. Remove the file, the stale allow-plugins entry and the orphaned symfony.lock recipe, plus the symfony/messenger recipe (package equally absent). - Node: one version everywhere — .nvmrc, docker-bake NODE_VERSION and the root engines field now all say 26 (nodesource setup_26.x verified); README described Node as the asset compiler, but assets build with bun — Node serves the Playwright e2e tooling. - e2e/E2E_TEST_PLAN.md: rewritten to describe the actual suite (14 specs + 8 helpers); it still listed spec files that no longer exist and proposed a structure that was never adopted. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
error403.html.twig still carried its original blue/gray panel styling (tahoma font stack, #15428b headers, gradient panel chrome) and ignored the saved light/dark preference. Restyle with the app's light-dark() palette and 44px targets, and include partials/theme-init.html.twig so the page follows the user's theme like login and the SPA shell do (theme-init no-ops its button wiring when no #theme-cycle exists). Also drop the never-emitting labels header loop from export.csv.twig — ExportCsvAction always passed labels=null, and the functional test already asserts a header without those columns — and stop passing the variable. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
The buildx lint rule InvalidDefaultArgInFrom flagged PHP_BASE_IMAGE and COMPOSER_IMAGE on every CI build (6 annotations per run, also on main). The default-less ARGs are a documented design choice — docker-bake.hcl is the single source of truth for versions — so skip that rule via the check directive instead of duplicating the pins. Also fix the README manual-install block: it still called for Node 22 and 'npm run build' (no such root script); the frontend builds with bun. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
d6b6b69 to
1fb9844
Compare
Verified against the dependency graph and the runtime (audit findings, each independently re-verified): - require ext-pdo_mysql: the app connects via mysql:// DSNs and nothing else provides the extension (not bundled in php:8.5-fpm; no lock package requires it) — the manifest understated a hard dependency. - drop symfony/expression-language: no '@=' expressions, no route conditions, no security expressions anywhere; container lint verified green in dev/prod/test without it. - drop dg/bypass-finals (dev): BypassFinals::enable() is called nowhere (no bootstrap call, no phpunit extension block) — inert since install. - move symfony/stopwatch to require-dev: only the dev-context performance suite uses it (stays in the lock's prod section via doctrine/migrations). - drop the 'security-check' script: it curl-piped a third-party phar at a pinned 2-major-old version; composer audit already gates via captainhook and make audit. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
serialize-javascript, uuid and http-proxy-middleware targeted advisories in the retired build toolchain's dependency tree. The root manifest now holds only @playwright/test + @axe-core/playwright, and none of the three packages exists anywhere in package-lock.json — the overrides matched nothing. Verified: npm install --package-lock-only leaves the resolved tree untouched (the only lock delta is the engines field catching up with the Node-26 pin). Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
- docker-php-ext-install xml recompiled an extension the php:8.5-fpm base image already ships statically (verified by running the bare image: xml/dom/simplexml/libxml all loaded), and libxml2-dev existed only for that build. If a future base ever dropped ext-xml, composer would fail loudly (symfony/framework-bundle requires it). - tools/dev/profiling repeated the composer COPY they already inherit from the deps stage. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Audit findings, each independently re-verified: - doctrine.yaml: default_table_options used 'collate' — DBAL 4 reads only 'collation' (AbstractMySQLPlatform), so the option was silently ignored. Rename the key. - compose.yml app-e2e DSN: serverVersion mariadb-12.1.0 → 12.1.2, matching .env.test and the mariadb:12.1 images. - config/routes/dev/framework.yaml only re-imported routes.yaml, which MicroKernelTrait already loads unconditionally — the dev routes were registered twice. Delete. - config/packages/twig_extensions.yaml registered nothing (an empty _defaults block plus commented-out lines for the abandoned twig/extensions package). Delete. - .env: drop the symfony/messenger recipe block (package removed); document APP_ENCRYPTION_KEY in .env and .env.example (referenced by services.yaml and four docs, previously undocumented in env files). - .env.test: drop APP_RUNTIME_ENV (symfony/runtime is not installed; nothing reads it). - phpat.php: drop the Sensio namespace selector (sensio/framework-extra-bundle is long gone). - routes.yaml: comments referenced Symfony 7.3/6.4 conventions on a Symfony 8.1 app and announced a login_check removal that never came — state the actual reason it stays. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
- src/Controller/ControllingController.php: a routeless shim of
protected static spreadsheet helpers with no subclass and no caller
(routes live in Controlling\ExportAction; the web test never imports
the shim).
- translations/activities.{de,en}.yml: the 'activities' domain was
consumed only by the NrArrayTranslator Twig filter removed in #489;
every remaining trans call uses the default or security domain.
- docker/ldap/dev-users.ldif: compose mounts only users-only.ldif;
the file was referenced by three comments/docs, now repointed.
Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Audit findings, each verified against the real Makefile, composer scripts, compose services and installed packages: - Makefile: validate-stack and analyze-coverage ran in the 'app' service, whose production image ships neither composer nor dev tools — point them at app-tools/app-dev. - Commit .env.test.local.example: 'make e2e-up' tried to cp it since forever; the file never existed, so the target always fell back to a brittle echo with literal \n escapes. - copilot-instructions.md: dropped Psalm (never installed) and the security-check script; PHPUnit 12→13; test/quality commands moved to app-dev/app-tools; frontend section now bun/Vite; removed references to nonexistent PLANNING.md, docs/security-checklist.md and assets/. - tests/AGENTS.md: no ParaTest, no composer test:parallel, test db is db_unittest, PHPUnit 13. - tests/README.md: real filter target (testSaveAndDeleteWorkLog), real analyze-coverage path/service. - docs/development.md: bun frontend workflow, real db targets (reset-test-db), nvm use 26. - docs/TROUBLESHOOTING.md: asset rebuild via bun/Vite instead of the removed npm/webpack pipeline. - docs/testing.md: composer audit instead of the removed security-check script. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
- slsa-provenance.yml: the provenance job never declared job-level outputs, so needs.provenance.outputs.has_subjects was always empty and the SLSA Level 3 generator job never ran on any release. Map the step outputs. - Makefile npm-build/dev/watch invoked root 'npm run build|dev|watch' — scripts that do not exist (root npm is Playwright-only). Run the real bun/Vite commands in frontend/. - serverVersion truth: the dev DSN claimed 'mysql 8' and doctrine.yaml '10.11' while every compose database runs mariadb:12.1 — Doctrine picked the wrong DDL platform (DSN wins over yaml). Align .env, doctrine.yaml and the e2e template on mariadb-12.1.2. - e2e-up: use the now-committed .env.test.local.example instead of the echo fallback whose \n escapes were written literally. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Audit-verified (zero consumers each), removed atomically with their config/env/doc surfaces: - symfony/mailer + mailer.yaml + MAILER_DSN (.env, deployment guide): no code path sends mail. - symfony/form + csrf.yaml: no Twig forms exist (login is hand-written HTML); login/logout CSRF runs on security-csrf + the stateless framework.csrf_protection config, independent of the Form component. - dev-deps symfony/css-selector + phpdocumentor/reflection-docblock: no crawler filtering, no docblock parsing (property_info uses phpstan/phpdoc-parser). 11 lock packages drop with the transitives. - SERVICE_USERS parameter + env + the docs/features.md impersonation claim: the parameter had zero consumers while the docs advertised it as a feature; the working impersonation path is Symfony switch_user (simulateUserId), now documented instead. - cache pools (cache.auth/config/data/session/debug): defined and per-env tuned, but nothing ever injected them — only cache.app is used. Kept prefix_seed + the APCu app adapter; docs/apcu-setup.md rewritten to match. - sentry.yaml.dist: Symfony never loads .dist files; the bundle runs on its defaults. - compose db-test service + volume + app-dev depends_on: tests use db_unittest; nothing pointed at db-test. - translations: drop messages.ru.yml (one key, for a locale the UI does not offer); add validators.de.yml re-keying the team-requirement violation to the exact constraint message and domain the validator actually translates. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
- APCu was compiled from an unpinned git clone of krakjoe/apcu master — every build could ship a different arbitrary commit, contradicting the Dockerfile's own single-source-of-truth versioning. pecl apcu-5.1.28 builds and loads cleanly on php:8.5-fpm (verified); pin it in docker-bake.hcl like Xdebug and mirror the ARG. - Declare ext-apcu and ext-intl in composer.json: the app cache is bound to cache.adapter.apcu and intl is deliberately installed for native ICU behavior — the manifest now states both (the mailer/form removal also dropped symfony/polyfill-intl-icu, making native intl the only provider). - e2e stage: drop the hand-maintained 17-package chromium apt list; 'npx playwright install chromium --with-deps' already installs Playwright's canonical dependency set. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Audit-verified doc debt:
- Repair all 17 broken relative links that pointed at seven never-
tracked files (DEVELOPER_SETUP, PROJECT_INDEX, API_USAGE_GUIDE,
DEVELOPER_ONBOARDING_GUIDE, API_DOCUMENTATION,
SECURITY_IMPLEMENTATION_GUIDE, CONTROLLER_INDEX) — each repointed to
the surviving equivalent (development.md, techstack.md, api.md,
security.md, TROUBLESHOOTING.md) or dropped where none exists.
- techstack.md: rewritten — it described PHP 8.4/Symfony 7.3, the
Encore/Stimulus/Sass frontend and Psalm/PHP_CodeSniffer tooling; now
documents the actual stack (PHP 8.5, Symfony 8.1, SolidJS/Vite/bun,
PHPUnit 13, PHPStan/PHPat, Playwright/Vitest).
- api.md: /scripts/timeSummaryForJira documented a {script, version}
object; the endpoint returns the instance's summary base URL as a
JSON string — document reality. README.rst now points at the actual
userscript file (public/scripts/timeSummaryForJira.js).
- testing.md / CODE_EXAMPLES.md: examples referenced
App\Service\Integration\JiraWorklogService and Jira\JiraOAuthApi —
the real classes are Jira\JiraWorkLogService and
Jira\JiraOAuthApiService. PHPUnit 12 → 13.
Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
ee52d56 to
029f881
Compare
Drops the config shapes of the removed mailer/form/messenger surfaces. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Review feedback on #490: - export.csv.twig: the per-row externalLabels loop emitted a variable number of columns, misaligning rows against the single 'Andere Labels' header column — join the labels into that one column (gemini-code-assist). - error403.html.twig: add plain-color fallbacks before every light-dark() declaration so browsers on the documented FAQ baseline (Chrome 90 / Firefox 88 / Safari 14) keep a readable page (copilot). - theme-init.html.twig: the docblock now names the error pages among its consumers and states the button wiring no-ops without the header (copilot). Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
The gate was vacuous since its wiring switched to 'bin/phpstan analyze config/quality/phpat.php': that invocation analyzed the rule FILE as code under the main config — PHPat discovers rules exclusively through DI services tagged phpat.test (TestExtractor), and nothing ever registered the test class, so zero rules ran. - Move the rules to tests/Architecture/ArchitectureTest.php (PSR-4 autoloadable; PHPStan's DI must instantiate the service before bootstrap files load). - Add config/quality/phpat.neon: a standalone level-0 pass over src/ with the phpat.test service registration; built-in PHP classes are ignored (they are not architecture). - Calibrate the allow-lists to the codebase's actual architecture (verified empirically: the previous aspirational lists produced 1174 violations, including controllers depending on their own BaseController). The contradicted 'controllers must not access repositories' rule is dropped — repository injection into invokable actions is the codebase's established pattern (33 sites). - Rewire composer analyze:arch, the captainhook action and the CI step to '-c config/quality/phpat.neon'. Verified live by experiment: a probe controller depending on PHPUnit is reported and the pass returns to [OK] once removed. src/ is green. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Derived with a placeholder-aware literal search across every tracked file (dynamic trans($e->getMessage()) feeders included): none of these 17 strings is built anywhere anymore. 'Every user must belong to at least one team.' survives in its corrected form in validators.de.yml (the validator translates via the validators domain and the constraint message carries no trailing period). Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
SonarCloud php:S1192 on the new ArchitectureTest (App\Dto, App\Exception and App\Model each repeated across allow-lists) — extend the file's existing constants idiom. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
|
## Description
Enable CSRF protection on logout. The old `enable_csrf: false` carried
the comment "because ExtJS frontend uses simple link for logout" — the
ExtJS shell is gone, and with the stateless CSRF setup already used by
the login form, protecting the plain logout links costs nothing at the
UX level while blocking cross-site forced logout.
Mechanics (verified against the installed Symfony 8.1 vendor code): with
`stateless_token_ids: [authenticate, logout]`, `csrf_token('logout')`
renders a constant marker and validation is purely origin-based —
`Sec-Fetch-Site: same-origin` (primary), `Origin`/`Referer` fallback. A
real user clicking a logout link passes; a cross-site `<img>`/link/form
hard-fails.
## Type of Change
- [x] New feature (non-breaking change that adds functionality)
## Related Issue
Follow-up to #490 (which removed every other ExtJS reference; this PR
retires the last one).
## Changes Made
- `security.yaml`: `enable_csrf: true` on the logout listener; comment
states the actual mechanism instead of blaming the removed ExtJS
frontend.
- All logout triggers use Symfony's `logout_path()`/`logout_url()` — the
`LogoutUrlGenerator` appends `_csrf_token` automatically and stays
correct if the flag is ever toggled: header badge + mobile drawer, 403
page, and the SPA's `logoutUrl` (command palette).
- `AccessDeniedSubscriber`: the remember-me/not-fully-authenticated case
now logs out programmatically (`Security::logout(false)`) instead of
redirecting through `/logout` — a browser following that redirect from
an address-bar navigation carries no same-origin fetch metadata and
would hit the CSRF wall (the empirical weak spot identified during
design).
- e2e logout flows click the link instead of `page.goto()` (CDP
navigations send `Sec-Fetch-Site: none` and would fail even though real
users pass); the tests also assert the link carries the token.
- Functional tests send `HTTP_SEC_FETCH_SITE: same-origin` (BrowserKit
emits no fetch metadata); a new test pins the 403 for tokenless logout
requests; the remember-me tests assert the new direct-to-login flow.
## Testing
- [x] Unit tests green locally (1557, incl. two new subscriber tests:
logout response used as-is + null fallback)
- [x] phpstan level 10, cs-fixer, phpat, twig lint, `lint:container`
(dev/prod/test) — all green locally
- [ ] Functional + e2e — CI (the test env inherits `enable_csrf: true`
via Symfony's config merge; the click-based e2e logout genuinely
exercises CSRF-on logout)
## Code Quality
- [x] Code follows project coding standards
- [x] Self-review completed
- [x] Documentation updated (config comment)
- [x] No breaking changes for real users (bookmarked bare `/logout` URLs
now 403 by design — standard Symfony logout-CSRF behavior)
## Migration Notes
None for deployments. Users who bookmarked the bare `/logout` URL get a
403; logging out via the UI works unchanged.
## Checklist
- [x] I have read the
[CONTRIBUTING](https://github.com/netresearch/timetracker/blob/main/CONTRIBUTING.md)
guidelines
- [x] I agree to follow the [Code of
Conduct](https://github.com/netresearch/timetracker/blob/main/CODE_OF_CONDUCT.md)
…ide with screenshots, ADR record, agent rules (#494) ## Summary Full documentation overhaul: a verified-facts rewrite of the guides, a new illustrated user guide, a corrected ADR record, refreshed agent rules, an extended in-app Help page, and a full-structure README. A 5-domain audit against the actual code found that, beyond routine drift, several large docs (DEPLOYMENT_GUIDE, CODE_EXAMPLES, TROUBLESHOOTING, configuration, development, testing, and ADRs 003–013) described **infrastructure this application never had** — Redis layers, JWT auth, `/api/v1`, ParaTest/Panther suites, ~50 invented env vars and `app:*` console commands. Everything replaced here was re-derived from `Makefile`, `composer.json`, `compose.yml`, `.env*`, `config/`, `src/` and the real CI workflows; every command, route, env var and version in the new docs was verified to exist. ## What's in here - **New [user guide](docs/user-guide.md)** covering every feature, with 20 English 1440px screenshots — including the QoL features (dark mode, compact density, left/right sidebar navigation, Alt shortcut badges); [features.md](docs/features.md) and [FAQ.md](docs/FAQ.md) rewritten for the current SolidJS UI - **README expanded to a full project page**: TOC, About, grouped features, screenshot gallery, first-login credentials for the dev stack, key-config table, mermaid architecture diagram, Usage/Testing/Deployment/Contributing/Security sections - **Developer guides rewritten** ([development](docs/development.md), [configuration](docs/configuration.md), [testing](docs/testing.md)) — ~5,300 lines of fiction replaced by ~1,300 verified lines; configuration now documents the real ticket-system admin fields (SERVER OAuth 1.0a vs CLOUD OAuth 2.0) and internal-Jira ticket mirroring - **Ops docs rewritten** ([deployment](docs/DEPLOYMENT_GUIDE.md), [troubleshooting](docs/TROUBLESHOOTING.md)) from `compose.yml` / `docker-bake.hcl` / the publish workflow - **ADR record corrected**: index now lists all 17 ADRs; dated *reality notes* on ADRs whose bodies describe never-built infrastructure (bodies kept as history); new [ADR-015](docs/adr/ADR-015-php-8-5-symfony-8-upgrade.md) (PHP 8.5/Symfony 8), [ADR-016](docs/adr/ADR-016-solidjs-frontend-rewrite.md) (ExtJS→SolidJS, #470/#490), [ADR-017](docs/adr/ADR-017-jira-cloud-oauth2.md) (dual-mode Jira auth, #416) - **API/internals references** (api.md, DTO/EVENT/REPOSITORY docs) aligned with the code — all 65 endpoint headings now map to real routes - **AGENTS.md**: drift fixed (PHPStan 10, PER-CS), new scoped files for `frontend/` and `e2e/`, `CLAUDE.md` symlinks restored at all five levels - **In-app Help** (`/ui/help`): new "The pages" section (EN+DE) and a link to the user guide — lint/typecheck/346 Vitest tests green - **CONTRIBUTING**: the enforced-but-undocumented DCO sign-off requirement is now documented - **Removed**: `README.rst` (stale duplicate), `TASKS.md` (abandoned 2025 notes), `docs/CODE_EXAMPLES.md` (68 KB of examples for services that never existed); all references updated ## Review Copilot raised 2 inline comments (PER-CS leftover in src/AGENTS.md, 404ing v4_EOL release link) — both fixed in 41fee70, threads replied to and resolved. Gemini reviewed with no findings. ## Verification - Every documented `make`/`composer`/`bin/console` command checked against `Makefile`, `composer.json` scripts and `src/Command/` - All relative links and image references across 58 markdown files resolve - ADR PR/commit references verified via GitHub (#416, #470, #490) - Frontend change: `bun run lint`, `bun run typecheck`, `bun run test` (346 passing), page visually verified in the running e2e stack - Host unit suite green (1557 tests) via the CaptainHook pre-commit gate on every commit ## Follow-ups (out of scope, found during verification) - `docker/nginx/default.conf` forwards to `phpfpm:9000` but the prod compose service is named `app` — the deployment guide documents the alias workaround; compose.yml should probably gain a `phpfpm` network alias - The admin Users form still offers a `CTL` user type (`frontend/src/admin/entities.ts`) that `UserType::from()` rejects - Jira Cloud OAuth 2.0: data model + admin form exist (#416), but the runtime 3LO flow is not implemented yet (`JiraAuthenticationService` is OAuth1-only) — ADR-017 records this honestly



Description
Post-ExtJS consistency pass: after the SolidJS/Vite migration, docs, tool config, templates and dependency wiring still described or served the removed stack. Every change either removes something verified unreferenced, migrates something to its proper home, or rewrites a description to state the current contract. A five-scanner dependency/orphan audit (adversarially verified) contributed the second half of the commits.
Type of Change
Related Issue
N/A — follow-up to #489. Logout CSRF lands separately on top of this branch.
Changes Made
Consistency pass
header.cssfolded into the Vite build (un-minified 1:1, cascade verified in the emitted bundle); logo migrated topublic/images/;public/build/no longer exists.nav.test.ts).E2E_TEST_PLAN.mdrewritten.Audit fixes (each independently re-verified)
default_table_options.collateignored by DBAL 4 (→collation); dev DSN claimed MySQL 8 against MariaDB 12.1 (wrong DDL platform) —serverVersionunified onmariadb-12.1.2;make e2e-up/validate-stack/analyze-coverage/npm targets repaired.ext-pdo_mysql/ext-apcu/ext-intldeclared;symfony/expression-language,dg/bypass-finals,symfony/mailer,symfony/form,symfony/css-selector,phpdocumentor/reflection-docblockremoved (zero usage each, 11 further lock transitives dropped);symfony/stopwatch→ require-dev; dead npmoverridesremoved.InvalidDefaultArgInFromlint declared intentional (bake is the version source of truth).http_discovery.yaml(uninstalled package),twig_extensions.yaml(no-op),routes/dev/framework.yaml(double-loaded routes),sentry.yaml.dist(never loaded), unused cache pools (docs rewritten),SERVICE_USERSwiring + false docs claim (switch_user documented instead),db-testcompose service, orphanedControllingController,dev-users.ldif,activitiestranslation catalogs;validators.de.ymladded so the team-requirement violation actually translates.techstack.mdrewritten to the real stack;api.mddocuments the actual/scripts/timeSummaryForJiraresponse; example code references real class names; commands run in images that contain the tools (app-dev/app-tools).Testing
nav.test.ts); full suite in CI[OK], cs-fixer 0 findings, phpat via hookslint:containergreen in dev/prod/test after every config change;compose configvalid;composer validatecleanCode Quality
Migration Notes
APP_LOGO_URLoverrides keep working; default logo now at/images/logo-netresearch.svg. Node tooling expects 26. Local.envgains anAPP_ENCRYPTION_KEYdoc block;MAILER_DSN/SERVICE_USERS/messenger blocks are gone (nothing read them).Checklist