Routing Architecture Analysis & Fix Plan
Complete analysis of current routing issues and systematic fix
🔍 Routing Architecture Analysis - October 29, 2025
Time: Evening
Status: 🔴 CRITICAL ISSUES FOUND
Priority: P0 - Must fix before proceeding
🎯 Problem Statement
User reported: "Routes are all over the place - we can't even access our space routes"
Current State:
- URL:
localhost:5200/my-space/dashboard - Page loads but routing is broken
- Space-first routing (
/:spaceSlug) is configured but not working correctly - Multiple routing layers causing confusion
📊 Current Architecture Overview
1. Route Structure ✅ CORRECT PATTERN
// apps/gograb-space/src/app/app.routes.ts
PUBLIC ROUTES:
/landing → LandingComponent
/auth/* → Auth routes
PROTECTED ROUTES (Space-First):
/:spaceSlug → AppShellComponent
├─ dashboard → GSpaceDashboardComponent
├─ universe/create → UniverseCreationWizardComponent
├─ ux-test/* → UiBuilderRoutes
├─ [MODULE ROUTES INJECTED DYNAMICALLY]
│ ├─ singularity → SingularityManifest
│ ├─ space-map → SpaceMapManifest
│ ├─ editor → EditorManifest
│ ├─ modularity → ModularityManifest
│ ├─ widgets → WidgetsManagerManifest
│ └─ launch-station → LaunchStationManifest
├─ content-browser → ContentBrowserComponent
├─ theme-test/* → Theme routes
└─ demos/* → Demo routes
Guards & Resolvers:
authGuard- Ensures user is authenticatedspaceGuard- Validates space contextspaceResolver- Pre-fetches space data
🔴 Critical Issues Identified
Issue #1: Two Navigation Systems Fighting Each Other
PROBLEM: You have BOTH systems running simultaneously:
MainSidenavComponent(Old/Manual)- Location:
apps/gograb-space/src/app/layout/main-layout/main-sidenav/main-sidenav.component.ts - Manually builds storage routes, specialized categories
- Uses
NavigationBuilderServiceto get route-based items - Complex computed signal:
navigationCategories()
- Location:
SidebarComponent(New/Dynamic)- Location:
apps/gograb-space/src/app/core/layout/sidebar.component.ts - Used by
AppShellComponent - Reads from
ModuleRegistryService - Shows registered module navigation items
- Location:
Result: CONFLICT! Two sidebars, two navigation systems, confusion.
Issue #2: Navigation Builder Race Condition
PROBLEM: Navigation is built BEFORE routes are registered
Flow:
1. App starts
2. NavigationBuilderService initializes
3. Builds navigation from routes ← ROUTES NOT READY YET!
4. BrowserBootstrapperService starts
5. Routes get registered by RouteRegistrationService
6. RouteReadyService notifies
7. Navigation rebuilds (via effect)
Issue: Steps 2-3 happen before step 5, so initial navigation is incomplete.
Evidence:
// navigation-builder.service.ts
constructor() {
// Try to load from cache first
this.loadFromCache();
// Initial build with static routes
this.buildNavigationFromRoutes(); // ← Too early!
// React to route changes
effect(() => {
const ready = this.routeReady.routesReady();
if (ready) {
console.log('🔄 NavigationBuilderService: Routes ready, rebuilding navigation');
this.buildNavigationFromRoutes();
}
});
}
Issue #3: Space Context Not Set Early Enough
PROBLEM: Routes depend on spaceSlug but it's not guaranteed to be set
Evidence:
// sidebar.component.ts (line 347)
const spaceSlug = this.universeContext.spaceSlug() || 'test-space';
// main-sidenav.component.ts (line 37)
const spaceSlug = this.universeContext.spaceSlug() || 'test-space';
Fallback to 'test-space' means spaceSlug might not be set correctly.
Where it should be set:
// spaceGuard should set it when route matches /:spaceSlug
// spaceResolver should populate it with space data
Issue #4: Docs App Service in GoGrab Space
PROBLEM: You're analyzing project-config.service.ts from apps/docs-angular
The user pointed to:
@project-config.service.ts
But this file is:
apps/docs-angular/src/app/services/project-config.service.ts
This is for the DOCS app, NOT gograb-space!
The gograb-space app doesn't use this service at all. This might be causing confusion.
Issue #5: Module Routes Not Visible
PROBLEM: BrowserBootstrapperService registers routes but sidebar is empty
Expected: Sidebar should show:
- Singularity
- Space Map
- Editor
- Modularity
- Widgets Manager
- Launch Station
Actual: Sidebar shows "No modules registered"
Reason: ModuleRegistryService.getAllModules() returns modules, but their navigation.menuItems might be empty or undefined.
🎯 Root Cause Analysis
Core Problem: Architectural Confusion
You're mixing THREE different routing/navigation paradigms:
- Static routes (
app.routes.ts) - Dynamic module routes (via
BrowserBootstrapperService) - Manual navigation building (via
NavigationBuilderService)
Plus TWO sidebar components:
MainSidenavComponent(old)SidebarComponent(new)
Result: Chaos!
✅ Solution: Simplify & Fix
Step 1: Choose ONE Navigation System
RECOMMENDED: Use the NEW system (AppShell + SidebarComponent + ModuleRegistry)
Remove/Deprecate:
MainSidenavComponent(too complex, manual)NavigationBuilderServicecaching logic (causes race conditions)- Manual
navigationCategoriescomputed signal
Step 2: Fix Module Manifests
PROBLEM: Modules might not have navigation.menuItems defined
CHECK:
// Each manifest should have:
{
id: 'singularity',
name: 'Singularity',
navigation: {
menuItems: [
{
id: 'logic-builder',
label: 'Logic Builder',
route: '/logic-builder',
icon: 'fas fa-brain'
}
]
}
}
ACTION: Verify all manifests have proper navigation config.
Step 3: Simplify Navigation Builder
CURRENT (Complex):
constructor() {
this.loadFromCache(); // ← Cache layer (adds complexity)
this.buildNavigationFromRoutes(); // ← Initial build (too early)
effect(() => { ... }); // ← Reactive rebuild (good!)
}
SIMPLIFIED:
constructor() {
// ONLY reactive building, NO cache, NO initial build
effect(() => {
const ready = this.routeReady.routesReady();
if (ready) {
this.buildNavigationFromRoutes();
}
}, { allowSignalWrites: true });
}
Step 4: Ensure Space Context is Set
FIX: spaceGuard must set spaceSlug BEFORE allowing navigation
// libs/core-angular/src/lib/guards/space.guard.ts
export const spaceGuard: CanActivateFn = async (route, state) => {
const universeContext = inject(UniverseContextService);
const spaceSlug = route.params['spaceSlug'];
if (!spaceSlug) {
console.error('❌ spaceGuard: No spaceSlug in route');
return router.createUrlTree(['/landing']);
}
// ✅ Set space context BEFORE allowing navigation
universeContext.setSpaceContext({
spaceId: spaceSlug,
spaceSlug: spaceSlug
});
console.log('✅ spaceGuard: Space context set', spaceSlug);
return true;
};
Step 5: Fix AppShell to Use Correct Sidebar
CURRENT:
// app-shell.component.ts uses SidebarComponent ✅
import { SidebarComponent } from './sidebar.component';
BUT:
// main-layout still uses MainSidenavComponent ❌
// This component should be REMOVED or marked deprecated
ACTION: Remove main-sidenav.component.ts from main layout
📋 Implementation Plan
Phase 1: Clean Up (30 min)
- ✅ Identify which navigation system to keep
- ✅ Mark old components as deprecated
- ✅ Remove conflicting navigation builders
Phase 2: Fix Guards (20 min)
- ✅ Update
spaceGuardto set context - ✅ Add logging to see guard execution
- ✅ Test space context is available
Phase 3: Fix Navigation Builder (30 min)
- ✅ Remove cache logic (causes race conditions)
- ✅ Remove initial build (happens too early)
- ✅ Keep ONLY reactive building via effect
- ✅ Add proper error handling
Phase 4: Verify Module Manifests (20 min)
- ✅ Check each manifest has
navigation.menuItems - ✅ Add missing navigation configs
- ✅ Test module registry returns correct data
Phase 5: Test Everything (30 min)
- ✅ Test
/my-space/dashboardloads - ✅ Test sidebar shows all modules
- ✅ Test navigation links work
- ✅ Test space context is correct
Total Time: ~2 hours
🎯 Decision Points
Question 1: Which Navigation System?
Option A (RECOMMENDED): AppShell + SidebarComponent + ModuleRegistry
- ✅ Clean separation
- ✅ Module-based
- ✅ Dynamic
- ✅ Future-proof
Option B: Keep both (NOT RECOMMENDED)
- ❌ Complex
- ❌ Conflicting
- ❌ Hard to maintain
DECISION: Use Option A, deprecate MainSidenavComponent
Question 2: What About Storage Routes?
PROBLEM: MainSidenavComponent has storageTree() for storage testing routes
SOLUTION: Move storage routes to a MODULE
// Create: @storage-system/manifest.ts
export const StorageSystemManifest: ModuleManifest = {
id: 'storage-system',
name: 'Storage System',
navigation: {
menuItems: [
{ id: 'test', label: 'Test Lab', route: '/test' },
{ id: 'analysis', label: 'Deep Analysis', route: '/analysis' },
// ... etc
]
}
};
// Register in main.ts
moduleRegistry.registerModule(StorageSystemManifest);
Question 3: What About Internal Tools Category?
PROBLEM: MainSidenavComponent has "🔧 Internal Tools" category
SOLUTION: Add to module manifests as a category field
export const StorageSystemManifest: ModuleManifest = {
id: 'storage-system',
name: 'Storage System',
category: 'internal-tools', // ✅ NEW
// ...
};
Then SidebarComponent can group by category.
🔄 Migration Path
Immediate (This Session)
- ✅ Fix spaceGuard to set context
- ✅ Simplify NavigationBuilderService
- ✅ Add logging to debug route registration
- ✅ Test basic navigation works
Short Term (Next Session)
- ⏳ Move storage routes to module manifest
- ⏳ Add category support to SidebarComponent
- ⏳ Remove MainSidenavComponent completely
- ⏳ Add navigation caching (AFTER everything works)
Long Term (Next Week)
- ⏳ Add navigation preferences (user can collapse categories)
- ⏳ Add navigation search
- ⏳ Add navigation keyboard shortcuts
- ⏳ Add navigation analytics
📝 Code Changes Required
File 1: spaceGuard (libs/core-angular)
ADD: Space context setting
// BEFORE
export const spaceGuard: CanActivateFn = async (route, state) => {
// ... validation only
};
// AFTER
export const spaceGuard: CanActivateFn = async (route, state) => {
const universeContext = inject(UniverseContextService);
const spaceSlug = route.params['spaceSlug'];
// ✅ Set space context
universeContext.setSpaceContext({
spaceId: spaceSlug,
spaceSlug: spaceSlug
});
return true;
};
File 2: navigation-builder.service.ts
REMOVE: Cache and initial build
// BEFORE
constructor() {
this.loadFromCache(); // ❌ Remove
this.buildNavigationFromRoutes(); // ❌ Remove
effect(() => { ... });
}
// AFTER
constructor() {
// ONLY reactive building
effect(() => {
const ready = this.routeReady.routesReady();
if (ready) {
console.log('🔄 NavigationBuilderService: Building navigation from routes');
this.buildNavigationFromRoutes();
// DON'T save to cache here - causes issues
}
}, { allowSignalWrites: true });
}
File 3: main-sidenav.component.ts
MARK: Deprecated (or remove)
// ADD to top of file:
/**
* @deprecated This component is being replaced by SidebarComponent
* in AppShellComponent. Use that instead.
*
* This component will be removed in a future version.
*/
File 4: Module Manifests
ADD: Navigation menu items
// Example: singularity.manifest.ts
export const SingularityManifest: ModuleManifest = {
id: 'singularity',
name: 'Singularity',
navigation: {
menuItems: [
{
id: 'logic-builder',
label: 'Logic Builder',
route: '/logic-builder',
icon: 'fas fa-brain',
description: 'Visual logic builder'
},
{
id: 'flow-composer',
label: 'Flow Composer',
route: '/flow-composer',
icon: 'fas fa-project-diagram',
description: 'Create and manage flows'
}
]
},
// ... rest of manifest
};
✅ Success Criteria
After fixes, you should see:
- ✅ Navigate to
/my-space/dashboard→ works - ✅ Sidebar shows all registered modules
- ✅ Console logs show:
✅ spaceGuard: Space context set: my-space 🚀 Dynamic Route Registration Complete 🎯 RouteReadyService: Module routes registered 🔄 NavigationBuilderService: Building navigation from routes - ✅ No errors in console
- ✅ Space context available:
spaceSlug() === 'my-space' - ✅ Navigation links work correctly
🎓 Key Learnings
1. Simpler is Better
Too many layers of abstraction cause problems:
- Cache layer → race conditions
- Multiple navigation systems → confusion
- Early initialization → incomplete data
Solution: One system, reactive, event-driven.
2. Guards Set Context
Route guards should:
- ✅ Validate access
- ✅ Set context (spaceSlug, userId, etc.)
- ✅ Pre-fetch data if needed
Not just: Check and return boolean.
3. Event-Driven Navigation
Navigation should:
- ✅ Wait for routes to be ready
- ✅ React to route changes
- ✅ Rebuild when needed
Not: Build immediately on construction.
🚀 Next Steps
IMMEDIATE:
- Implement fixes from this document
- Test navigation works
- Fix any remaining issues
- Document final architecture
THEN:
- Move to Phase 2 of your original plan
- Continue with widget system unification
- Complete foundation work
Status: 📋 Analysis Complete
Action Required: Implement fixes
Estimated Time: 2 hours
Priority: P0 - Critical
Last Updated: October 29, 2025
Analyst: AI Assistant
Approved By: (Pending user review)