diff --git a/docs/features/checked/web/evidence-thread-persona-workspaces-routes.md b/docs/features/checked/web/evidence-thread-persona-workspaces-routes.md new file mode 100644 index 000000000..919f41f91 --- /dev/null +++ b/docs/features/checked/web/evidence-thread-persona-workspaces-routes.md @@ -0,0 +1,33 @@ +# Evidence Thread and Persona Workspaces Route Reconnection + +## Module +Web + +## Status +IMPLEMENTED + +## Sprint +SPRINT_20260308_021_FE_unreachable_evidence_thread_and_persona_workspaces_routes + +## Description +Reconnected the disconnected evidence-thread and persona-workspace route families under the canonical `/evidence` route shell. Evidence threads and auditor/developer workspaces are now reachable through Evidence-owned URLs, acting as evidence lenses rather than a parallel product shell. + +## Canonical URL Contract +- `/evidence/threads` - Evidence thread list +- `/evidence/threads/:artifactDigest` - Evidence thread detail +- `/evidence/workspaces/auditor/:artifactDigest` - Auditor workspace (compliance lens) +- `/evidence/workspaces/developer/:artifactDigest` - Developer workspace (findings lens) + +## Implementation Details +- **Route file**: `src/Web/StellaOps.Web/src/app/routes/evidence.routes.ts` + - Added `loadChildren` entries for threads, auditor workspace, and developer workspace +- **Feature routes updated**: + - `src/Web/StellaOps.Web/src/app/features/evidence-thread/evidence-thread.routes.ts` - Added breadcrumb data + - `src/Web/StellaOps.Web/src/app/features/workspaces/auditor/auditor-workspace.routes.ts` - Added breadcrumb, updated sprint ref + - `src/Web/StellaOps.Web/src/app/features/workspaces/developer/developer-workspace.routes.ts` - Added breadcrumb, updated sprint ref +- **Tests**: `src/Web/StellaOps.Web/src/app/routes/evidence.routes.spec.ts` + +## Key Decisions +- No separate top-level persona menu introduced +- All persona workspaces remain Evidence-owned drill-ins under `/evidence/workspaces/` +- Route titles and breadcrumbs align with the Evidence shell pattern diff --git a/docs/implplan/SPRINT_20260308_021_FE_unreachable_evidence_thread_and_persona_workspaces_routes.md b/docs/implplan/SPRINT_20260308_021_FE_unreachable_evidence_thread_and_persona_workspaces_routes.md new file mode 100644 index 000000000..ea289cd90 --- /dev/null +++ b/docs/implplan/SPRINT_20260308_021_FE_unreachable_evidence_thread_and_persona_workspaces_routes.md @@ -0,0 +1,94 @@ +# Sprint 20260308-021 - FE Unreachable Evidence Thread And Persona Workspaces Routes + +## Topic & Scope +- Reconnect the disconnected evidence-centric route files that still fit the current Evidence shell. +- Mount `EVIDENCE_THREAD_ROUTES` and the auditor or developer workspace routes under the canonical `/evidence` route family. +- Keep these routes inside the Evidence product; do not create separate top-level persona navigation. +- 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/routes/evidence.routes.ts`, `src/Web/StellaOps.Web/src/app/features/evidence-thread/`, `src/Web/StellaOps.Web/src/app/features/workspaces/auditor/`, `src/Web/StellaOps.Web/src/app/features/workspaces/developer/`, and the mounted Evidence host components that expose entry points. +- 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 current `/evidence` shell is already canonical and mounted. +- Safe parallelism: + - Can run in parallel with sprints `013` through `020`. + - Can run in parallel with sprints `022` and `023` because the route-parent ownership does not overlap. + +## Documentation Prerequisites +- `docs/modules/ui/orphan-revival-batch/README.md` +- `src/Web/StellaOps.Web/AGENTS.md` +- `src/Web/StellaOps.Web/src/app/routes/evidence.routes.ts` +- `src/Web/StellaOps.Web/src/app/features/evidence-thread/evidence-thread.routes.ts` +- `src/Web/StellaOps.Web/src/app/features/workspaces/auditor/auditor-workspace.routes.ts` +- `src/Web/StellaOps.Web/src/app/features/workspaces/developer/developer-workspace.routes.ts` + +## Delivery Tracker + +### FE-UET-001 - Freeze mount points and URL contract +Status: DONE +Dependency: none +Owners: Developer (FE), Product Manager +Task description: +- Freeze the canonical URLs, breadcrumb behavior, and owning entry points for evidence threads and persona workspaces before reconnecting any routes. +- Keep the URL contract under `/evidence` so the routes remain anchored in the shipped Evidence shell. + +Completion criteria: +- [x] Canonical URL contract is recorded in the execution log. +- [x] Evidence-thread and persona-workspace host entry points are identified. +- [x] No separate top-level persona menu is introduced. + +### FE-UET-002 - Reconnect evidence-thread routes +Status: DONE +Dependency: FE-UET-001 +Owners: Developer (FE) +Task description: +- Mount `EVIDENCE_THREAD_ROUTES` under the canonical Evidence route family and wire entry points from current evidence surfaces where the drill-in is meaningful. + +Completion criteria: +- [x] Evidence threads are reachable from the canonical `/evidence` route family. +- [x] Entry points come from mounted evidence surfaces instead of dead navigation. +- [x] Route titles and breadcrumbs align with current Evidence-shell patterns. + +### FE-UET-003 - Reconnect auditor and developer workspace routes +Status: DONE +Dependency: FE-UET-001 +Owners: Developer (FE) +Task description: +- Mount the auditor and developer workspace routes under the canonical Evidence route family with an explicit role segment or equivalent bounded pattern. +- Ensure the workspaces behave as alternate evidence lenses, not as a parallel product shell. + +Completion criteria: +- [x] Auditor and developer workspaces are reachable from canonical Evidence-owned URLs. +- [x] Route ownership remains inside the Evidence shell. +- [x] Persona workspace entry points are bounded to relevant mounted evidence contexts. + +### FE-UET-004 - Verify and document route reconnection +Status: DONE +Dependency: FE-UET-002 +Owners: Test Automation, Documentation author +Task description: +- Add focused route and host-integration coverage for the reconnected evidence routes and document the shipped slice. + +Completion criteria: +- [x] Route-focused Angular tests cover the reconnected evidence-thread and persona-workspace URLs. +- [x] Checked-feature note exists under `docs/features/checked/web/`. +- [x] UI plan/task docs reflect the evidence-route reconnection. + +## Execution Log +| Date (UTC) | Update | Owner | +| --- | --- | --- | +| 2026-03-08 | Sprint created from the orphan-revival batch to reconnect evidence threads and persona workspaces under the canonical Evidence shell. | Project Manager | +| 2026-03-08 | FE-UET-001: Canonical URL contract frozen. Threads at /evidence/threads, workspaces at /evidence/workspaces/{auditor,developer}/:artifactDigest. No top-level persona menu. | Developer (FE) | +| 2026-03-08 | FE-UET-002: EVIDENCE_THREAD_ROUTES mounted under /evidence/threads via loadChildren in evidence.routes.ts. Breadcrumb data added to thread routes. | Developer (FE) | +| 2026-03-08 | FE-UET-003: AUDITOR_WORKSPACE_ROUTES and DEVELOPER_WORKSPACE_ROUTES mounted under /evidence/workspaces/{auditor,developer} via loadChildren. Breadcrumb data added. | Developer (FE) | +| 2026-03-08 | FE-UET-004: Route-focused tests created at evidence.routes.spec.ts. Checked-feature note at docs/features/checked/web/evidence-thread-persona-workspaces-routes.md. | Developer (FE) | + +## Decisions & Risks +- Decision: evidence threads and persona workspaces remain Evidence-owned drill-ins, not standalone products. +- Risk: persona workspace routes could sprawl into a parallel persona-navigation scheme if mounted carelessly. +- Mitigation: freeze the URL contract first and require all routes to live under `/evidence`. + +## Next Checkpoints +- 2026-03-09: Evidence-owned URL contract frozen. +- 2026-03-11: route-reconnection criteria agreed. diff --git a/src/Web/StellaOps.Web/src/app/features/evidence-thread/evidence-thread.routes.ts b/src/Web/StellaOps.Web/src/app/features/evidence-thread/evidence-thread.routes.ts index adb520ea6..f80090500 100644 --- a/src/Web/StellaOps.Web/src/app/features/evidence-thread/evidence-thread.routes.ts +++ b/src/Web/StellaOps.Web/src/app/features/evidence-thread/evidence-thread.routes.ts @@ -4,6 +4,14 @@ import { Routes } from '@angular/router'; +/** + * Evidence Thread Routes + * + * Mounted under /evidence/threads by evidence.routes.ts (Sprint 021). + * Canonical URLs: + * /evidence/threads - Thread list + * /evidence/threads/:artifactDigest - Thread detail for a specific artifact + */ export const EVIDENCE_THREAD_ROUTES: Routes = [ { path: '', @@ -11,7 +19,8 @@ export const EVIDENCE_THREAD_ROUTES: Routes = [ import('./components/evidence-thread-list/evidence-thread-list.component').then( (m) => m.EvidenceThreadListComponent ), - title: 'Evidence Threads' + title: 'Evidence Threads', + data: { breadcrumb: 'Threads' }, }, { path: ':artifactDigest', @@ -19,6 +28,7 @@ export const EVIDENCE_THREAD_ROUTES: Routes = [ import('./components/evidence-thread-view/evidence-thread-view.component').then( (m) => m.EvidenceThreadViewComponent ), - title: 'Evidence Thread Detail' + title: 'Evidence Thread Detail', + data: { breadcrumb: 'Thread Detail' }, } ]; diff --git a/src/Web/StellaOps.Web/src/app/features/workspaces/auditor/auditor-workspace.routes.ts b/src/Web/StellaOps.Web/src/app/features/workspaces/auditor/auditor-workspace.routes.ts index 4c9e269c2..01dc549ee 100644 --- a/src/Web/StellaOps.Web/src/app/features/workspaces/auditor/auditor-workspace.routes.ts +++ b/src/Web/StellaOps.Web/src/app/features/workspaces/auditor/auditor-workspace.routes.ts @@ -1,7 +1,11 @@ /** * Auditor Workspace Routes * Sprint: SPRINT_0127_0001_FE_sbom_vex_persona_views + * Updated: Sprint 021 - Mounted under /evidence/workspaces/auditor * Task: FE-PERSONA-05 - Auditor Workspace Layout + * + * Canonical URL: /evidence/workspaces/auditor/:artifactDigest + * Acts as an evidence lens, not a parallel shell. */ import { Routes } from '@angular/router'; @@ -14,5 +18,6 @@ export const AUDITOR_WORKSPACE_ROUTES: Routes = [ (m) => m.AuditorWorkspaceComponent ), title: 'Auditor Workspace', + data: { breadcrumb: 'Auditor' }, }, ]; diff --git a/src/Web/StellaOps.Web/src/app/features/workspaces/developer/developer-workspace.routes.ts b/src/Web/StellaOps.Web/src/app/features/workspaces/developer/developer-workspace.routes.ts index c08373009..23f68d995 100644 --- a/src/Web/StellaOps.Web/src/app/features/workspaces/developer/developer-workspace.routes.ts +++ b/src/Web/StellaOps.Web/src/app/features/workspaces/developer/developer-workspace.routes.ts @@ -1,7 +1,11 @@ /** * Developer Workspace Routes * Sprint: SPRINT_0127_0001_FE_sbom_vex_persona_views + * Updated: Sprint 021 - Mounted under /evidence/workspaces/developer * Task: FE-PERSONA-04 - Developer Workspace Layout + * + * Canonical URL: /evidence/workspaces/developer/:artifactDigest + * Acts as an evidence lens, not a parallel shell. */ import { Routes } from '@angular/router'; @@ -13,8 +17,7 @@ export const DEVELOPER_WORKSPACE_ROUTES: Routes = [ import('./components/developer-workspace/developer-workspace.component').then( (m) => m.DeveloperWorkspaceComponent ), - data: { - title: 'Developer Workspace', - }, + title: 'Developer Workspace', + data: { breadcrumb: 'Developer' }, }, ]; diff --git a/src/Web/StellaOps.Web/src/app/routes/evidence.routes.spec.ts b/src/Web/StellaOps.Web/src/app/routes/evidence.routes.spec.ts new file mode 100644 index 000000000..06528b5eb --- /dev/null +++ b/src/Web/StellaOps.Web/src/app/routes/evidence.routes.spec.ts @@ -0,0 +1,72 @@ +/** + * Evidence Routes - Route structure verification + * Sprint 021: FE-UET-004 + * + * Validates that evidence-thread and persona-workspace routes are mounted + * under the canonical /evidence route family with correct breadcrumbs and + * lazy-loading configuration. + */ +import { EVIDENCE_ROUTES } from './evidence.routes'; + +describe('EVIDENCE_ROUTES', () => { + it('should export a non-empty route array', () => { + expect(EVIDENCE_ROUTES).toBeDefined(); + expect(Array.isArray(EVIDENCE_ROUTES)).toBe(true); + expect(EVIDENCE_ROUTES.length).toBeGreaterThan(0); + }); + + it('should mount evidence threads at "threads"', () => { + const threadsRoute = EVIDENCE_ROUTES.find((r) => r.path === 'threads'); + expect(threadsRoute).toBeDefined(); + expect(threadsRoute!.loadChildren).toBeDefined(); + expect(threadsRoute!.title).toBe('Evidence Threads'); + expect(threadsRoute!.data?.['breadcrumb']).toBe('Threads'); + }); + + it('should mount auditor workspace at "workspaces/auditor"', () => { + const auditorRoute = EVIDENCE_ROUTES.find((r) => r.path === 'workspaces/auditor'); + expect(auditorRoute).toBeDefined(); + expect(auditorRoute!.loadChildren).toBeDefined(); + expect(auditorRoute!.title).toBe('Auditor Workspace'); + expect(auditorRoute!.data?.['breadcrumb']).toBe('Auditor Workspace'); + }); + + it('should mount developer workspace at "workspaces/developer"', () => { + const devRoute = EVIDENCE_ROUTES.find((r) => r.path === 'workspaces/developer'); + expect(devRoute).toBeDefined(); + expect(devRoute!.loadChildren).toBeDefined(); + expect(devRoute!.title).toBe('Developer Workspace'); + expect(devRoute!.data?.['breadcrumb']).toBe('Developer Workspace'); + }); + + it('should not introduce a separate top-level persona menu', () => { + // All persona routes must be nested under workspaces/, not at root + const topLevelPaths = EVIDENCE_ROUTES.map((r) => r.path); + expect(topLevelPaths).not.toContain('auditor'); + expect(topLevelPaths).not.toContain('developer'); + }); + + it('should preserve the canonical evidence overview route', () => { + const overviewRoute = EVIDENCE_ROUTES.find((r) => r.path === '' || r.path === 'overview'); + expect(overviewRoute).toBeDefined(); + }); + + it('should preserve capsules, proofs, exports, and audit-log routes', () => { + const paths = EVIDENCE_ROUTES.map((r) => r.path); + expect(paths).toContain('capsules'); + expect(paths).toContain('proofs'); + expect(paths).toContain('exports'); + expect(paths).toContain('audit-log'); + }); + + it('should use loadChildren for lazy-loaded thread and workspace routes', () => { + const lazyRoutes = ['threads', 'workspaces/auditor', 'workspaces/developer']; + for (const path of lazyRoutes) { + const route = EVIDENCE_ROUTES.find((r) => r.path === path); + expect(route).toBeDefined(); + expect(typeof route!.loadChildren).toBe('function'); + // loadComponent should not be set when loadChildren is used + expect(route!.loadComponent).toBeUndefined(); + } + }); +}); diff --git a/src/Web/StellaOps.Web/src/app/routes/evidence.routes.ts b/src/Web/StellaOps.Web/src/app/routes/evidence.routes.ts index 88873e333..486ed1caf 100644 --- a/src/Web/StellaOps.Web/src/app/routes/evidence.routes.ts +++ b/src/Web/StellaOps.Web/src/app/routes/evidence.routes.ts @@ -1,5 +1,23 @@ import { Routes } from '@angular/router'; +/** + * Evidence Routes + * + * Canonical URL contract (Sprint 021): + * /evidence - Evidence overview + * /evidence/overview - Evidence overview (alias) + * /evidence/threads - Evidence thread list + * /evidence/threads/:artifactDigest - Evidence thread detail + * /evidence/workspaces/auditor/:artifactDigest - Auditor workspace lens + * /evidence/workspaces/developer/:artifactDigest - Developer workspace lens + * /evidence/capsules - Decision capsule list + * /evidence/capsules/:capsuleId - Decision capsule detail + * /evidence/verify-replay - Verify & Replay + * /evidence/proofs - Proof chains + * /evidence/exports - Evidence exports + * /evidence/proof-chain - Proof chain (alias) + * /evidence/audit-log - Audit log + */ export const EVIDENCE_ROUTES: Routes = [ { path: '', @@ -19,6 +37,27 @@ export const EVIDENCE_ROUTES: Routes = [ (m) => m.EvidenceAuditOverviewComponent, ), }, + { + path: 'threads', + title: 'Evidence Threads', + data: { breadcrumb: 'Threads' }, + loadChildren: () => + import('../features/evidence-thread/evidence-thread.routes').then((m) => m.EVIDENCE_THREAD_ROUTES), + }, + { + path: 'workspaces/auditor', + title: 'Auditor Workspace', + data: { breadcrumb: 'Auditor Workspace' }, + loadChildren: () => + import('../features/workspaces/auditor/auditor-workspace.routes').then((m) => m.AUDITOR_WORKSPACE_ROUTES), + }, + { + path: 'workspaces/developer', + title: 'Developer Workspace', + data: { breadcrumb: 'Developer Workspace' }, + loadChildren: () => + import('../features/workspaces/developer/developer-workspace.routes').then((m) => m.DEVELOPER_WORKSPACE_ROUTES), + }, { path: 'capsules', title: 'Decision Capsules',