Spaces:
Sleeping
Sleeping
Add unified partner discovery endpoint for project creation - Implemented /api/v1/organizations/partners for easy contractor/client discovery - Returns ALL contractors to client admins, ALL clients to contractor admins - Includes project stats (active/total counts) for informed partner selection - Open marketplace model: no invitations needed, instant project creation - Supports search, filtering by industry/active status, pagination - Added comprehensive PROJECT_CREATION_FLOW.md documentation
e63c22c
| # User Preferences Update Bug - Root Cause & Fix | |
| ## Issue Summary | |
| User preferences updates (theme, favorite_apps) were not being saved to the database despite the API returning 200 OK responses. | |
| ## Root Cause | |
| ### Duplicate Route Definitions | |
| The `auth.py` file had **TWO different endpoints** with the **same route path**: | |
| 1. **OLD Endpoint (Line 847)** - `PUT /me/preferences` | |
| - Function: `update_user_preferences()` | |
| - Input: Generic `dict` | |
| - Output: `UserProfile` (no preference fields) | |
| - **Only handled**: `last_active_project_id` | |
| - **Ignored**: `theme`, `favorite_apps`, and all other preference fields | |
| 2. **NEW Endpoint (Line 1242)** - `PUT /me/preferences` | |
| - Function: `update_my_preferences()` | |
| - Input: `UserPreferencesUpdate` schema | |
| - Output: `UserPreferencesResponse` (includes all preference fields) | |
| - **Handles**: `favorite_apps`, `theme`, `language`, notifications, etc. | |
| ### Why It Failed | |
| When FastAPI registers routes, **only the first matching route is registered**. The old endpoint (line 847) was being called for all `/me/preferences` PUT requests, which: | |
| - Accepted the request body as a dict | |
| - Only looked for `last_active_project_id` | |
| - **Silently ignored** `theme`, `favorite_apps`, and other fields | |
| - Returned `UserProfile` without preference data | |
| - This is why the browser console showed: `favoriteAppsCount: 0, favoriteAppsJson: undefined` | |
| ## Evidence from Logs | |
| ### Browser Console (browserconsole.txt) | |
| ``` | |
| Line 48: [DATA] Updating user preferences {theme: 'light', favoriteAppsJson: undefined} | |
| Line 49: PUT https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences | |
| Line 50: PUT .../api/v1/auth/me/preferences β 200 (625ms) | |
| Line 51: [DATA] User preferences updated successfully {updatedFields: Array(1), theme: undefined, favoriteAppsCount: 0, favoriteAppsJson: undefined} | |
| ``` | |
| The request succeeded (200 OK) but the response didn't contain the updated data. | |
| ### Server Logs (runtimeerror.txt) | |
| ``` | |
| Line 35: PUT /api/v1/auth/me/preferences HTTP/1.1" 200 OK | |
| Line 181: PUT /api/v1/auth/me/preferences HTTP/1.1" 200 OK | |
| Line 260: PUT /api/v1/auth/me/preferences HTTP/1.1" 200 OK | |
| Line 264: PUT /api/v1/auth/me/preferences HTTP/1.1" 200 OK | |
| ``` | |
| Multiple successful requests, but the old endpoint was being called. | |
| ## The Fix | |
| ### Changes Made | |
| **1. Added `last_active_project_id` to `UserPreferencesUpdate` schema** | |
| - File: `src/app/schemas/user_preferences.py` | |
| - Added the field so the preferences endpoint can handle project context updates | |
| **2. Enhanced the preferences endpoint with project validation** | |
| - File: `src/app/api/v1/auth.py` (line 1242+) | |
| - Added validation logic for `last_active_project_id`: | |
| - Prevents platform admins from setting project context | |
| - Verifies user is assigned to the project | |
| - Verifies project exists and is active | |
| - Updated field exclusion list to skip validated fields | |
| **3. Removed the old duplicate endpoint entirely** | |
| - File: `src/app/api/v1/auth.py` (previously line 847-1020) | |
| - **Deleted** the old `PUT /me/active-project` endpoint | |
| - No longer needed since the new endpoint handles everything | |
| ### Result: Single Unified Endpoint | |
| Now there is **ONE endpoint** that handles **ALL** user preference updates: | |
| **`PUT /api/v1/auth/me/preferences`** | |
| - Input: `UserPreferencesUpdate` schema | |
| - Output: `UserPreferencesResponse` | |
| - Handles: | |
| - β `favorite_apps` - Array of app codes (max 6, role-validated) | |
| - β `theme` - 'light', 'dark', or 'auto' | |
| - β `language` - Language code | |
| - β `last_active_project_id` - Project context (validated) | |
| - β `email_notifications` - Boolean | |
| - β `push_notifications` - Boolean | |
| - β `sms_notifications` - Boolean | |
| - β `dashboard_widgets` - Array of widget codes | |
| - β `default_tickets_view` - 'list', 'kanban', or 'calendar' | |
| - β All other preference fields | |
| ### Response Format | |
| The endpoint now returns `UserPreferencesResponse` which includes: | |
| ```json | |
| { | |
| "id": "uuid", | |
| "user_id": "uuid", | |
| "favorite_apps": ["dashboard", "organizations", "users", "activity"], | |
| "theme": "light", | |
| "language": "en", | |
| "email_notifications": true, | |
| "last_active_project_id": "uuid", | |
| ... | |
| } | |
| ``` | |
| ## Testing Required | |
| 1. **Restart the backend server** to load the updated route | |
| 2. **Test theme updates**: | |
| - Toggle theme from dark to light | |
| - Verify database `user_preferences.theme` column updates | |
| - Verify API response contains updated theme | |
| 3. **Test favorite apps updates**: | |
| - Add/remove favorite apps | |
| - Verify database `user_preferences.favorite_apps` column updates | |
| - Verify API response contains updated favorite_apps array | |
| 4. **Test project context updates**: | |
| - Switch active project | |
| - Verify database `user_preferences.last_active_project_id` column updates | |
| - Verify API response contains updated project ID | |
| ## Migration Notes | |
| ### Breaking Changes | |
| - **Removed**: `PUT /me/active-project` endpoint (was never in production) | |
| - **Use instead**: `PUT /me/preferences` for all preference updates | |
| ### Unified Endpoint | |
| - **Route**: `PUT /api/v1/auth/me/preferences` | |
| - **Purpose**: Update all user preferences in one place | |
| - **Supports**: All preference fields including `last_active_project_id` | |
| ## Database Schema | |
| The fix doesn't require any database changes. The `user_preferences` table already has all the necessary columns: | |
| - `favorite_apps` (JSONB array) | |
| - `theme` (VARCHAR) | |
| - `language` (VARCHAR) | |
| - `email_notifications` (BOOLEAN) | |
| - etc. | |
| The issue was purely in the routing layer. | |