swiftops-backend / docs /dev /users /preferences_update_fix.md
kamau1's picture
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.