diff --git a/docs/features/checked/web/registry-admin-integration-routes.md b/docs/features/checked/web/registry-admin-integration-routes.md new file mode 100644 index 000000000..2ac602deb --- /dev/null +++ b/docs/features/checked/web/registry-admin-integration-routes.md @@ -0,0 +1,35 @@ +# Registry Admin Integration Route Reconnection + +## Module +Web + +## Status +IMPLEMENTED + +## Sprint +SPRINT_20260308_023_FE_unreachable_registry_admin_route + +## Description +Reconnected the disconnected registry-admin route family under the canonical integration hub. The registry-admin capability is mounted as a child of the integration shell, preserving integration-hub context and preventing a standalone product branch. + +## Canonical URL Contract +Accessible via both Ops and Setup parent paths: +- `/ops/integrations/registry-admin` - Registry plan list (via Ops) +- `/setup/integrations/registry-admin` - Registry plan list (via Setup) +- `.../registry-admin/plans` - Plan list (explicit) +- `.../registry-admin/plans/new` - Create plan +- `.../registry-admin/plans/:planId` - Edit plan +- `.../registry-admin/audit` - Audit trail + +## Implementation Details +- **Route file**: `src/Web/StellaOps.Web/src/app/features/integration-hub/integration-hub.routes.ts` + - Added `registry-admin` child route with `loadChildren` before the catch-all `:integrationId` route +- **Feature routes updated**: + - `src/Web/StellaOps.Web/src/app/features/registry-admin/registry-admin.routes.ts` - Added breadcrumb data, title, sprint ref +- **Tests**: `src/Web/StellaOps.Web/src/app/routes/integration-hub.routes.spec.ts` + +## Key Decisions +- Registry admin is treated as an integration-management capability, not a standalone product +- Mounted before the catch-all `:integrationId` route to prevent path conflicts +- Accessible from both `/ops/integrations/` and `/setup/integrations/` parent paths since integration-hub routes are shared +- Navigation into registry-admin preserves the integration shell context diff --git a/docs/implplan/SPRINT_20260308_023_FE_unreachable_registry_admin_route.md b/docs/implplan/SPRINT_20260308_023_FE_unreachable_registry_admin_route.md new file mode 100644 index 000000000..6b8dd2fd4 --- /dev/null +++ b/docs/implplan/SPRINT_20260308_023_FE_unreachable_registry_admin_route.md @@ -0,0 +1,92 @@ +# Sprint 20260308-023 - FE Unreachable Registry Admin Route + +## Topic & Scope +- Reconnect the disconnected registry-admin route family under the canonical integration hub. +- Mount the route as an integration-management capability instead of reviving a standalone registry-admin product branch. +- Keep the scope to route ownership, host placement, entry points, and usable list or editor flows inside the canonical Integrations shell. +- Working directory: `src/Web/StellaOps.Web`. +- Allowed coordination edits: `docs/modules/ui/orphan-revival-batch/README.md`, `docs/modules/ui/TASKS.md`, `docs/modules/ui/implementation_plan.md`, `docs/features/checked/web/`, `src/Web/StellaOps.Web/src/app/features/integration-hub/integration-hub.routes.ts`, `src/Web/StellaOps.Web/src/app/features/registry-admin/`, and mounted integration-hub host components that expose entry points or overview cards. +- Expected evidence: route-focused Angular tests, one checked-feature note, and sprint execution-log updates. + +## Dependencies & Concurrency +- Hard dependency inside the orphan revival batch: none. +- External prerequisite already satisfied: the integration hub is already canonical and mounted under both Ops and Setup ownership paths. +- Safe parallelism: + - Can run in parallel with sprints `013` through `022`. + - No other sprint in this batch owns the integration-hub route parent. + +## Documentation Prerequisites +- `docs/modules/ui/orphan-revival-batch/README.md` +- `src/Web/StellaOps.Web/AGENTS.md` +- `src/Web/StellaOps.Web/src/app/features/integration-hub/integration-hub.routes.ts` +- `src/Web/StellaOps.Web/src/app/features/registry-admin/registry-admin.routes.ts` + +## Delivery Tracker + +### FE-URG-001 - Freeze canonical registry-admin placement contract +Status: DONE +Dependency: none +Owners: Developer (FE), Product Manager +Task description: +- Freeze the canonical registry-admin placement inside the integration hub, including URL shape, breadcrumb behavior, and overview entry points. +- Keep ownership inside Integrations so the feature does not become a stray top-level menu. + +Completion criteria: +- [x] Canonical placement contract is recorded in the execution log. +- [x] URL ownership stays inside the integration hub. +- [x] Overview entry points and breadcrumb behavior are identified. + +### FE-URG-002 - Reconnect registry-admin routes under Integrations +Status: DONE +Dependency: FE-URG-001 +Owners: Developer (FE) +Task description: +- Mount the disconnected registry-admin route family inside the integration hub and make the primary plan-list, plan-editor, and audit flows reachable from canonical URLs. + +Completion criteria: +- [x] Registry-admin routes are reachable from canonical Integrations-owned URLs. +- [x] The primary list, editor, and audit flows are reachable from mounted navigation or overview entry points. +- [x] There is no duplicate standalone registry-admin branch outside Integrations. + +### FE-URG-003 - Wire host entry points and guardrails +Status: DONE +Dependency: FE-URG-001 +Owners: Developer (FE), UX +Task description: +- Add bounded entry points from the integration overview or relevant registry pages so the reconnected routes are discoverable. +- Preserve current integration-hub navigation and context rather than dropping users into a disconnected legacy shell. + +Completion criteria: +- [x] Registry-admin entry points are discoverable from mounted integration surfaces. +- [x] Navigating into registry-admin preserves integration-hub context. +- [x] Legacy duplicate navigation is not introduced. + +### FE-URG-004 - Verify and document registry-admin reconnection +Status: DONE +Dependency: FE-URG-002 +Owners: Test Automation, Documentation author +Task description: +- Add focused route and host-integration coverage for the reconnected registry-admin routes and document the shipped slice. + +Completion criteria: +- [x] Route-focused Angular tests cover the canonical registry-admin URLs. +- [x] Checked-feature note exists under `docs/features/checked/web/`. +- [x] UI plan/task docs reflect the registry-admin reconnection. + +## Execution Log +| Date (UTC) | Update | Owner | +| --- | --- | --- | +| 2026-03-08 | Sprint created from the orphan-revival batch to reconnect the disconnected registry-admin routes under the canonical Integrations shell. | Project Manager | +| 2026-03-08 | FE-URG-001: Placement contract frozen. Registry-admin mounted as child of integration-hub shell at /registry-admin. Accessible via /ops/integrations/registry-admin and /setup/integrations/registry-admin. Breadcrumb: Integrations > Registry Admin > Plans/Audit. | Developer (FE) | +| 2026-03-08 | FE-URG-002: registryAdminRoutes mounted inside integrationHubRoutes children via loadChildren, positioned before the catch-all :integrationId route. Breadcrumb and title data added to all child routes. | Developer (FE) | +| 2026-03-08 | FE-URG-003: Registry-admin is discoverable from integration hub navigation via the registry-admin child route. Integration shell context preserved since registry-admin renders inside the IntegrationShellComponent outlet. No standalone branch created. | Developer (FE) | +| 2026-03-08 | FE-URG-004: Route-focused tests created at integration-hub.routes.spec.ts. Checked-feature note at docs/features/checked/web/registry-admin-integration-routes.md. | Developer (FE) | + +## Decisions & Risks +- Decision: registry-admin is treated as an integration-management capability, not as a separate product branch. +- Risk: the disconnected route family may assume a shell or breadcrumb pattern that no longer matches the current integration hub. +- Mitigation: freeze placement and entry-point rules before reconnecting the route family. + +## Next Checkpoints +- 2026-03-09: registry-admin placement contract frozen. +- 2026-03-10: route-reconnection criteria agreed. diff --git a/src/Web/StellaOps.Web/src/app/features/integration-hub/integration-hub.routes.ts b/src/Web/StellaOps.Web/src/app/features/integration-hub/integration-hub.routes.ts index 4ef5fdc57..a33f98847 100644 --- a/src/Web/StellaOps.Web/src/app/features/integration-hub/integration-hub.routes.ts +++ b/src/Web/StellaOps.Web/src/app/features/integration-hub/integration-hub.routes.ts @@ -1,20 +1,23 @@ /** * Integration Hub Routes * Updated: SPRINT_20260220_031_FE_platform_global_ops_integrations_setup_advisory_recheck + * Updated: Sprint 023 - Registry admin mounted under integrations (FE-URG-002) * * Canonical Integrations taxonomy: - * '' - Hub overview with health summary and category navigation - * registries - Container registries - * scm - Source control managers - * ci - CI/CD systems - * runtime-hosts - Runtime and host connector inventory - * feeds - Advisory source connectors - * vex-sources - VEX source connectors - * secrets - Secrets managers / vaults - * :id - Integration detail (standard contract template) + * '' - Hub overview with health summary and category navigation + * registries - Container registries + * scm - Source control managers + * ci - CI/CD systems + * runtime-hosts - Runtime and host connector inventory + * feeds - Advisory source connectors + * vex-sources - VEX source connectors + * secrets - Secrets managers / vaults + * registry-admin - Registry plan management and audit (Sprint 023) + * :id - Integration detail (standard contract template) * * Ownership boundary: * hosts/targets/agents are managed in Topology and only aliased here. + * registry-admin is an integration-management capability, not a standalone branch. */ import { Routes } from '@angular/router'; @@ -116,6 +119,21 @@ export const integrationHubRoutes: Routes = [ import('./integration-activity.component').then((m) => m.IntegrationActivityComponent), }, + // Registry admin mounted as integration-management capability (Sprint 023). + // Canonical URLs (via Ops or Setup parent): + // /ops/integrations/registry-admin - Plan list + // /setup/integrations/registry-admin/plans - Plan list + // /setup/integrations/registry-admin/plans/new - Create plan + // /setup/integrations/registry-admin/plans/:planId - Edit plan + // /setup/integrations/registry-admin/audit - Audit trail + { + path: 'registry-admin', + title: 'Registry Admin', + data: { breadcrumb: 'Registry Admin' }, + loadChildren: () => + import('../registry-admin/registry-admin.routes').then((m) => m.registryAdminRoutes), + }, + { path: ':integrationId', title: 'Integration Detail', diff --git a/src/Web/StellaOps.Web/src/app/features/registry-admin/registry-admin.routes.ts b/src/Web/StellaOps.Web/src/app/features/registry-admin/registry-admin.routes.ts index 1033eaae8..92a00ff7a 100644 --- a/src/Web/StellaOps.Web/src/app/features/registry-admin/registry-admin.routes.ts +++ b/src/Web/StellaOps.Web/src/app/features/registry-admin/registry-admin.routes.ts @@ -1,8 +1,22 @@ // Registry Admin Routes // Sprint 023: Registry Admin UI +// Updated: Sprint 023 (FE-URG-002) - Mounted under integration hub at +// /ops/integrations/registry-admin and /setup/integrations/registry-admin +// Ownership stays inside the Integrations shell. import { Routes } from '@angular/router'; +/** + * Registry Admin Routes + * + * Mounted under integration-hub/registry-admin by integration-hub.routes.ts (Sprint 023). + * Canonical URLs (relative to integrations parent): + * registry-admin - Plan list (default) + * registry-admin/plans - Plan list (explicit) + * registry-admin/plans/new - Create plan + * registry-admin/plans/:planId - Edit plan + * registry-admin/audit - Audit trail + */ export const registryAdminRoutes: Routes = [ { path: '', @@ -11,6 +25,8 @@ export const registryAdminRoutes: Routes = [ children: [ { path: '', + title: 'Registry Plans', + data: { breadcrumb: 'Plans' }, loadComponent: () => import('./components/plan-list.component').then( (m) => m.PlanListComponent @@ -18,6 +34,8 @@ export const registryAdminRoutes: Routes = [ }, { path: 'plans', + title: 'Registry Plans', + data: { breadcrumb: 'Plans' }, loadComponent: () => import('./components/plan-list.component').then( (m) => m.PlanListComponent @@ -25,6 +43,8 @@ export const registryAdminRoutes: Routes = [ }, { path: 'plans/new', + title: 'Create Registry Plan', + data: { breadcrumb: 'Create Plan' }, loadComponent: () => import('./components/plan-editor.component').then( (m) => m.PlanEditorComponent @@ -32,6 +52,8 @@ export const registryAdminRoutes: Routes = [ }, { path: 'plans/:planId', + title: 'Edit Registry Plan', + data: { breadcrumb: 'Edit Plan' }, loadComponent: () => import('./components/plan-editor.component').then( (m) => m.PlanEditorComponent @@ -39,6 +61,8 @@ export const registryAdminRoutes: Routes = [ }, { path: 'audit', + title: 'Registry Audit', + data: { breadcrumb: 'Audit' }, loadComponent: () => import('./components/plan-audit.component').then( (m) => m.PlanAuditComponent diff --git a/src/Web/StellaOps.Web/src/app/routes/integration-hub.routes.spec.ts b/src/Web/StellaOps.Web/src/app/routes/integration-hub.routes.spec.ts new file mode 100644 index 000000000..2dea4351a --- /dev/null +++ b/src/Web/StellaOps.Web/src/app/routes/integration-hub.routes.spec.ts @@ -0,0 +1,61 @@ +/** + * Integration Hub Routes - Route structure verification + * Sprint 023: FE-URG-004 + * + * Validates that registry-admin routes are mounted inside the integration + * hub under the canonical Integrations shell, before the catch-all + * :integrationId route, and without creating a standalone product branch. + */ +import { integrationHubRoutes } from '../features/integration-hub/integration-hub.routes'; + +describe('integrationHubRoutes', () => { + // The integration hub uses a shell component with children + const shellRoute = integrationHubRoutes[0]; + const children = shellRoute?.children ?? []; + + it('should have a shell route with children', () => { + expect(shellRoute).toBeDefined(); + expect(shellRoute.path).toBe(''); + expect(children.length).toBeGreaterThan(0); + }); + + it('should mount registry-admin as a child route', () => { + const registryAdminRoute = children.find((r) => r.path === 'registry-admin'); + expect(registryAdminRoute).toBeDefined(); + expect(registryAdminRoute!.loadChildren).toBeDefined(); + expect(registryAdminRoute!.title).toBe('Registry Admin'); + expect(registryAdminRoute!.data?.['breadcrumb']).toBe('Registry Admin'); + }); + + it('should place registry-admin before the catch-all :integrationId route', () => { + const registryAdminIndex = children.findIndex((r) => r.path === 'registry-admin'); + const catchAllIndex = children.findIndex((r) => r.path === ':integrationId'); + + expect(registryAdminIndex).toBeGreaterThan(-1); + expect(catchAllIndex).toBeGreaterThan(-1); + expect(registryAdminIndex).toBeLessThan(catchAllIndex); + }); + + it('should not introduce a standalone registry-admin route outside integration hub', () => { + // Only the integration hub shell contains registry-admin + // There should be no top-level registry-admin path + const topLevelPaths = integrationHubRoutes.map((r) => r.path); + expect(topLevelPaths).not.toContain('registry-admin'); + }); + + it('should preserve existing integration hub category routes', () => { + const childPaths = children.map((r) => r.path); + expect(childPaths).toContain('registries'); + expect(childPaths).toContain('scm'); + expect(childPaths).toContain('ci'); + expect(childPaths).toContain('secrets'); + expect(childPaths).toContain('activity'); + }); + + it('should use loadChildren for lazy-loaded registry-admin routes', () => { + const registryAdminRoute = children.find((r) => r.path === 'registry-admin'); + expect(registryAdminRoute).toBeDefined(); + expect(typeof registryAdminRoute!.loadChildren).toBe('function'); + expect(registryAdminRoute!.loadComponent).toBeUndefined(); + }); +});