PROJECT SCOPED ARCHITECTURE
Comprehensive documentation system guides
Project-Scoped Root Architecture
🎯 Overview
The docs-angular application has been transformed from a folder-based routing system to a project-scoped root architecture where each project acts as its own application root, with explicit project selection and state management.
📐 Architecture Principles
1. Explicit Project Selection
- Users must explicitly select a project before accessing documentation
- Project selection is persisted across sessions in localStorage
- No implicit project detection from URLs
2. Project as Context
- All paths are relative to the currently selected project
- URL format:
/{contentPath}instead of/projectName/{contentPath} - Project context stored in NGXS state (ProjectSelectionState)
3. Preserved Access Control
- ✅ Password Protection: Private projects require authentication
- ✅ Visibility Rules: Public vs Private distinction
- ✅ Cross-Project Access: Projects can define which other projects they can see
- ✅ Unlock Persistence: Remembered across sessions
4. Clean Separation
- Project switching requires going through selection screen
- No cross-project navigation via direct URLs
- Each project maintains its own navigation structure
🏗️ Key Components
State Management
ProjectSelectionState
{
currentProjectId: string | null,
currentProjectMetadata: ProjectMetadata | null,
availableProjects: ProjectMetadata[],
lastSelectedTimestamp: number | null,
isInitialized: boolean
}
Actions:
SelectProject- Select a projectClearProject- Clear selectionLoadPersistedProject- Load from localStorageLoadAvailableProjects- Load all available projects
Services
DocsConfigService
- Purpose: Provides project-scoped paths
- Key Method:
effectiveDocsPath()returnsdocs/{language}/{projectName}/ - Integration: Uses ProjectSelectionState for current project
PathResolutionService
- Purpose: Resolves file paths within current project
- Simplified: No longer needs
projectScopeparameter - Format: Paths are relative to project root
AccessService (Enhanced)
- Purpose: Manages access control and cross-project visibility
- New Methods:
canAccessProject(targetProjectId)- Check if current project can access targetgetAccessibleProjects()- Get all accessible projectsgetAccessibleProjectsForLanguage(lang)- Filter by language
- Preserved Features:
- Password protection
- Unlock state management
- Visibility rules
- Project-specific configurations
NavigationService
- Updated: Uses ProjectSelectionState instead of URL parsing
- Project-Scoped: Navigation is scoped to current project
- No Cross-Project: Cannot navigate between projects via URLs
Components
ProjectSelectionComponent
- Beautiful UI: Gradient background with project cards
- Language Switching: Toggle between English/Spanish
- Access Control: Shows locked/unlocked status
- Password Prompt: Handles private project authentication
ProjectSwitcherComponent
- Updated: Uses ProjectSelectionState for current project
- Access-Aware: Shows only accessible projects based on rules
- Selection Page: Redirects to selection page for switching
📊 URL Structure
Before (Folder-Based)
http://localhost:5010/getting-started → public project
http://localhost:5010/GoGrab-Space/architecture → GoGrab-Space project
http://localhost:5010/private/confidential → private project
After (Project-Scoped)
http://localhost:5010/select-project → Project selection
http://localhost:5010/architecture → Current project's architecture page
http://localhost:5010/libs/ux-portal → Current project's libs/ux-portal page
Project Context: Stored in ProjectSelectionState, not in URL
🔐 Access Control Matrix
| Current Project Type | Can Access Public Projects | Can Access Private Projects | Notes |
|---|---|---|---|
| Public | ✅ Yes (all public) | ✅ If unlocked | Standard public access |
| Private (hasAccessToPublic: true) | ✅ Yes | ✅ If unlocked | Enhanced private project |
| Private (hasAccessToPublic: false) | ❌ No | ✅ Own + unlocked | Restricted private project |
| No Selection | ✅ Yes (public only) | ❌ No | Before project selection |
🔄 Project Selection Flow
graph TD
A[User Visits App] --> B{Project Selected?}
B -->|No| C[Show Project Selection Page]
B -->|Yes| D[Load Project from State]
C --> E[User Selects Project]
E --> F{Requires Password?}
F -->|Yes| G[Prompt Password]
F -->|No| H[Store in State]
G --> I{Correct?}
I -->|Yes| H
I -->|No| E
H --> J[Navigate to Project]
J --> K[Load Documentation]
📁 Path Resolution
DocsConfigService
effectiveDocsPath() {
const project = currentProject();
if (!project) return 'docs';
const lang = project.language === 'spanish' ? 'spanish' : 'english';
return `docs/${lang}/${project.name}`;
}
PathResolutionService
resolveDocumentationFilePath(relativePath: string) {
const basePath = this.getEffectiveDocsPath(); // docs/english/GoGrab-Space
const cleanPath = relativePath.replace(/^\/+/, '');
return `${basePath}/${cleanPath}.md`; // docs/english/GoGrab-Space/architecture.md
}
🚀 Benefits
User Experience
- Clear Project Context: Always know which project you're viewing
- Explicit Selection: No ambiguity about current project
- Fast Switching: Quick project selection via beautiful UI
- Persistent State: Remember project across sessions
Developer Experience
- Simplified Paths: No project name in URLs
- Type Safety: Strong typing with ProjectMetadata
- Centralized State: Single source of truth (NGXS)
- Easier Testing: Mock project selection state
Architecture
- Clean Separation: Each project is independent
- Access Control: Fine-grained project visibility rules
- Scalability: Easy to add new projects
- Maintainability: Less complex path resolution
⚠️ Breaking Changes
URLs
- ❌ Old:
/public/getting-started - ❌ Old:
/GoGrab-Space/architecture - ✅ New:
/architecture(with project in state)
Bookmarks
- Users must re-bookmark pages after selecting projects
- No automatic URL migration
Cross-Project Links
- Cannot link directly between projects via URLs
- Must use project switcher UI
🔧 Configuration
Project Definition (docs-folders-config.json)
{
"name": "GoGrab-Space",
"path": "docs/english/GoGrab-Space",
"language": "english",
"isRoot": true,
"password": null,
"config": {
"search": {
"scopeToCurrentProject": true,
"crossProjectSearch": false,
"hasAccessToPublic": false
},
"navigation": {
"enableBreadcrumbs": true,
"showProjectIcon": true
}
}
}
Access Rules
hasAccessToPublic: Can private project access public projects?scopeToCurrentProject: Limit search to current project?crossProjectSearch: Allow searching other projects?
📝 Implementation Checklist
✅ Completed
- ProjectSelectionState (NGXS)
- ProjectSelectionComponent (UI)
- ProjectSelectedGuard (Route protection)
- App initialization (Load persisted project)
- DocsConfigService (Project-scoped paths)
- PathResolutionService (Simplified paths)
- AccessService (Enhanced with cross-project rules)
- NavigationService (State-based project detection)
- ProjectSwitcherComponent (Selection page redirect)
- proxy.conf.json (Documentation)
🔄 In Progress
- StructureSyncService
- FolderHierarchyService
- DynamicPageComponent
- DocsBreadcrumbsComponent
- GlobalSearchComponent
- Build scripts
⏳ Pending
- Testing & validation
- Performance optimization
- Documentation updates
- Migration guide
🎓 Best Practices
For Developers
- Always use
DocsConfigService.effectiveDocsPath()for base paths - Never hardcode project names in URLs
- Use
AccessService.canAccessProject()before cross-project features - Test with multiple projects selected
For Users
- Select your primary project on first visit
- Use project switcher for changing projects
- Unlock private projects to maintain access
- Bookmark
/select-projectfor quick project changes
📚 Related Documentation
- Project Selection State (to be created)
- Access Control Rules (to be created)
- Migration Guide (to be created)
Last Updated: Implementation in progress Version: 1.0.0-alpha Status: Active Development