2:I[7012,["4765","static/chunks/4765-f5afdf8061f456f3.js","9856","static/chunks/9856-3b185291364d9bef.js","6687","static/chunks/app/docs/%5B...slug%5D/page-e07536548216bee4.js"],"MarkdownRenderer"] 4:I[9856,["4765","static/chunks/4765-f5afdf8061f456f3.js","9856","static/chunks/9856-3b185291364d9bef.js","6687","static/chunks/app/docs/%5B...slug%5D/page-e07536548216bee4.js"],""] 5:I[4126,[],""] 7:I[9630,[],""] 8:I[4278,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"HeadingProvider"] 9:I[1476,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"Header"] a:I[3167,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"Sidebar"] b:I[7409,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"PageFrame"] 3:T1c62, # Feature Flags Phase 4: User Overrides Implementation Plan ## Overview Phase 4 extends the feature flags system with per-user overrides, allowing administrators to: - Set specific flag values for individual users - Test new features with select beta users before broader rollout - Debug issues by forcing specific flag states for affected users - Implement personalized feature experiences ## Implementation Tasks ### 1. Database Schema #### New Table: `user_flag_overrides` ```sql CREATE TABLE user_flag_overrides ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, flag_name VARCHAR(255) NOT NULL, override_value JSONB NOT NULL, enabled BOOLEAN DEFAULT true, reason VARCHAR(500), created_by VARCHAR(255) NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), expires_at TIMESTAMP WITH TIME ZONE, UNIQUE(user_id, flag_name) ); CREATE INDEX idx_user_flag_overrides_user ON user_flag_overrides(user_id); CREATE INDEX idx_user_flag_overrides_flag ON user_flag_overrides(flag_name); CREATE INDEX idx_user_flag_overrides_expires ON user_flag_overrides(expires_at) WHERE expires_at IS NOT NULL; ``` ### 2. Backend API Endpoints | Endpoint | Method | Description | | ------------------------------------------------------- | ------ | --------------------------------------------------- | | `/api/admin/users/{user_id}/flag-overrides` | GET | List overrides for a user | | `/api/admin/users/{user_id}/flag-overrides` | POST | Create override for user | | `/api/admin/users/{user_id}/flag-overrides/{flag_name}` | GET | Get specific override | | `/api/admin/users/{user_id}/flag-overrides/{flag_name}` | PATCH | Update override | | `/api/admin/users/{user_id}/flag-overrides/{flag_name}` | DELETE | Remove override | | `/api/admin/feature-flags/{flag_name}/user-overrides` | GET | List all user overrides for a flag | | `/api/flags/me` | GET | Get current user's flag values (includes overrides) | ### 3. Service Layer Updates #### UserFlagOverrideService ```python class UserFlagOverrideService: async def get_user_overrides(self, user_id: str) -> Dict[str, Any] async def set_override(self, user_id: str, flag_name: str, value: Any, **kwargs) -> Override async def remove_override(self, user_id: str, flag_name: str) -> bool async def get_flag_value_for_user(self, flag_name: str, user_id: str) -> Any async def cleanup_expired_overrides(self) -> int ``` #### Flag Resolution Priority 1. User-specific override (if enabled and not expired) 2. User targeting rules (from Phase 2) 3. Scheduled variant changes (from Phase 3) 4. Default flag value ### 4. Admin UI Components #### UserOverridesPanel - List view of all users with overrides - Search/filter by user email or flag name - Bulk enable/disable overrides #### UserOverrideEditor - Select user (autocomplete search) - Select flag (dropdown with current value shown) - Set override value (type-aware input) - Optional expiration date - Reason field for audit #### Integration with Existing UI - Add "User Overrides" tab in Feature Flags page - Add override indicator on user management page - Show override count badge on flags with user overrides ### 5. SDK Client Methods ```typescript interface FlagClient { // Existing methods getFlag(flagName: string): FlagValue; // New methods for Phase 4 getUserFlags(): Record; hasOverride(flagName: string): boolean; getOverrideInfo(flagName: string): OverrideInfo | null; } ``` ### 6. RBAC Permissions | Action | Admin | Viewer | | ------------------- | ----- | ------ | | List user overrides | Yes | Yes | | Create override | Yes | No | | Update override | Yes | No | | Delete override | Yes | No | | View own overrides | Yes | Yes | ### 7. Monitoring & Metrics ```python # New Prometheus metrics user_flag_overrides_total = Counter( 'voiceassist_user_flag_overrides_total', 'Total user flag overrides', ['flag_name', 'action'] # action: created, updated, deleted ) user_flag_overrides_active = Gauge( 'voiceassist_user_flag_overrides_active', 'Currently active user overrides', ['flag_name'] ) ``` ### 8. Testing Plan #### Unit Tests - Override resolution priority - Expiration handling - Concurrent override updates - Invalid user/flag handling #### Integration Tests - RBAC enforcement (similar to scheduled changes tests) - Override persistence across sessions - Real-time propagation of override changes - Cleanup of expired overrides ### 9. Documentation Updates - Update Admin Guide with User Overrides section - Add API reference for new endpoints - Update SDK documentation - Add troubleshooting guide for override conflicts ## UI/UX Distinction: Scheduled Changes vs User Overrides | Aspect | Scheduled Changes | User Overrides | | -------- | ------------------------------------- | ---------------------------------- | | Scope | All users | Individual user | | Timing | Future date/time | Immediate (with optional expiry) | | Purpose | Gradual rollout | Testing/debugging | | Location | Feature Flags > Scheduled Changes tab | Feature Flags > User Overrides tab | | Icon | Calendar | User badge | ## Migration Path 1. Create database migration 2. Implement service layer 3. Add API endpoints with tests 4. Build admin UI components 5. Update SDK client 6. Update documentation ## Dependencies - Phase 2: Targeting rules (completed) - Phase 3: Real-time updates (completed) - User management system (existing) ## Estimated Effort | Component | Complexity | | --------------- | ---------- | | Database schema | Low | | Service layer | Medium | | API endpoints | Medium | | Admin UI | Medium | | SDK updates | Low | | Tests | Medium | | Documentation | Low | ## Success Criteria - [ ] User overrides can be created/updated/deleted via API - [ ] Admin UI provides intuitive override management - [ ] Override resolution follows correct priority - [ ] Expired overrides are automatically cleaned up - [ ] Real-time updates propagate override changes - [ ] All RBAC permissions enforced - [ ] 90%+ test coverage for new code ## Related Documentation - [Admin Panel Guide](../admin-guide/feature-flags/admin-panel-guide.md) - Feature flags admin UI documentation - [Scheduled Variant Changes](../admin-guide/feature-flags/admin-panel-guide.md#scheduled-variant-changes) - Phase 3 scheduled changes feature - [Phase 2: Targeting Rules](../UNIFIED_ARCHITECTURE.md) - Advanced flag types and user targeting 6:["slug","feature-flags/PHASE_4_USER_OVERRIDES_PLAN","c"] 0:["X7oMT3VrOffzp0qvbeOas",[[["",{"children":["docs",{"children":[["slug","feature-flags/PHASE_4_USER_OVERRIDES_PLAN","c"],{"children":["__PAGE__?{\"slug\":[\"feature-flags\",\"PHASE_4_USER_OVERRIDES_PLAN\"]}",{}]}]}]},"$undefined","$undefined",true],["",{"children":["docs",{"children":[["slug","feature-flags/PHASE_4_USER_OVERRIDES_PLAN","c"],{"children":["__PAGE__",{},[["$L1",["$","div",null,{"children":[["$","div",null,{"className":"mb-6 flex items-center justify-between gap-4","children":[["$","div",null,{"children":[["$","p",null,{"className":"text-sm text-gray-500 dark:text-gray-400","children":"Docs / Raw"}],["$","h1",null,{"className":"text-3xl font-bold text-gray-900 dark:text-white","children":"Feature Flags Phase 4 - User Overrides"}],["$","p",null,{"className":"text-sm text-gray-600 dark:text-gray-400","children":["Sourced from"," ",["$","code",null,{"className":"font-mono text-xs","children":["docs/","feature-flags/PHASE_4_USER_OVERRIDES_PLAN.md"]}]]}]]}],["$","a",null,{"href":"https://github.com/mohammednazmy/VoiceAssist/edit/main/docs/feature-flags/PHASE_4_USER_OVERRIDES_PLAN.md","target":"_blank","rel":"noreferrer","className":"inline-flex items-center gap-2 rounded-md border border-gray-200 dark:border-gray-700 px-3 py-1.5 text-sm text-gray-700 dark:text-gray-200 hover:border-primary-500 dark:hover:border-primary-400 hover:text-primary-700 dark:hover:text-primary-300","children":"Edit on GitHub"}]]}],["$","div",null,{"className":"rounded-lg border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-6","children":["$","$L2",null,{"content":"$3"}]}],["$","div",null,{"className":"mt-6 flex flex-wrap gap-2 text-sm","children":[["$","$L4",null,{"href":"/reference/all-docs","className":"inline-flex items-center gap-1 rounded-md bg-gray-100 px-3 py-1 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700","children":"← All documentation"}],["$","$L4",null,{"href":"/","className":"inline-flex items-center gap-1 rounded-md bg-gray-100 px-3 py-1 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700","children":"Home"}]]}]]}],null],null],null]},[null,["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children","docs","children","$6","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[null,["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children","docs","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/7f586cdbbaa33ff7.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","className":"h-full","children":["$","body",null,{"className":"__className_f367f3 h-full bg-white dark:bg-gray-900","children":[["$","a",null,{"href":"#main-content","className":"skip-to-content","children":"Skip to main content"}],["$","$L8",null,{"children":[["$","$L9",null,{}],["$","$La",null,{}],["$","main",null,{"id":"main-content","className":"lg:pl-64","role":"main","aria-label":"Documentation content","children":["$","$Lb",null,{"children":["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]]}]]}]}]],null],null],["$Lc",null]]]] c:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Feature Flags Phase 4 - User Overrides | Docs | VoiceAssist Docs"}],["$","meta","3",{"name":"description","content":"Implementation plan for user-specific feature flag overrides and admin UI enhancements"}],["$","meta","4",{"name":"keywords","content":"VoiceAssist,documentation,medical AI,voice assistant,healthcare,HIPAA,API"}],["$","meta","5",{"name":"robots","content":"index, follow"}],["$","meta","6",{"name":"googlebot","content":"index, follow"}],["$","link","7",{"rel":"canonical","href":"https://assistdocs.asimo.io"}],["$","meta","8",{"property":"og:title","content":"VoiceAssist Documentation"}],["$","meta","9",{"property":"og:description","content":"Comprehensive documentation for VoiceAssist - Enterprise Medical AI Assistant"}],["$","meta","10",{"property":"og:url","content":"https://assistdocs.asimo.io"}],["$","meta","11",{"property":"og:site_name","content":"VoiceAssist Docs"}],["$","meta","12",{"property":"og:type","content":"website"}],["$","meta","13",{"name":"twitter:card","content":"summary"}],["$","meta","14",{"name":"twitter:title","content":"VoiceAssist Documentation"}],["$","meta","15",{"name":"twitter:description","content":"Comprehensive documentation for VoiceAssist - Enterprise Medical AI Assistant"}],["$","meta","16",{"name":"next-size-adjust"}]] 1:null