swiftops-backend / docs /api /user-profile /USER_PREFERENCES_API.md
kamau1's picture
auth:better logging for rejected refresh tokens
4f3ae76
# User Preferences API Documentation
## Overview
The User Preferences API allows users to customize their experience in the SwiftOps platform, including favorite apps in the navigation bar, UI theme, language, notification settings, and dashboard layout.
**Key Features:**
- Role-based default preferences
- Maximum 6 favorite apps (database constraint)
- Automatic preference creation on first access
- Full CRUD operations with audit logging
- Context-aware app availability based on user role
---
## Table of Contents
1. [Authentication](#authentication)
2. [Endpoints](#endpoints)
3. [Data Models](#data-models)
4. [Role-Based Defaults](#role-based-defaults)
5. [Frontend Integration Guide](#frontend-integration-guide)
6. [Common Use Cases](#common-use-cases)
7. [Error Handling](#error-handling)
8. [Best Practices](#best-practices)
---
## Authentication
All endpoints require authentication via JWT token in the Authorization header:
```
Authorization: Bearer <access_token>
```
---
## Endpoints
### 1. Get Current User's Preferences
**Endpoint:** `GET /api/v1/auth/me/preferences`
**Description:** Retrieves the current user's preferences. If no preferences exist yet, they are automatically created with role-based defaults.
**Response:** Returns full preference object including:
- Favorite apps array (max 6 items)
- UI theme (light/dark/auto)
- Language preference
- Notification settings (email, push, SMS)
- Dashboard widget configuration
- Table/list preferences (view type, pagination, sorting)
- Map preferences (zoom level, center coordinates)
- Additional custom settings
**Use Cases:**
- Load user preferences on application startup
- Populate settings page
- Configure UI based on user theme preference
- Display favorite apps in navigation bar
---
### 2. Update User Preferences
**Endpoint:** `PUT /api/v1/auth/me/preferences`
**Description:** Updates one or more preference fields. Only send fields you want to update - all fields are optional.
**Request Body Fields:**
- `favorite_apps` - Array of app codes (max 6, validated against role)
- `theme` - One of: `light`, `dark`, `auto`
- `language` - Language code (e.g., `en`, `sw`)
- `email_notifications` - Boolean
- `push_notifications` - Boolean
- `sms_notifications` - Boolean
- `dashboard_widgets` - Array of widget codes
- `default_tickets_view` - One of: `list`, `kanban`, `calendar`
- `tickets_per_page` - Integer between 10-100
- `default_sort_field` - String (field name for default sorting)
- `default_sort_order` - One of: `asc`, `desc`
- `default_map_zoom` - Integer (map zoom level)
- `default_map_center_lat` - Float (latitude)
- `default_map_center_lng` - Float (longitude)
- `additional_settings` - Object (free-form custom settings)
**Validation Rules:**
- Maximum 6 favorite apps
- Favorite apps must be from the role's available apps list
- Theme must be one of the valid options
- Tickets per page must be between 10-100
**Response:** Returns updated preference object
**Use Cases:**
- Save settings from user preferences page
- Update theme when user toggles dark mode
- Reorder favorite apps in navigation
- Change language preference
- Toggle notification preferences
---
### 3. Get Available Apps for Role
**Endpoint:** `GET /api/v1/auth/me/preferences/available-apps`
**Description:** Returns the list of apps available for the user to favorite based on their role, along with current favorites and defaults.
**Response Fields:**
- `role` - User's current role
- `current_favorites` - Array of currently favorited app codes
- `available_apps` - Array of all apps user can choose from
- `default_favorites` - Array of role's default favorite apps
- `max_favorites` - Maximum number allowed (always 6)
**Use Cases:**
- Populate app picker in settings UI
- Show which apps can be added/removed
- Display role-appropriate app options
- Validate favorite apps client-side before submission
---
## Data Models
### UserPreferencesResponse
Full preference object returned by GET and PUT endpoints:
**Core Fields:**
- `id` - UUID of preference record
- `user_id` - UUID of user who owns these preferences
**App & Navigation:**
- `favorite_apps` - Array of app codes (e.g., `["dashboard", "users", "tickets"]`)
**UI Preferences:**
- `theme` - `"light"`, `"dark"`, or `"auto"`
- `language` - Language code (default: `"en"`)
**Notifications:**
- `email_notifications` - Boolean (default: `true`)
- `push_notifications` - Boolean (default: `true`)
- `sms_notifications` - Boolean (default: `false`)
**Dashboard:**
- `dashboard_widgets` - Array of widget codes (e.g., `["recent_tickets", "team_performance"]`)
**Table/List Preferences:**
- `default_tickets_view` - View type (default: `"list"`)
- `tickets_per_page` - Pagination size (default: `25`)
- `default_sort_field` - Default sort field (default: `"created_at"`)
- `default_sort_order` - Sort direction (default: `"desc"`)
**Map Preferences:**
- `default_map_zoom` - Zoom level (default: `12`)
- `default_map_center_lat` - Latitude (nullable)
- `default_map_center_lng` - Longitude (nullable)
**Flexible Storage:**
- `additional_settings` - Object for custom settings
---
## Role-Based Defaults
Each role gets context-appropriate default preferences:
### Platform Admin
**Favorite Apps:** `dashboard`, `organizations`, `users`, `activity`
**Available Apps:** Core apps (dashboard, organizations, users, activity) + Management apps (settings, billing, notifications, help)
**Dashboard Widgets:** Recent tickets, team performance, SLA metrics, organizations overview
### Client Admin
**Favorite Apps:** `dashboard`, `projects`, `tickets`, `team`
**Available Apps:** Dashboard, projects, tickets, team, sales orders, customers, contractors, reports, settings, help
**Dashboard Widgets:** Recent tickets, team performance, SLA metrics, project status
### Contractor Admin
**Favorite Apps:** `dashboard`, `projects`, `tickets`, `team`
**Available Apps:** Dashboard, projects, tickets, team, timesheets, payroll, reports, settings, help
**Dashboard Widgets:** Recent tickets, team performance, payroll summary, project status
### Sales Manager
**Favorite Apps:** `dashboard`, `sales_orders`, `customers`, `reports`
**Available Apps:** Dashboard, sales orders, customers, reports, team, maps, settings, help
**Dashboard Widgets:** Sales pipeline, revenue metrics, team performance, conversion rates
### Project Manager
**Favorite Apps:** `dashboard`, `projects`, `tickets`, `team`
**Available Apps:** Dashboard, projects, tickets, team, reports, maps, settings, help
**Dashboard Widgets:** Project status, team performance, SLA metrics, map view
### Dispatcher
**Favorite Apps:** `dashboard`, `tickets`, `maps`, `team`
**Available Apps:** Dashboard, tickets, maps, team, projects, reports, settings, help
**Dashboard Widgets:** Recent tickets, map view, team availability, SLA metrics
### Field Agent
**Favorite Apps:** `tickets`, `maps`, `timesheets`, `profile`
**Available Apps:** Tickets, maps, timesheets, profile, expenses, documents, help
**Dashboard Widgets:** My tickets, earnings summary, attendance summary
### Sales Agent
**Favorite Apps:** `dashboard`, `sales_orders`, `customers`, `maps`
**Available Apps:** Dashboard, sales orders, customers, maps, profile, reports, help
**Dashboard Widgets:** My sales, customer pipeline, earnings summary
---
## Frontend Integration Guide
### Application Startup Flow
1. **After successful login**, fetch user preferences:
- Call `GET /api/v1/auth/me/preferences`
- Store preferences in global state (Redux, Vuex, Context, etc.)
- If preferences don't exist, backend automatically creates them with role defaults
2. **Apply preferences to UI:**
- Set theme based on `theme` field (light/dark/auto)
- Configure language/i18n based on `language` field
- Render favorite apps in top navigation bar
- Configure dashboard widgets
- Set default table views and pagination sizes
3. **Cache preferences locally:**
- Store in localStorage/sessionStorage for quick access
- Sync with backend on changes
- Handle offline scenarios gracefully
### Settings Page Implementation
**Favorite Apps Section:**
- Display current favorite apps with drag-to-reorder functionality
- Show "Add App" button that opens modal with available apps
- Validate max 6 apps client-side
- Allow removal of favorites
- Show role-appropriate apps only (fetch from `/available-apps` endpoint)
**Theme Selector:**
- Radio buttons or dropdown for Light/Dark/Auto
- Apply theme immediately on change (optimistic UI)
- Save to backend in background
**Notification Preferences:**
- Toggle switches for each notification type
- Group by delivery method (Email, Push, SMS)
- Show current state from backend
- Update backend on toggle
**Dashboard Customization:**
- Widget picker showing available widgets for role
- Drag-and-drop to reorder widgets
- Toggle widget visibility
- Save layout to `dashboard_widgets` field
**Table Preferences:**
- Dropdown for default view (List/Kanban/Calendar)
- Number input for pagination size (10-100)
- Dropdowns for sort field and order
### Navigation Bar Integration
**Rendering Favorite Apps:**
- Fetch `favorite_apps` array from preferences
- Map app codes to app metadata (icons, names, routes)
- Render in top navigation or app drawer
- Maintain order from array
- Show all available apps in "All Apps" menu or 9-dot launcher
**App Code to Route Mapping:**
```
dashboard -> /dashboard
organizations -> /organizations
users -> /users
tickets -> /tickets
projects -> /projects
sales_orders -> /sales-orders
customers -> /customers
maps -> /map
team -> /team
reports -> /reports
timesheets -> /timesheets
payroll -> /payroll
profile -> /profile
expenses -> /expenses
documents -> /documents
settings -> /settings
billing -> /billing
notifications -> /notifications
help -> /help
```
### Theme Management
**Auto Theme Implementation:**
- When `theme: "auto"`, detect system preference
- Listen for system theme changes
- Update UI dynamically without backend call
- Only `light` and `dark` are stored in backend, `auto` uses system detection
**Theme Application:**
- Set CSS variables or toggle theme classes
- Persist across page refreshes
- Apply before first paint to avoid flash
### Optimistic Updates
For better UX, update UI immediately before backend confirmation:
1. User changes preference in UI
2. Update local state/UI immediately
3. Call PUT endpoint in background
4. On success: Keep UI as is
5. On error: Revert UI to previous state and show error message
---
## Common Use Cases
### Use Case 1: Customizing Favorite Apps
**User Story:** As a platform admin, I want to add "Billing" to my favorite apps.
**Implementation Steps:**
1. User opens Settings → Favorite Apps
2. Frontend calls `GET /api/v1/auth/me/preferences/available-apps` to get available apps
3. Display current favorites (4 apps) and available apps (8 apps)
4. User clicks "Add App" → Modal shows available apps not already favorited
5. User selects "billing" → Add to favorites array
6. Frontend calls `PUT /api/v1/auth/me/preferences` with `{"favorite_apps": ["dashboard", "organizations", "users", "activity", "billing"]}`
7. Backend validates (max 6, role-appropriate) and saves
8. Frontend updates navigation bar with new favorite
### Use Case 2: Toggling Dark Mode
**User Story:** As a user, I want to switch to dark mode.
**Implementation Steps:**
1. User clicks theme toggle in header/settings
2. Frontend immediately applies dark theme to UI (optimistic update)
3. Frontend calls `PUT /api/v1/auth/me/preferences` with `{"theme": "dark"}`
4. Backend saves preference
5. On next login, dark theme is automatically applied
### Use Case 3: Reordering Favorite Apps
**User Story:** As a dispatcher, I want "maps" to be my first favorite app.
**Implementation Steps:**
1. User drags "maps" to first position in favorites list
2. Frontend updates array order: `["maps", "dashboard", "tickets", "team"]`
3. UI updates immediately (optimistic)
4. Frontend calls `PUT /api/v1/auth/me/preferences` with new array
5. Backend saves new order
6. Navigation bar reflects new order
### Use Case 4: Setting Default Map Center
**User Story:** As a field agent, I want the map to always center on my region.
**Implementation Steps:**
1. User navigates map to preferred location
2. User clicks "Set as default center" button
3. Frontend captures current map center coordinates
4. Frontend calls `PUT /api/v1/auth/me/preferences` with `{"default_map_center_lat": -1.2921, "default_map_center_lng": 36.8219, "default_map_zoom": 13}`
5. Backend saves preferences
6. On next map load, map centers at saved coordinates with saved zoom level
### Use Case 5: Customizing Dashboard
**User Story:** As a sales manager, I want to see "Conversion Rates" widget on my dashboard.
**Implementation Steps:**
1. User opens Dashboard Settings
2. Frontend shows available widgets for sales_manager role
3. User toggles "conversion_rates" widget on
4. Frontend updates `dashboard_widgets` array
5. Frontend calls `PUT /api/v1/auth/me/preferences` with updated widget list
6. Dashboard re-renders with new widget
---
## Error Handling
### Common Errors
**400 Bad Request - Invalid App for Role:**
```json
{
"detail": "Invalid apps for dispatcher: billing, organizations. Available apps: dashboard, tickets, maps, team, projects, reports, settings, help"
}
```
**Action:** Show user which apps are invalid and provide picker with valid apps only.
**400 Bad Request - Too Many Favorites:**
```json
{
"detail": "Maximum 6 favorite apps allowed"
}
```
**Action:** Disable "Add" button when 6 apps are already favorited, show count (e.g., "5/6 favorites").
**400 Bad Request - Invalid Theme:**
```json
{
"detail": "Theme must be one of: light, dark, auto"
}
```
**Action:** Use dropdown/radio buttons to prevent invalid values client-side.
**401 Unauthorized:**
```json
{
"detail": "Could not validate credentials"
}
```
**Action:** Token expired or invalid - redirect to login page.
### Error Handling Strategy
1. **Validate client-side first** - Prevent invalid requests before sending
2. **Show specific error messages** - Extract `detail` field from error response
3. **Revert optimistic updates** - Roll back UI changes if API call fails
4. **Retry on network errors** - Implement exponential backoff for transient failures
5. **Log errors** - Track preference update failures for debugging
---
## Best Practices
### Performance
1. **Cache preferences locally** - Fetch once on login, update on changes
2. **Debounce rapid updates** - If user changes multiple settings quickly, batch into single API call
3. **Use optimistic updates** - Update UI immediately, sync with backend asynchronously
4. **Lazy load available apps** - Only fetch when user opens app picker modal
### User Experience
1. **Show loading states** - Display skeleton or spinner during fetch
2. **Provide immediate feedback** - Visual confirmation when settings save
3. **Persist across sessions** - Store preferences in localStorage as backup
4. **Handle offline gracefully** - Queue preference updates if offline, sync when online
5. **Validate before submission** - Check constraints client-side (max 6 apps, valid values)
### Security
1. **Never cache sensitive data** - Clear preferences on logout
2. **Validate all inputs** - Don't trust client-side validation alone
3. **Use HTTPS** - Ensure all API calls are over secure connection
4. **Handle token expiration** - Refresh token or redirect to login gracefully
### Accessibility
1. **Keyboard navigation** - Allow keyboard control of app picker and settings
2. **Screen reader support** - Announce preference changes
3. **High contrast mode** - Respect system high contrast preferences
4. **Focus management** - Return focus appropriately after modal closes
### State Management
1. **Single source of truth** - Store preferences in global state manager
2. **Sync with backend** - Keep local state in sync with server
3. **Handle race conditions** - Use timestamps or version numbers to resolve conflicts
4. **Broadcast changes** - Notify all components when preferences update
---
## Example Implementation Flows
### Complete Settings Page Flow
**Initial Load:**
1. Component mounts → Check if preferences in state
2. If not in state → Call `GET /api/v1/auth/me/preferences`
3. Store in state and render current preferences
4. Enable editing
**User Makes Change:**
1. User modifies setting (e.g., toggles notification)
2. Update local state immediately (optimistic)
3. Debounce API call (500ms wait for more changes)
4. Call `PUT /api/v1/auth/me/preferences` with changed fields only
5. On success: Keep optimistic update
6. On error: Revert to previous value, show error toast
**Adding Favorite App:**
1. User clicks "Add Favorite App" button
2. If favorites.length === 6 → Show "Maximum reached" message
3. Else → Call `GET /api/v1/auth/me/preferences/available-apps`
4. Filter out already favorited apps
5. Show modal with available apps
6. User selects app → Add to favorites array
7. Update UI immediately
8. Call `PUT` endpoint with new array
9. On success: Close modal
10. On error: Remove app from array, show error
### Theme Toggle Implementation
**Toggle Component:**
1. Read current theme from preferences state
2. Render toggle switch (Light/Dark) or three-way selector (Light/Dark/Auto)
3. On click:
- Update UI theme immediately
- Call `PUT /api/v1/auth/me/preferences` with `{"theme": newTheme}`
- Show loading indicator on toggle
- On success: Remove loading indicator
- On error: Revert theme, show error
**Auto Theme Handling:**
1. If theme is "auto", detect system preference:
```javascript
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
```
2. Apply system theme to UI
3. Listen for changes:
```javascript
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
if (preferences.theme === 'auto') {
applyTheme(e.matches ? 'dark' : 'light')
}
})
```
---
## Testing Recommendations
### Unit Tests
- Test preference state management (Redux/Vuex actions)
- Test validation logic (max 6 apps, valid values)
- Test app code to route mapping
- Test theme application logic
### Integration Tests
- Test full settings page flow (fetch → edit → save)
- Test favorite app picker flow
- Test theme toggle with API calls
- Test error handling and rollback
### E2E Tests
- Test complete user journey: Login → Change preferences → Logout → Login (preferences persisted)
- Test preference changes reflect across multiple tabs
- Test offline handling and sync on reconnect
---
## Migration Guide
If your app currently stores preferences differently:
1. **Phase 1: Dual Read** - Read from old storage, fallback to new API
2. **Phase 2: Migrate Data** - Background job to copy old preferences to new system
3. **Phase 3: Dual Write** - Write to both old and new storage
4. **Phase 4: Cut Over** - Stop reading from old storage, read from API only
5. **Phase 5: Cleanup** - Remove old preference storage code
---
## Support & Troubleshooting
### Common Issues
**Issue:** Preferences not saving
**Solution:** Check network tab for API errors, verify authentication token is valid
**Issue:** Default preferences not created
**Solution:** Preferences are auto-created on first GET request, ensure user is authenticated
**Issue:** Theme not applying
**Solution:** Ensure theme CSS classes/variables are correctly wired to preference value
**Issue:** Favorite apps showing wrong apps for role
**Solution:** Fetch available apps from API, don't hardcode app lists in frontend
### Debug Checklist
- [ ] User is authenticated (valid token)
- [ ] API endpoint returns 200 status
- [ ] Response data structure matches expected format
- [ ] Preferences are stored in state manager
- [ ] UI components read from state correctly
- [ ] Optimistic updates revert on error
- [ ] Error messages are displayed to user
---
## API Versioning
Current Version: **v1**
All endpoints are under `/api/v1/auth/me/preferences`
Breaking changes will be introduced in new API versions (v2, v3, etc.) with deprecation notices.
---
## Changelog
**Version 1.0** (Current)
- Initial release
- Support for favorite apps, theme, notifications, dashboard widgets
- Role-based defaults and validation
- Maximum 6 favorite apps constraint
---
## Additional Resources
- **User Management API:** See general user profile endpoints
- **Authentication API:** Token management and session handling
- **Role Definitions:** Complete list of roles and permissions
---
**Last Updated:** November 18, 2025
**Maintained By:** SwiftOps Backend Team