Spaces:
Sleeping
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.pydocs/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)
Incidents - Incident tracking and resolution
- Category: Operations
- Icon: alert-triangle
- Route: /incidents
Tasks - Task management and assignment
- Category: Operations
- Icon: check-square
- Route: /tasks
Subscriptions - Recurring revenue management
- Category: Finance
- Icon: refresh-cw
- Route: /subscriptions
- Requires: view_subscriptions permission
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)
- β
Can create projects (has
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_ACCESSinapps.py - Determines which apps appear in navigation
- Broad by default for most roles
Action Permissions (Feature Level)
- Controlled by RBAC system (database
permissionstable) - 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 β )
- Add 4 new apps to APPS dictionary
- Update ROLE_APP_ACCESS for all 8 roles
- Update DEFAULT_FAVORITE_APPS
- Add philosophy comment
Phase 2: Frontend (Next)
- Update API calls to fetch new apps
- Test navigation with expanded app lists
- Verify app launcher categories
- Test favorites with new apps
- Implement permission-based action buttons
Phase 3: Permissions Setup
- Define action permissions in database
- Assign permissions to roles
- Implement row-level security queries
- Add permission decorators to endpoints
Phase 4: Testing
- User acceptance testing with each role
- Verify casual workers can see earnings
- Test multi-role scenarios
- 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
- Permission Management UI - Admin interface to assign permissions
- Role Templates - Pre-configured permission sets per role
- Custom Roles - Organizations define their own roles
- App Analytics - Track which apps users access most
- Dynamic Permissions - Time-based or condition-based permissions
- App Bundles - Group apps into bundles (Operations Bundle, Finance Bundle)
Updated By: AI Assistant
Reviewed By: Pending
Status: Ready for Frontend Integration