30 KiB
Below is a migration map from your current route surface (~120+) to a canonical release-control-plane IA, plus a redirect/alias strategy designed to preserve existing deep links, keep bookmarks working, and avoid breaking external references (docs, emails, Slack links, ticket comments, etc.).
I’m assuming the new canonical IA is:
- Product flows (what customers do):
/(Control Plane),/releases,/approvals,/environments,/deployments,/security/*,/evidence/*,/witness/* - Operations (running the platform):
/operations/* - Settings (configuration + access control):
/settings/* - Policy authoring (still first-class):
/policy/*(instead of/policy-studio/*)
If you want to keep /ops/* and /console/* as canonical, you can—but then your route taxonomy stays inconsistent. The plan below keeps canonical clean without breaking anything, by keeping /ops/* and /console/* as legacy aliases indefinitely.
0) Canonical new route taxonomy (what we’re migrating to)
0.1 Control plane and release lifecycle
/→ Control Plane (pipeline, pending approvals, drift/risk deltas)/releases→ Releases list/releases/:releaseId→ Release detail (gates, diff, evidence, proof chain)/approvals→ Approvals inbox/approvals/:approvalId→ Approval detail (diff-first + decision + evidence)/environments→ Environments/environments/:envId→ Environment detail/deployments→ Deployments list/deployments/:deployId→ Deployment detail (workflow DAG + artifacts + evidence)
0.2 Security (scanner heritage becomes “gate inputs”)
/security/overview→ Security overview dashboard (old Home dashboard preserved here)/security/findings→ Findings (impact-to-release, reachability chips)/security/scans/:scanId→ Scan run detail/security/vulnerabilities→ CVE explorer/security/vulnerabilities/:cveId→ CVE detail/security/sbom/graph→ SBOM graph explorer/security/lineage→ Lineage/compare (global)/security/reachability→ Reachability center/security/vex→ VEX hub (no longer under/admin)/security/unknowns→ Unknowns tracking/security/patch-map→ Patch map
0.3 Evidence and verification
/evidence→ Evidence center (packets, bundles, export, replay, provenance)/evidence/:evidenceId→ Evidence packet viewer/evidence/packsand/evidence/packs/:packId→ Evidence packs/evidence/proofs/:subjectDigest→ Proof chain viewer/witness/:witnessId→ Witness viewer (reachability slice + replay/verify)
0.4 Policy (rename, but keep semantics)
/policy/packs(list)/policy/packs/:packId/editor/policy/packs/:packId/yaml/policy/packs/:packId/simulate/policy/packs/:packId/approvals/policy/packs/:packId/rules/policy/packs/:packId/explain/:runId/policy/packs/:packId/dashboard/policy/exceptions(exception queue + approvals)
0.5 Operations
/operations/orchestrator(+ jobs, quotas)/operations/quotas/*/operations/dead-letter/*/operations/slo/*/operations/health/*/operations/feeds/*/operations/offline-kit/*/operations/aoc/*/operations/scheduler/*/operations/doctor
0.6 Settings
/settings/profile/settings/integrations/*(hub + detail + activity)/settings/admin/*(tenants/users/roles/clients/tokens/branding)/settings/trust/*(keys/issuers/certs/score-config/audit)/settings/registries(registry token service)/settings/notifications/*/settings/policy/governance/settings/sbom-sources/settings/trivy-db(or fold into feeds)
1) Migration principles (minimize breaking links)
Principle A — Keep old links working forever: Every old route either:
- Redirects to the new canonical route, or
- Remains as an alias that renders the same page/module.
Principle B — Preserve identifiers and semantics:
If :scanId, :packId, :subjectDigest exist today, do not change their format. New routes simply “re-home” them.
Principle C — Use redirects only when mapping is 1:1:
If old route needs query params (e.g., “filter type=audit”), use a guard-based redirect returning a UrlTree (so you can append query parameters safely).
Principle D — Track legacy usage:
Add telemetry: whenever a legacy route is hit, record { oldPath, newPath }. This lets you quantify remaining legacy usage.
2) Old → new route migration map
Each entry includes: Old route → New canonical route + strategy.
Legend:
- KEEP = route stays as-is (canonical already good)
- REDIRECT = Angular router redirect (1:1 mapping)
- SMART REDIRECT = redirect via guard/matcher to add query params/open specific view
- ALIAS = old route still loads same module/component as new (no visible URL change)
2.1 Home & dashboard routes
| Old Route | New Route | Strategy | Notes |
|---|---|---|---|
/ |
/ |
KEEP (content changes) | Home becomes Control Plane. Preserve old “security dashboard” as /security/overview. |
/welcome |
/welcome |
KEEP | Usually public. Keep stable. |
/dashboard/sources |
/operations/feeds |
REDIRECT | Old “sources dashboard” becomes operational view of feeds/mirrors. |
Add a prominent navigation link: Security Overview → /security/overview to avoid “we removed my dashboard” backlash.
2.2 Analyze routes → Security namespace
| Old Route | New Route | Strategy | Notes |
|---|---|---|---|
/findings |
/security/findings |
REDIRECT | Findings become security impact-to-release view. |
/findings/:scanId |
/security/scans/:scanId |
REDIRECT | Preserve deep links; scan detail page remains. |
/vulnerabilities |
/security/vulnerabilities |
REDIRECT | CVE explorer moved under security. |
/vulnerabilities/:vulnId |
/security/vulnerabilities/:vulnId |
REDIRECT | 1:1 mapping. |
/graph |
/security/sbom/graph |
REDIRECT | SBOM graph belongs under Security. |
/lineage |
/security/lineage |
REDIRECT | (Or /releases/lineage, choose one canonical; I recommend Security.) |
/lineage/:artifact/compare |
/security/lineage/:artifact/compare |
ALIAS or REDIRECT | Keep params same. |
/lineage/compare |
/security/lineage/compare |
REDIRECT | Stable. |
/reachability |
/security/reachability |
REDIRECT | Reachability center is security analysis. |
/admin/vex-hub |
/security/vex |
REDIRECT | VEX is not “admin-only”; move. |
/admin/vex-hub/search |
/security/vex/search |
REDIRECT | Keep identical subroutes. |
/admin/vex-hub/search/detail/:id |
/security/vex/search/detail/:id |
REDIRECT | 1:1. |
/admin/vex-hub/stats |
/security/vex/stats |
REDIRECT | 1:1. |
/admin/vex-hub/consensus |
/security/vex/consensus |
REDIRECT | 1:1. |
/admin/vex-hub/explorer |
/security/vex/explorer |
REDIRECT | 1:1. |
/analyze/unknowns |
/security/unknowns |
REDIRECT | 1:1. |
/analyze/patch-map |
/security/patch-map |
REDIRECT | 1:1. |
/scans/:scanId |
/security/scans/:scanId |
REDIRECT | Consolidate scan detail here. |
/compare/:currentId |
/security/lineage/compare/:currentId |
REDIRECT | Preserve compare deep links. |
/cvss/receipts/:receiptId |
/evidence/receipts/cvss/:receiptId |
REDIRECT | CVSS receipt is an evidence artifact. |
2.3 Triage routes → split between Security (artifact triage) and Policy/Evidence
| Old Route | New Route | Strategy | Notes |
|---|---|---|---|
/triage/artifacts |
/security/artifacts |
REDIRECT | “Artifact workspace” becomes security artifact index (digest-first). |
/triage/artifacts/:artifactId |
/security/artifacts/:artifactId |
REDIRECT | Preserve the triage workspace; it becomes “Artifact Detail”. |
/exceptions |
/policy/exceptions |
REDIRECT | Exceptions are governance controls for gates. |
/triage/audit-bundles |
/evidence?type=audit |
SMART REDIRECT | Needs query param. Alternatively create /evidence/bundles/audit to allow simple redirect. |
/triage/audit-bundles/new |
/evidence/bundles/new?type=audit |
SMART REDIRECT | Needs query param. |
/risk |
/security/risk |
REDIRECT | Risk dashboard becomes security analytics. |
Recommendation to reduce SMART redirects: create explicit canonical paths:
/evidence/bundles/audit/evidence/bundles/release/evidence/bundles/scanThen redirects are trivial and do not require query injection.
2.4 Policy routes (/policy-studio/* → /policy/*)
| Old Route | New Route | Strategy | Notes |
|---|---|---|---|
/policy-studio/packs |
/policy/packs |
REDIRECT | Rename for brevity. |
/policy-studio/packs/:packId/editor |
/policy/packs/:packId/editor |
REDIRECT | 1:1. |
/policy-studio/packs/:packId/yaml |
/policy/packs/:packId/yaml |
REDIRECT | 1:1. |
/policy-studio/packs/:packId/simulate |
/policy/packs/:packId/simulate |
REDIRECT | 1:1. |
/policy-studio/packs/:packId/approvals |
/policy/packs/:packId/approvals |
REDIRECT | 1:1. |
/policy-studio/packs/:packId/rules |
/policy/packs/:packId/rules |
REDIRECT | 1:1. |
/policy-studio/packs/:packId/explain/:runId |
/policy/packs/:packId/explain/:runId |
REDIRECT | 1:1. |
/policy-studio/packs/:packId/dashboard |
/policy/packs/:packId/dashboard |
REDIRECT | 1:1. |
/orchestrator |
/operations/orchestrator |
REDIRECT | Orchestrator is ops. |
/orchestrator/jobs |
/operations/orchestrator/jobs |
REDIRECT | 1:1. |
/orchestrator/jobs/:jobId |
/operations/orchestrator/jobs/:jobId |
REDIRECT | 1:1. |
/orchestrator/quotas |
/operations/orchestrator/quotas |
REDIRECT | 1:1. |
2.5 Ops routes (/ops/* + /scheduler/* → /operations/*)
| Old Route | New Route | Strategy | Notes |
|---|---|---|---|
/sbom-sources |
/settings/sbom-sources |
REDIRECT | This is configuration, not ops. |
/ops/quotas |
/operations/quotas |
REDIRECT | 1:1. |
/ops/quotas/tenants |
/operations/quotas/tenants |
REDIRECT | 1:1. |
/ops/quotas/tenants/:tenantId |
/operations/quotas/tenants/:tenantId |
REDIRECT | 1:1. |
/ops/quotas/throttle |
/operations/quotas/throttle |
REDIRECT | 1:1. |
/ops/quotas/alerts |
/operations/quotas/alerts |
REDIRECT | 1:1. |
/ops/quotas/forecast |
/operations/quotas/forecast |
REDIRECT | 1:1. |
/ops/quotas/reports |
/operations/quotas/reports |
REDIRECT | 1:1. |
/ops/orchestrator/dead-letter |
/operations/dead-letter |
REDIRECT | Flatten path; keep subroute for queue. |
/ops/orchestrator/dead-letter/queue |
/operations/dead-letter/queue |
REDIRECT | 1:1. |
/ops/orchestrator/slo |
/operations/slo |
REDIRECT | 1:1. |
/ops/orchestrator/slo/alerts |
/operations/slo/alerts |
REDIRECT | 1:1. |
/ops/orchestrator/slo/definitions |
/operations/slo/definitions |
REDIRECT | 1:1. |
/ops/health |
/operations/health |
REDIRECT | 1:1. |
/ops/feeds |
/operations/feeds |
REDIRECT | 1:1. |
/ops/feeds/mirror/:mirrorId |
/operations/feeds/mirror/:mirrorId |
REDIRECT | 1:1. |
/ops/feeds/airgap/import |
/operations/feeds/airgap/import |
REDIRECT | 1:1. |
/ops/feeds/airgap/export |
/operations/feeds/airgap/export |
REDIRECT | 1:1. |
/ops/feeds/version-locks |
/operations/feeds/version-locks |
REDIRECT | 1:1. |
/ops/offline-kit/* |
/operations/offline-kit/* |
ALIAS or REDIRECT | Either keep the segment name to avoid churn, or canonicalize to /operations/offline/*. |
/ops/aoc/* |
/operations/aoc/* |
REDIRECT | Keep short; avoid nested /compliance/ unless you really need it. |
/ops/doctor |
/operations/doctor |
REDIRECT | 1:1. |
/scheduler/* |
/operations/scheduler/* |
REDIRECT | Fix inconsistent prefix. |
/ops/scanner/* |
/operations/scanner/* |
REDIRECT | Scanner ops is now “security gate engine ops”. |
2.6 Notify
| Old Route | New Route | Strategy | Notes |
|---|---|---|---|
/notify |
/operations/notifications |
REDIRECT | If /notify is history/dispatch, it belongs to operations. If it is configuration, redirect to /settings/notifications. |
2.7 Admin + Console routes → Settings namespace
| Old Route | New Route | Strategy | Notes |
|---|---|---|---|
/console/profile |
/settings/profile |
REDIRECT | Consolidate under settings. |
/console/status |
/operations/status |
REDIRECT | Status is ops. |
/console/configuration |
/settings/integrations |
REDIRECT | Configuration pane becomes integrations hub. |
/console/admin/tenants |
/settings/admin/tenants |
REDIRECT | 1:1. |
/console/admin/users |
/settings/admin/users |
REDIRECT | 1:1. |
/console/admin/roles |
/settings/admin/roles |
REDIRECT | 1:1. |
/console/admin/clients |
/settings/admin/clients |
REDIRECT | 1:1. |
/console/admin/tokens |
/settings/admin/tokens |
REDIRECT | 1:1. |
/console/admin/audit |
/evidence/audit |
REDIRECT | Audit is evidence. |
/console/admin/branding |
/settings/admin/branding |
REDIRECT | 1:1. |
/admin/audit/* |
/evidence/audit/* |
REDIRECT | Unified audit log belongs under evidence. |
/admin/trust/* |
/settings/trust/* |
REDIRECT | Keys/issuers/certs/score config consolidated. |
/admin/registries |
/settings/registries |
REDIRECT | Registry token service is configuration. |
/admin/issuers |
/settings/trust/issuers |
REDIRECT | Fold into trust. |
/admin/notifications |
/settings/notifications/admin |
REDIRECT | Admin notifications config. |
/admin/policy/governance |
/settings/policy/governance |
REDIRECT | Governance is configuration. |
/admin/policy/simulation |
/policy/simulation |
REDIRECT | Or keep /settings/policy/simulation if truly admin-only. |
/concelier/trivy-db-settings |
/settings/trivy-db |
REDIRECT | Or fold into /operations/feeds/trivy. |
2.8 Release Orchestrator routes (/release-orchestrator/* → lifecycle roots)
| Old Route | New Route | Strategy | Notes |
|---|---|---|---|
/release-orchestrator |
/ |
REDIRECT | Control plane becomes the orchestrator home. |
/release-orchestrator/environments |
/environments |
REDIRECT | 1:1. |
/release-orchestrator/releases |
/releases |
REDIRECT | 1:1. |
/release-orchestrator/workflows |
/workflows (or /settings/workflows) |
REDIRECT | Decide: if workflows are editable config → settings; if used daily → top-level. |
/release-orchestrator/approvals |
/approvals |
REDIRECT | 1:1. |
/release-orchestrator/deployments |
/deployments |
REDIRECT | 1:1. |
/release-orchestrator/evidence |
/evidence?type=release |
SMART REDIRECT | Better to create /evidence/bundles/release for simple redirect. |
2.9 Evidence routes (mostly keep)
| Old Route | New Route | Strategy | Notes |
|---|---|---|---|
/evidence |
/evidence |
KEEP | Already good. |
/evidence/bundles |
/evidence |
ALIAS or REDIRECT | If you keep tabbed routes, you can keep it as alias. |
/evidence/export |
/evidence/export |
KEEP | Stable. |
/evidence/replay |
/evidence/replay |
KEEP | Stable. |
/evidence/provenance |
/evidence/provenance |
KEEP | Stable. |
/evidence-packs |
/evidence/packs |
REDIRECT | Normalize under evidence namespace. |
/evidence-packs/:packId |
/evidence/packs/:packId |
REDIRECT | 1:1. |
/proofs/:subjectDigest |
/evidence/proofs/:subjectDigest |
ALIAS (recommended) | Keep /proofs/* forever as a public-friendly shortlink. |
2.10 Integrations routes → Settings
| Old Route | New Route | Strategy | Notes |
|---|---|---|---|
/integrations |
/settings/integrations |
REDIRECT | Canonicalize. |
/integrations/registries |
/settings/integrations/registries |
REDIRECT | 1:1. |
/integrations/scm |
/settings/integrations/scm |
REDIRECT | 1:1. |
/integrations/ci |
/settings/integrations/ci |
REDIRECT | 1:1. |
/integrations/hosts |
/settings/integrations/hosts |
REDIRECT | 1:1. |
/integrations/feeds |
/settings/integrations/feeds |
REDIRECT | 1:1. |
/integrations/activity |
/settings/integrations/activity |
REDIRECT | Or move to /operations/integrations/activity if you want. |
/integrations/:integrationId |
/settings/integrations/:integrationId |
REDIRECT | 1:1. |
2.11 Other routes
| Old Route | New Route | Strategy | Notes |
|---|---|---|---|
/ai-runs |
/operations/ai-runs |
REDIRECT | AI runs are operational telemetry. |
/ai-runs/:runId |
/operations/ai-runs/:runId |
REDIRECT | 1:1. |
/change-trace |
/evidence/change-trace |
REDIRECT | Change trace is evidence lineage. |
/setup |
/setup |
KEEP | Installation wizard should remain stable. |
/auth/callback |
/auth/callback |
KEEP | Must remain stable for OIDC. |
3) Redirect strategy (implementation plan that won’t bite you)
3.1 Use a dedicated “Legacy Routes” layer (lowest priority in router)
Order matters. Put all legacy redirects after the new canonical route tree so you don’t accidentally intercept new paths.
-
app.routes.ts- New canonical routes
- Legacy redirect/alias routes
**fallback
3.2 Three redirect mechanisms (use the right one)
Mechanism 1 — Simple static redirect (redirectTo)
Use when mapping is clean and 1:1:
/findings→/security/findings/release-orchestrator/releases→/releases
Mechanism 2 — Param redirect (redirectTo with :param)
Use when it’s still 1:1 but has params:
/vulnerabilities/:vulnId→/security/vulnerabilities/:vulnId/findings/:scanId→/security/scans/:scanId
Mechanism 3 — SMART redirect (guard/matcher returning a UrlTree)
Use when you must:
- Add query params (e.g.,
type=audit) - Switch tabs
- Open a drawer based on route
Examples:
/triage/audit-bundles→/evidence?type=audit/release-orchestrator/evidence→/evidence?type=release
Strong recommendation: Avoid SMART redirects by giving evidence bundle types real paths:
/evidence/bundles/audit/evidence/bundles/releaseThen you can use simple redirects and remove complexity.
3.3 Preserve query params and fragments always
Legacy URLs in tickets often include query params. Your redirect logic must preserve:
?tab=...?filters=...#anchor
In Angular, guard-based UrlTree redirects are the most reliable way to preserve and augment query params intentionally.
3.4 Keep “short links” as permanent aliases
Some paths are extremely convenient and should remain:
/proofs/:subjectDigest(keep forever, even if canonical is under/evidence/proofs/...)- Potentially
/deploy/:idif you ever add it
This reduces friction when humans share links.
3.5 Add a “Legacy URL” banner (optional but useful)
On legacy-rendered aliases (not redirects), show a slim banner:
- “This URL has moved. Update bookmarks.”
- Button: “Go to new location”
- Include one-click copy of canonical URL
This is very effective during the transition without forcing redirects.
3.6 Instrument legacy hits
Emit a telemetry event:
-
legacy_route_hitoldPathnewPathtenantIduserId(if available)timestamp
This tells you when it’s safe to remove legacy routes (if you ever choose to).
4) Practical redirect coverage checklist (to prevent surprises)
Before shipping, test these as direct loads (not SPA navigation):
/admin/vex-hub/search/detail/123loads and lands on/security/vex/search/detail/123/findings/SCAN-123lands on scan detail/proofs/sha256:...still works and lands on proof viewer/release-orchestrator/environmentslands on/environments/triage/audit-bundleslands on the correct evidence bundle view (no empty state)