swiftops-backend / docs /api /user-profile /APP_ACCESS_UPDATE_SUMMARY.md
kamau1's picture
feat: app management roles for who can view what app
9a2466b

App Access Model Update - Summary

Overview

Updated the app management system to reflect real-world business scenarios where users wear multiple hats and need broad VIEW access with controlled ACTION permissions.

Date: November 18, 2025
Updated Files:

  • src/app/config/apps.py
  • docs/api/user-profile/APP_MANAGEMENT_SYSTEM.md

Philosophy Change

Before: Restrictive Access

  • Roles had limited app access
  • Field agents couldn't see payroll
  • Dispatchers had narrow view
  • Sales managers isolated from operations

After: Broad Views, Restricted Actions

  • Most roles see most apps (VIEW access)
  • Actions controlled via RBAC (create/edit/delete permissions)
  • Real-world flexibility (admins can wear multiple hats)
  • Casual workers track earnings (field/sales agents see payroll)

New Apps Added (4)

  1. Incidents - Incident tracking and resolution

    • Category: Operations
    • Icon: alert-triangle
    • Route: /incidents
  2. Tasks - Task management and assignment

    • Category: Operations
    • Icon: check-square
    • Route: /tasks
  3. Subscriptions - Recurring revenue management

    • Category: Finance
    • Icon: refresh-cw
    • Route: /subscriptions
    • Requires: view_subscriptions permission
  4. Inventory - Asset management

    • Category: Operations
    • Icon: package
    • Route: /inventory
    • Requires: view_inventory permission

Total Apps: 26 (was 22)


Role Access Changes

Platform Admin

  • Before: 8 apps
  • After: 26 apps (ALL)
  • Reason: System administrators need full visibility

Client Admin

  • Before: 10 apps
  • After: 23 apps
  • Added: Organizations, incidents, tasks, maps, timesheets, payroll, expenses, documents, inventory, subscriptions, billing, notifications
  • Reason: Can work as PM/dispatcher, needs full business visibility

Contractor Admin

  • Before: 9 apps
  • After: 23 apps
  • Added: Organizations, incidents, tasks, sales_orders, customers, maps, expenses, documents, inventory, subscriptions, billing, notifications, contractors
  • Reason: Can work as PM/dispatcher, needs operational visibility

Sales Manager

  • Before: 8 apps
  • After: 24 apps
  • Added: Projects, tickets, incidents, tasks, timesheets, payroll, expenses, contractors, documents, inventory, subscriptions, billing, notifications
  • Reason: Needs finance & operations visibility for fulfillment pipeline

Project Manager

  • Before: 8 apps
  • After: 25 apps
  • Added: Organizations, incidents, tasks, sales_orders, customers, contractors, timesheets, payroll, expenses, documents, inventory, subscriptions, billing, notifications
  • Reason: Needs full visibility for project coordination

Dispatcher

  • Before: 8 apps
  • After: 20 apps
  • Added: Incidents, tasks, sales_orders, customers, contractors, timesheets, expenses, documents, inventory, subscriptions
  • Reason: Sees what PM sees, different action permissions

Field Agent (Casual Worker)

  • Before: 7 apps (no payroll)
  • After: 14 apps
  • Added: Dashboard, incidents, tasks, payroll, customers, notifications
  • Reason: Track daily earnings from errands, see customer info for field visits

Sales Agent (Casual Worker)

  • Before: 7 apps (no payroll)
  • After: 15 apps
  • Added: Tickets, tasks, payroll, expenses, documents, notifications
  • Reason: Track sales commissions, follow up on customer issues

Why Casual Workers Need Payroll

Problem

Field agents and sales agents are typically casual/gig workers who:

  • Get paid per completed task (field agent: "How much did I earn today?")
  • Earn commission on sales (sales agent: "What's my commission this week?")
  • Want transparency on their compensation
  • Need to verify payments

Solution

Give VIEW-only access to payroll app with:

  • Row-level security: Workers only see their own payroll records
  • No action permissions: Can't modify payroll data
  • Real-time visibility: Track daily/weekly earnings
  • Transparent compensation: Build trust with workers

Implementation

# Backend query with row-level filtering
if user.role in ['field_agent', 'sales_agent']:
    payroll = Payroll.query.filter(Payroll.user_id == user.id)
else:
    payroll = Payroll.query  # Admins see all

Multi-Role Reality

Use Case: Small Business Client Admin

Scenario: John is a client admin at a small company. He also:

  • Coordinates projects (PM role)
  • Dispatches field agents (dispatcher role)
  • Approves timesheets (HR role)
  • Reviews sales reports (sales manager role)

Solution:

  • John sees ALL 23 apps (broad VIEW access)
  • Different permissions for different actions:
    • βœ… Can create projects (has can_create_project)
    • βœ… Can dispatch agents (has can_assign_tickets)
    • ❌ Cannot approve payroll (lacks can_approve_payroll)
    • βœ… Can view sales reports (has can_view_sales)

UI Behavior:

  • Navigation shows all accessible apps
  • Action buttons appear/disappear based on permissions
  • Tooltips explain why actions are disabled

Action Permissions vs View Access

View Access (App Level)

  • Controlled by ROLE_APP_ACCESS in apps.py
  • Determines which apps appear in navigation
  • Broad by default for most roles

Action Permissions (Feature Level)

  • Controlled by RBAC system (database permissions table)
  • Fine-grained (can_create_ticket, can_approve_payroll, etc.)
  • Checked on every mutation/action
  • Independent of app access

Example Matrix

Role Payroll App Access View Own Payroll View All Payroll Approve Payroll Process Payroll
Field Agent βœ… Yes βœ… Yes ❌ No ❌ No ❌ No
Sales Agent βœ… Yes βœ… Yes ❌ No ❌ No ❌ No
Dispatcher βœ… Yes βœ… Yes βœ… Yes* ❌ No ❌ No
PM βœ… Yes βœ… Yes βœ… Yes* ❌ No ❌ No
Contractor Admin βœ… Yes βœ… Yes βœ… Yes βœ… Yes βœ… Yes
Client Admin βœ… Yes βœ… Yes βœ… Yes βœ… Yes βœ… Yes

*Limited to their team/organization


Default Favorites Update

Changed

  • Contractor Admin: Added "payroll" to defaults (was team)
  • Dispatcher: Added "tasks" to defaults (was team)
  • Field Agent: Changed to "tickets, maps, timesheets, payroll"
  • Sales Agent: Changed to "sales_orders, customers, maps, payroll"

Why

  • Reflect most-used apps for each role
  • Casual workers prioritize earnings tracking
  • Dispatchers focus on task assignment

Frontend Impact

Navigation Bar

// Before: Hardcoded app list
const navItems = ['dashboard', 'tickets', 'projects'];

// After: Dynamic from API
const { apps } = useFetchApps();
const accessibleApps = apps.filter(app => app.has_access);

App Launcher

// Before: Role-based switch statement
switch(userRole) {
  case 'field_agent': return ['tickets', 'maps'];
  // ...
}

// After: API-driven with categories
const { apps_by_category } = useFetchApps();
{Object.entries(apps_by_category).map(([category, apps]) => (
  <CategorySection>
    {apps.filter(app => app.has_access).map(renderApp)}
  </CategorySection>
))}

Action Buttons

// Separate permission checks for actions
{hasPermission('can_create_ticket') && (
  <Button onClick={createTicket}>Create Ticket</Button>
)}

{hasPermission('can_approve_payroll') && (
  <Button onClick={approvePayroll}>Approve</Button>
)}

Backend Implementation

Row-Level Security Example

# Payroll endpoint
@router.get("/payroll")
def get_payroll(user: User = Depends(get_current_user), db: Session = Depends(get_db)):
    query = db.query(Payroll)
    
    # Apply row-level filtering
    if user.role in ['field_agent', 'sales_agent']:
        # Workers only see their own records
        query = query.filter(Payroll.user_id == user.id)
    elif user.role == 'dispatcher':
        # Dispatchers see their team
        query = query.filter(Payroll.organization_id == user.organization_id)
    # Admins see all (no additional filter)
    
    return query.all()

Permission Decorator

def require_permission(permission: str):
    def decorator(func):
        async def wrapper(*args, user: User = Depends(get_current_user), **kwargs):
            if not user.has_permission(permission):
                raise HTTPException(403, f"Missing permission: {permission}")
            return await func(*args, user=user, **kwargs)
        return wrapper
    return decorator

@router.post("/payroll/approve")
@require_permission('can_approve_payroll')
def approve_payroll(payroll_id: int, user: User):
    # Only executes if user has permission
    pass

Testing Checklist

Backend Tests

  • All 26 apps defined in APPS dictionary
  • All roles have valid app access lists
  • Helper functions work with new apps
  • Default favorites include valid app codes
  • Row-level security filters work correctly

Frontend Tests

  • Navigation shows correct apps per role
  • App launcher displays all accessible apps
  • Categories render correctly
  • Action buttons appear/disappear based on permissions
  • Settings page allows favoriting new apps
  • Max 6 favorites enforced
  • Invalid apps rejected with clear error

Integration Tests

  • Field agent sees only their payroll records
  • Dispatcher sees incidents, tasks, expenses
  • PM sees all apps except platform admin apps
  • Sales manager sees finance and inventory
  • Client admin can work as PM
  • Payroll access doesn't grant approval permissions

Migration Steps

Phase 1: Backend (Done βœ…)

  1. Add 4 new apps to APPS dictionary
  2. Update ROLE_APP_ACCESS for all 8 roles
  3. Update DEFAULT_FAVORITE_APPS
  4. Add philosophy comment

Phase 2: Frontend (Next)

  1. Update API calls to fetch new apps
  2. Test navigation with expanded app lists
  3. Verify app launcher categories
  4. Test favorites with new apps
  5. Implement permission-based action buttons

Phase 3: Permissions Setup

  1. Define action permissions in database
  2. Assign permissions to roles
  3. Implement row-level security queries
  4. Add permission decorators to endpoints

Phase 4: Testing

  1. User acceptance testing with each role
  2. Verify casual workers can see earnings
  3. Test multi-role scenarios
  4. Performance testing with 26 apps

Breaking Changes

None! πŸŽ‰

This is a backward-compatible update:

  • Existing apps still work
  • Old favorites still valid
  • No API contract changes
  • Only additive changes (more apps, more access)

Frontend will automatically:

  • Fetch new apps from API
  • Display expanded navigation
  • Allow favoriting new apps

Future Enhancements

  1. Permission Management UI - Admin interface to assign permissions
  2. Role Templates - Pre-configured permission sets per role
  3. Custom Roles - Organizations define their own roles
  4. App Analytics - Track which apps users access most
  5. Dynamic Permissions - Time-based or condition-based permissions
  6. App Bundles - Group apps into bundles (Operations Bundle, Finance Bundle)

Updated By: AI Assistant
Reviewed By: Pending
Status: Ready for Frontend Integration