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:

{
  "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.