openova/products/catalyst/bootstrap/ui
e3mrah ce4e93f31f
fix(auth): rootRoute auth gate closes route-bypass on /app/$id /users/$userId /apps + path-normalization edges (#1090 cluster A2) (#1109)
PR #1093 fixed the chroot anon→Keycloak bug for routes that mounted
under SovereignConsoleLayout. Iter-2 of the routing matrix surfaced
7 routes that BYPASS the layout, still hitting Keycloak's hosted
login on anon visit:

  /app/$componentId       (TC-R-058)
  /users/$userId          (TC-R-059)
  /dashboard/  trailing slash (TC-R-069)
  /Dashboard   capital case   (TC-R-070)
  //dashboard  double slash   (TC-R-093)
  /apps        + network filter (TC-R-075, TC-R-076)

Fix: lift the auth gate from SovereignConsoleLayout (per-route layer)
to rootRoute.beforeLoad (universal). The new gate runs BEFORE every
route's own beforeLoad, so no route can bypass it.

Two responsibilities of rootBeforeLoad:

  1. Path canonicalisation — collapse //+ → /, strip trailing /,
     lowercase. Malformed variants redirect to canonical via hard
     navigation (preserves search + hash byte-for-byte). This catches
     the trailing-slash / capital / double-slash edges in one rule.

  2. Sovereign-mode auth gate — when no session is detected and the
     canonical path is NOT in PUBLIC_PATH_PREFIXES, redirect to
     /login?next=<canonical>. Public allow-list is path-prefix matched:
     /login, /signup, /forgot, /auth/{handover,handover-error,callback},
     /readyz, /healthz, /sovereignty/preview, /designs, /api/

Helpers (canonicalisePath, isPublicPath, hasCatalystSession) extracted
to src/app/auth-gate.ts so they can be unit-tested without booting
the router. 24 unit tests cover canonicalisation rules, public-path
matching (including prefix-collision rejection like /loginz), session
detection, and an .each() integration block over all 7 bypass routes.

SovereignConsoleLayout sets sessionStorage['catalyst:authed']='1'
after a successful /whoami probe so the rootRoute gate is permissive
for already-authed users (the HttpOnly catalyst_session cookie is
invisible to JS).

Anti-regression: TC-R-002 (/dashboard) and TC-R-049 (network filter
on /dashboard) — already PASSING in iter-2, must continue to PASS.

Mothership routing (catalyst-zero mode) is a no-op in the new gate;
provisionAuthGuard / wizardAuthGuard continue to handle their own
routes via Fix #B (PR #1091).

Co-authored-by: Hati Yildiz <hati.yildiz@openova.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 22:05:46 +04:00
..
.pr-evidence fix(catalyst-ui): rebuild Flow canvas to match provision-mockup-v4.png (#282) 2026-04-30 18:32:02 +04:00
e2e feat(sme-tenant): multi-domain Sovereign support — parent-domain dropdown + free-subdomain-under-any-pool-domain (#828) (#836) 2026-05-04 23:48:10 +04:00
public fix(wizard): correct logo backplate colors for 7 components (refs #179) (#202) 2026-04-29 20:21:42 +02:00
scripts feat(sovereign-console): populate Jobs/Apps/Cloud views from local cluster (#933) (#937) 2026-05-05 14:43:01 +04:00
src fix(auth): rootRoute auth gate closes route-bypass on /app/$id /users/$userId /apps + path-normalization edges (#1090 cluster A2) (#1109) 2026-05-08 22:05:46 +04:00
.gitignore test(catalyst-ui): Playwright E2E for Cloud accordion + redirects 2026-05-01 08:08:45 +04:00
Containerfile fix(ui): bundle bootstrap-kit + platform + products into catalyst-ui build 2026-04-29 15:09:58 +02:00
eslint.config.js feat(catalyst): Bootstrap UI — full wizard, auth, dashboard, provision, success 2026-03-19 12:34:03 +01:00
index.html feat(catalyst): wizard sidebar redesign + rename UI to "Corporate" 2026-04-15 22:38:54 +02:00
nginx.conf fix(catalyst-ui): set Vite base to / — fixes blank page on all Sovereign clusters (#599) 2026-05-02 15:41:13 +04:00
package-lock.json feat: Architecture graph polish (P1 of #348) (#360) 2026-05-01 11:57:37 +04:00
package.json feat: Architecture graph polish (P1 of #348) (#360) 2026-05-01 11:57:37 +04:00
playwright.config.ts feat(phase-8b): sovereign wizard auth-gate + handover JWT minting + Playwright CI fixes (#611) 2026-05-02 19:17:56 +04:00
README.md feat(catalyst): Bootstrap UI — full wizard, auth, dashboard, provision, success 2026-03-19 12:34:03 +01:00
tsconfig.app.json feat(catalyst): Bootstrap UI — full wizard, auth, dashboard, provision, success 2026-03-19 12:34:03 +01:00
tsconfig.json feat(catalyst): Bootstrap UI — full wizard, auth, dashboard, provision, success 2026-03-19 12:34:03 +01:00
tsconfig.node.json feat(catalyst): Bootstrap UI — full wizard, auth, dashboard, provision, success 2026-03-19 12:34:03 +01:00
vite.config.ts fix(sovereign-console): flow physics, log tail, global log, header, theme (#669) (#671) 2026-05-03 14:58:34 +04:00

React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

React Compiler

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see this documentation.

Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      // Other configs...

      // Remove tseslint.configs.recommended and replace with this
      tseslint.configs.recommendedTypeChecked,
      // Alternatively, use this for stricter rules
      tseslint.configs.strictTypeChecked,
      // Optionally, add this for stylistic rules
      tseslint.configs.stylisticTypeChecked,

      // Other configs...
    ],
    languageOptions: {
      parserOptions: {
        project: ['./tsconfig.node.json', './tsconfig.app.json'],
        tsconfigRootDir: import.meta.dirname,
      },
      // other options...
    },
  },
])

You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific lint rules:

// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      // Other configs...
      // Enable lint rules for React
      reactX.configs['recommended-typescript'],
      // Enable lint rules for React DOM
      reactDom.configs.recommended,
    ],
    languageOptions: {
      parserOptions: {
        project: ['./tsconfig.node.json', './tsconfig.app.json'],
        tsconfigRootDir: import.meta.dirname,
      },
      // other options...
    },
  },
])