# COMP-004: Organization Components Repository ## Overview Enable teams to share a central component repository at the organization level. When a user belongs to a GitHub organization, they can access shared components from that org's component repository, creating a design system that's consistent across all team projects. ## Context Individual developers can export components to personal repos (COMP-003), but teams need: - Shared component library accessible to all org members - Consistent design system across projects - Centralized component governance - Version control for team components This task adds organization-level component repositories to the prefab source system. ### Organization Flow ``` User authenticates with GitHub (GIT-001) ↓ System detects user's organizations ↓ For each org, check for `noodl-components` repo ↓ Register as prefab source if found ↓ Components appear in NodePicker ``` ## Requirements ### Functional Requirements 1. **Organization Detection** - Detect user's GitHub organizations - Check for component repository in each org - Support custom repo names (configurable) - Handle multiple organizations 2. **Repository Discovery** - Auto-detect `{org}/noodl-components` repos - Validate repository structure - Read repository manifest - Cache organization components 3. **Component Access** - List org components in NodePicker - Show org badge on components - Filter by organization - Search across all org repos 4. **Permission Handling** - Respect GitHub permissions - Handle private repositories - Clear error messages for access issues - Re-auth prompt when needed 5. **Organization Settings** - Enable/disable specific org repos - Priority ordering between orgs - Refresh/sync controls - View org repo on GitHub ### Non-Functional Requirements - Org components load within 3 seconds - Cached for offline use after first load - Handles orgs with 100+ components - Works with GitHub Enterprise (future) ## Technical Approach ### 1. Organization Prefab Source ```typescript // packages/noodl-editor/src/editor/src/models/prefab/sources/OrganizationPrefabSource.ts interface OrganizationConfig { orgName: string; repoName: string; enabled: boolean; priority: number; } class OrganizationPrefabSource implements PrefabSource { config: PrefabSourceConfig; constructor(private orgConfig: OrganizationConfig) { this.config = { id: `org:${orgConfig.orgName}`, name: orgConfig.orgName, priority: orgConfig.priority, enabled: orgConfig.enabled }; } async initialize(): Promise { // Verify repo access const hasAccess = await this.verifyRepoAccess(); if (!hasAccess) { throw new PrefabSourceError('No access to organization repository'); } // Load manifest await this.loadManifest(); } async listPrefabs(): Promise { const manifest = await this.getManifest(); return manifest.components.map(c => ({ ...c, id: `org:${this.orgConfig.orgName}:${c.id}`, source: 'organization', organization: this.orgConfig.orgName })); } async downloadPrefab(id: string): Promise { // Clone specific component from repo const componentPath = this.getComponentPath(id); return await this.downloadFromGitHub(componentPath); } } ``` ### 2. Organization Discovery Service ```typescript // packages/noodl-editor/src/editor/src/services/OrganizationService.ts interface Organization { name: string; displayName: string; avatarUrl: string; hasComponentRepo: boolean; componentRepoUrl?: string; memberCount?: number; } class OrganizationService { private static instance: OrganizationService; // Discovery async discoverOrganizations(): Promise; async checkForComponentRepo(orgName: string): Promise; async validateComponentRepo(orgName: string, repoName: string): Promise; // Registration async registerOrgSource(org: Organization): Promise; async unregisterOrgSource(orgName: string): Promise; // Settings getOrgSettings(orgName: string): OrganizationConfig; updateOrgSettings(orgName: string, settings: Partial): void; // Refresh async refreshOrgComponents(orgName: string): Promise; async refreshAllOrgs(): Promise; } ``` ### 3. Auto-Registration on Login ```typescript // Integration with GitHub OAuth async function onGitHubAuthenticated(token: string): Promise { const orgService = OrganizationService.instance; const registry = PrefabRegistry.instance; // Discover user's organizations const orgs = await orgService.discoverOrganizations(); for (const org of orgs) { // Check for component repo const hasRepo = await orgService.checkForComponentRepo(org.name); if (hasRepo) { // Register as prefab source const source = new OrganizationPrefabSource({ orgName: org.name, repoName: 'noodl-components', enabled: true, priority: 80 // Below built-in, above docs }); registry.registerSource(source); } } } ``` ### 4. Organization Settings UI ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Organization Components │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ Connected Organizations │ │ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ [🏢] Acme Corp │ │ │ │ noodl-components • 24 components • Last synced: 2h ago │ │ │ │ [☑ Enabled] [⚙️ Settings] [🔄 Sync] [↗️ View on GitHub] │ │ │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ [🏢] StartupXYZ │ │ │ │ noodl-components • 8 components • Last synced: 1d ago │ │ │ │ [☑ Enabled] [⚙️ Settings] [🔄 Sync] [↗️ View on GitHub] │ │ │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ [🏢] OpenSource Collective │ │ │ │ ⚠️ No component repository found │ │ │ │ [Create Repository] │ │ │ └─────────────────────────────────────────────────────────────────┘ │ │ │ │ [🔄 Refresh Organizations] │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 5. NodePicker Integration ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Prefabs │ ├─────────────────────────────────────────────────────────────────────┤ │ 🔍 Search prefabs... │ ├─────────────────────────────────────────────────────────────────────┤ │ Source: [All Sources ▾] Category: [All ▾] │ │ • All Sources │ │ • Built-in │ │ • Acme Corp │ │ • StartupXYZ │ │ • Community │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ACME CORP │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ 🏢 AcmeButton v2.1.0 [Clone] │ │ │ │ Standard button following Acme design system │ │ │ ├────────────────────────────────────────────────────────────────┤ │ │ │ 🏢 AcmeCard v1.3.0 [Clone] │ │ │ │ Card component with Acme styling │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ │ │ BUILT-IN │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ 📦 Form Input v1.0.0 [Clone] │ │ │ │ Standard form input with validation │ │ │ └────────────────────────────────────────────────────────────────┘ │ ``` ## Files to Create 1. `packages/noodl-editor/src/editor/src/models/prefab/sources/OrganizationPrefabSource.ts` 2. `packages/noodl-editor/src/editor/src/services/OrganizationService.ts` 3. `packages/noodl-core-ui/src/components/settings/OrganizationSettings/OrganizationSettings.tsx` 4. `packages/noodl-core-ui/src/components/settings/OrganizationSettings/OrgCard.tsx` 5. `packages/noodl-core-ui/src/preview/launcher/Launcher/views/OrganizationsView.tsx` ## Files to Modify 1. `packages/noodl-editor/src/editor/src/services/GitHubOAuthService.ts` - Trigger org discovery on auth 2. `packages/noodl-editor/src/editor/src/models/prefab/PrefabRegistry.ts` - Handle org sources dynamically - Add source filtering 3. `packages/noodl-editor/src/editor/src/views/NodePicker/tabs/NodePickerSearchView/NodePickerSearchView.tsx` - Add source filter dropdown - Show org badges 4. `packages/noodl-editor/src/editor/src/views/NodePicker/components/ModuleCard/ModuleCard.tsx` - Show organization name - Different styling for org components 5. `packages/noodl-core-ui/src/preview/launcher/Launcher/Launcher.tsx` - Add Organizations section/page ## Implementation Steps ### Phase 1: Organization Discovery 1. Create OrganizationService 2. Implement GitHub org listing 3. Check for component repos 4. Store org data ### Phase 2: Organization Source 1. Create OrganizationPrefabSource 2. Implement manifest loading 3. Implement component downloading 4. Add to PrefabRegistry ### Phase 3: Auto-Registration 1. Hook into OAuth flow 2. Auto-register on login 3. Handle permission changes 4. Persist org settings ### Phase 4: Settings UI 1. Create OrganizationSettings component 2. Create OrgCard component 3. Add to Settings panel 4. Implement enable/disable ### Phase 5: NodePicker Integration 1. Add source filter 2. Show org grouping 3. Add org badges 4. Update search ### Phase 6: Polish 1. Sync/refresh functionality 2. Error handling 3. Offline support 4. Performance optimization ## Testing Checklist - [ ] Organizations discovered on login - [ ] Component repos detected - [ ] Source registered for orgs with repos - [ ] Components appear in NodePicker - [ ] Source filter works - [ ] Org badge displays - [ ] Enable/disable works - [ ] Sync refreshes components - [ ] Private repos accessible - [ ] Permission errors handled - [ ] Works with multiple orgs - [ ] Caching works offline - [ ] Settings persist ## Dependencies - COMP-001 (Prefab System Refactoring) - COMP-003 (Component Export) - for repository structure - GIT-001 (GitHub OAuth) - for organization access ## Blocked By - COMP-001 - GIT-001 ## Blocks - COMP-005 (depends on org repos existing) - COMP-006 (depends on org repos existing) ## Estimated Effort - Organization discovery: 3-4 hours - OrganizationPrefabSource: 4-5 hours - Auto-registration: 2-3 hours - Settings UI: 3-4 hours - NodePicker integration: 3-4 hours - Polish & testing: 3-4 hours - **Total: 18-24 hours** ## Success Criteria 1. Orgs auto-detected on GitHub login 2. Component repos discovered automatically 3. Org components appear in NodePicker 4. Can filter by organization 5. Settings allow enable/disable 6. Works with private repositories 7. Clear error messages for access issues ## Repository Setup Guide (For Users) To create an organization component repository: 1. Create repo named `noodl-components` in your org 2. Add `index.json` manifest file: ```json { "name": "Acme Components", "version": "1.0.0", "components": [] } ``` 3. Export components using COMP-003 4. Noodl will auto-detect the repository ## Future Enhancements - GitHub Enterprise support - Repository templates - Permission levels (read/write per component) - Component approval workflow - Usage analytics per org - Component deprecation notices - Multi-repo per org support