Skip to content

feat(router): move zaakafhandelapp off hash routing to clean path URLs - #609

Merged
rubenvdlinde merged 1 commit into
developmentfrom
feat/zaakafhandelapp-history-routing
Sep 1, 2026
Merged

feat(router): move zaakafhandelapp off hash routing to clean path URLs#609
rubenvdlinde merged 1 commit into
developmentfrom
feat/zaakafhandelapp-history-routing

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Second app in the move off # routing, after stackiq (softwarecatalog#899) proved the pattern.

Verified before switching

History mode fails at the server when the AppHost SPA catch-all is missing. Probed first: /apps/zaakafhandelapp/zaken and /taken already returned 200 with the app shell.

Two parts, and the second is the one that matters

  1. createWebHashHistorycreateWebHistory.

  2. routerBase(), derived from the URL actually being served. Nextcloud serves this app under both /apps/zaakafhandelapp/... and /index.php/apps/zaakafhandelapp/..., but generateUrl() returns only the form the instance is configured for. Arriving on the other leaves the path outside the router base, vue-router cannot resolve it, and the catch-all redirects to / — the visitor lands on the dashboard with no error, deep link silently swallowed.

    This app's own e2e suite uses the /index.php form (tests/e2e/app-path.ts: APP = '/index.php/apps/zaakafhandelapp'), so without routerBase() every deep link the suite makes would break. That is exactly how it surfaced on stackiq.

The 11 spec files built URLs as `${APP}/#/<route>`; all now use real paths.

Verification

URL result
/apps/zaakafhandelapp/ Dashboard
/apps/zaakafhandelapp/zaken Zaken
/index.php/apps/zaakafhandelapp/zaken Zaken
/index.php/apps/zaakafhandelapp/klanten Klanten
reload on /index.php/.../zaken 200, still Zaken

That reload is the point — the case hash mode existed to avoid, now served by the catch-all instead of 404ing. No hash anywhere.

e2e: ui-nav-navigation + ui-case-views → 21 passed, 3 failed; the three re-ran green in isolation. They failed on cn-app-root never mounting — the shell did not boot at all — which is the shared dev container dropping into maintenance mid-run, not a routing regression.

eslint exits 0 and prettier --check "**/*.{js,ts,vue,css,scss}" is clean — the full glob, tests included, having twice landed format failures by checking only src/.

Second app in the fleet-wide move off `#` routing, after stackiq
(softwarecatalog#899) proved the pattern.

Verified BEFORE switching, because history mode fails at the SERVER when
the AppHost SPA catch-all is missing: /apps/zaakafhandelapp/zaken and
/taken already returned 200 with the app shell.

Two parts, and the second is the one that matters:

1. createWebHashHistory -> createWebHistory.

2. routerBase(), derived from the URL actually being served. Nextcloud
   serves this app under BOTH /apps/zaakafhandelapp/... and
   /index.php/apps/zaakafhandelapp/..., but generateUrl() returns only
   the form the instance is configured for. Arriving on the other form
   leaves the path outside the router base, vue-router cannot resolve it,
   and the catch-all redirects to '/' -- the visitor lands on the
   dashboard with no error and the deep link is silently swallowed.

   This app's own e2e suite uses the /index.php form
   (tests/e2e/app-path.ts: APP = '/index.php/apps/zaakafhandelapp'), so
   without routerBase() every deep link the suite makes would break. That
   is exactly how it was caught on stackiq.

The 11 spec files built URLs as `${APP}/#/<route>`; all now use real
paths.

Verified against the published @conduction/nextcloud-vue
(USE_LOCAL_LIB=false):

  /apps/zaakafhandelapp/                    -> Dashboard
  /apps/zaakafhandelapp/zaken               -> Zaken
  /index.php/apps/zaakafhandelapp/zaken     -> Zaken
  /index.php/apps/zaakafhandelapp/klanten   -> Klanten
  RELOAD on /index.php/.../zaken            -> 200, still Zaken

That reload is the point: it is the case hash mode existed to avoid, and
the catch-all serves it rather than 404ing. No hash anywhere.

e2e: ui-nav-navigation + ui-case-views, 21 passed / 3 failed, and the
three re-ran green in isolation -- they failed on `cn-app-root` never
mounting, i.e. the shell did not boot, which is the shared dev container
dropping into maintenance mid-run rather than a routing regression.

eslint exits 0 and `prettier --check "**/*.{js,ts,vue,css,scss}"` is
clean -- the FULL glob, tests included, not just src/.
@rubenvdlinde
rubenvdlinde merged commit 78c8d1b into development Sep 1, 2026
1 check passed
@rubenvdlinde
rubenvdlinde deleted the feat/zaakafhandelapp-history-routing branch September 1, 2026 07:06
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/zaakafhandelapp @ 19b7d25

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
test-l10n
format
composer ✅ 100/100
npm ✅ 537/537
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development
Hydra gates

Quality workflow — 2026-09-01 07:16 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde added a commit that referenced this pull request Sep 1, 2026
…e de-hashing (#615)

Follow-up to #609, which turned E2E red on development: 12 failed / 81
passed where the previous commit was green. Both causes were mine.

1. THE DE-HASH SWEEP WAS TOO NARROW. It replaced `${APP}/#/x` but not
   `${APP}/#${route}`, where the route variable already carries its own
   leading slash. Three call sites kept the `#`, so under history routing
   they resolved to the app root and every assertion about the target
   page failed. spaNavigate() and gotoIndex() are the two helpers, which
   is why nine record-index tests went down together.

2. THE APP HAD NO CATCH-ALL. appinfo/routes.php enumerates a page route
   per index (/zaken, /klanten, …), so those deep links worked while
   anything NOT in that list -- /features-roadmap, /auditTrail, any
   detail route -- 404'd at the server. Under hash routing this never
   showed, because the route travelled in the fragment and the server
   only ever saw the app root.

⚠️ MY PRE-CHECK FOR #609 WAS WRONG, and this is the lesson: I probed
/zaken and /taken, which are both ENUMERATED routes, and concluded a
catch-all existed. Probing an enumerated path proves nothing. Probe a
NONSENSE path:

  /apps/zaakafhandelapp/zzz-nonsense -> 404   (no catch-all)
  /apps/stackiq/zzz-nonsense         -> 401   (catch-all present)

Re-probed every converted app that way afterwards; only this one and
openregister (still on hash routing, so unaffected) were missing it.

The catch-all is spelled inline rather than via Routes::standard(),
because this file also declares a `resources` block the builder does not
carry. It is LAST so every explicit route above keeps priority.

Also raised one test's budget from 90s to 240s, with the reason in the
file: it walks 8 index pages by hard goto. Under hash routing those were
SAME-DOCUMENT navigations; under history routing each is a full page
load, so the walk costs roughly an order of magnitude more wall-clock.
The assertion is unchanged.

⚠️ The catch-all does not take effect until Nextcloud's route cache is
dropped. With memcache.local = APCu, `occ app:disable/enable` is not
enough -- a container restart is.

Verified: ui-record-views 10/11 and ui-utility-pages 8/9, i.e. 11 of the
12 CI failures recovered. The one remaining is NOT routing: the audit
page reports "Could not load log entries" because OpenRegister answers
`Register not found: 'zaakafhandelapp'` on this workstation -- the
register is not provisioned locally, and CI seeds it.

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant