SPACE SLUG ARCHITECTURAL FIX
Documentation for Plans
๐๏ธ Space Slug Architectural Fix - COMPLETE
Date: October 31, 2025
Status: โ
IMPLEMENTED
Purpose: Fix space slug routing to work correctly in development vs. production
๐ฏ THE PROBLEM
The space slug was changing based on the URL, creating a terrible user experience:
User navigates to: /space-test-should-not-work/dashboard
Result: Space slug becomes "space-test-should-not-work" โ
User navigates to: /anything-here/dashboard
Result: Space slug becomes "anything-here" โ
Root Cause: The space.guard.ts was extracting spaceSlug from the URL and passing it to initializeSpace(), which would then update the space with this slug.
โ THE SOLUTION
Implemented deployment mode-aware routing:
Development Mode (deploymentMode: 'development')
- โ Space determined by logged-in user, NOT from URL
- โ URL slug is ignored completely
- โ User's space slug is stable and never changes
- โ After space loads, redirects to correct slug URL for consistency
Subdomain Mode (deploymentMode: 'subdomain')
- โ
Space determined by URL/subdomain (e.g.,
acme.gograb.space) - โ Used for production deployment with custom domains
- โ Each space has its own subdomain
๐ FILES CHANGED
1. Environment Configuration
apps/gograb-space/src/environments/environment.shared.ts
export const DEPLOYMENT_MODES = {
development: 'development', // Space from user, not URL
subdomain: 'subdomain', // Space from URL/subdomain
} as const;
export type DeploymentMode = keyof typeof DEPLOYMENT_MODES;
apps/gograb-space/src/environments/environment.ts
import { DEPLOYMENT_MODES } from './environment.shared';
export const environment = {
// ...
deploymentMode: DEPLOYMENT_MODES.development, // โ Development mode
};
apps/gograb-space/src/environments/environment.prod.ts
import { DEPLOYMENT_MODES } from './environment.shared';
export const environment = {
// ...
deploymentMode: DEPLOYMENT_MODES.subdomain, // โ Subdomain mode
};
2. Core Angular Library
libs/core-angular/src/lib/tokens/deployment-mode.token.ts (NEW FILE)
import { InjectionToken } from '@angular/core';
export type DeploymentMode = 'development' | 'subdomain';
export const DEPLOYMENT_MODE = new InjectionToken<DeploymentMode>('DEPLOYMENT_MODE', {
providedIn: 'root',
factory: () => 'development'
});
libs/core-angular/src/index.ts
// Export tokens
export { DEPLOYMENT_MODE, type DeploymentMode } from './lib/tokens/deployment-mode.token';
3. Space Guard
libs/core-angular/src/lib/guards/space.guard.ts
import { DEPLOYMENT_MODE } from '../tokens/deployment-mode.token';
export const spaceGuard: CanActivateFn = async (route, state) => {
const deploymentMode = inject(DEPLOYMENT_MODE);
const spaceSlug = route.paramMap.get('spaceSlug');
// ...
// ๐ฏ CRITICAL: Deployment mode logic
let spaceSlugToUse: string | undefined;
if (deploymentMode === 'development') {
// Development: ALWAYS load user's space, ignore URL
spaceSlugToUse = undefined;
} else {
// Subdomain: Use URL slug
spaceSlugToUse = spaceSlug || undefined;
}
await spaceService.initializeSpace(userId, spaceSlugToUse);
// After initialization, redirect to correct slug URL
if (currentSpace.spaceSlug !== spaceSlug) {
const newUrl = state.url.replace(`/${spaceSlug}/`, `/${currentSpace.spaceSlug}/`);
return router.parseUrl(newUrl);
}
};
4. Main App Providers
apps/gograb-space/src/main.ts
import { DEPLOYMENT_MODE } from '@libs-foundational/core-angular';
bootstrapApplication(AppComponent, {
providers: [
// ...
{
provide: DEPLOYMENT_MODE,
useValue: environment.deploymentMode // โ Inject from environment
},
]
});
๐งช HOW TO TEST
1. Clear Old Data
// In browser console:
await clearCachedSpaceData();
2. Reload & Verify
1. Reload page: http://localhost:5200/
2. Login as: [email protected]
3. Navigate to ANY URL with ANY slug:
- http://localhost:5200/test-123/dashboard
- http://localhost:5200/whatever/editor
- http://localhost:5200/random-slug/space-map
4. Check "Current Space" section:
- NAME: "My space"
- SLUG: "my-space" โ
(ALWAYS stable!)
5. URL should auto-redirect to: /my-space/dashboard
โจ EXPECTED BEHAVIOR
Development Mode (Current)
// User: [email protected]
// Space: "My space" (slug: "my-space")
Navigate to: /anything/dashboard
Auto-redirect: /my-space/dashboard โ
Navigate to: /test-123/editor
Auto-redirect: /my-space/editor โ
Navigate to: /random/space-map
Auto-redirect: /my-space/space-map โ
Space slug NEVER changes! โ
Subdomain Mode (Future Production)
// URL: https://acme.gograb.space/dashboard
// Space determined by subdomain: "acme"
Navigate to: /dashboard
Loads space: "acme" โ
Navigate to: /editor
Still in space: "acme" โ
๐ IMPLEMENTATION STATISTICS
- Files Created: 1 (deployment-mode.token.ts)
- Files Modified: 6
- 3 environment files
- 1 space guard
- 1 main.ts
- 1 core-angular index
- Lines of Code: ~80 lines
- Complexity: Medium
- Impact: HIGH (fixes critical UX issue)
๐ BENEFITS
โ
Stable Space Slugs: Never change unexpectedly
โ
Flexible Architecture: Easy to switch between dev/prod modes
โ
Future-Proof: Ready for subdomain deployment
โ
Type-Safe: Full TypeScript support
โ
Zero Runtime Cost: Uses Angular's DI system
โ
Clear Separation: Development vs. production behavior
๐ NEXT STEPS
- โ Clear cached data
- โ Test in development mode
- โณ Deploy to staging with subdomain mode
- โณ Test multi-space architecture
- โณ Add space selector UI for users with multiple spaces
End of Document | Last Updated: October 31, 2025