Skip to content

User Management

Complete guide to managing user accounts, roles, permissions, and outlet assignments in the Reserva platform.


Overview

The user management system provides comprehensive account administration with support for:

  • User CRUD Operations - Create, read, update, and delete user accounts
  • Role-Based Access Control - Hierarchical permission system (SUPER_ADMIN → TENANT_ADMIN → OUTLET_MANAGER → STAFF)
  • Outlet Assignments - Manage which outlets users can access
  • Password Management - Administrative password reset with temporary credentials
  • User Statistics - Analytics and reporting on user accounts
  • Subscription Limits - Enforce user count restrictions based on subscription plan

Key Concepts:

  • Role Hierarchy = Controls who can manage whom (cannot manage equal or higher roles)
  • Tenant Isolation = Users can only see/manage accounts within their tenant
  • Outlet Scoping = Outlet managers restricted to their assigned outlets
  • Soft Deletion = User accounts deactivated, not permanently removed
  • Subscription Enforcement = User creation respects plan limits

Subscription Limits

User creation is subject to subscription plan limits:

Plan Max Outlets Max Staff per Outlet Total Users Impact
FREE 1 outlet 5 staff per outlet Max 5 staff + admins
PRO 10 outlets 50 staff per outlet Max 500 staff + admins
ENTERPRISE Unlimited Unlimited Unlimited users

Enforcement Rules:

  • Staff user creation checks max_staff_per_outlet limit for assigned outlets
  • Creating outlets checks max_outlets limit from subscription
  • Exceeding limits returns HTTP 403 with upgrade recommendation
  • Admins (TENANT_ADMIN, OUTLET_MANAGER) do not count toward staff limits
  • Deactivated users still count toward limits until fully deleted

Role Hierarchy

The platform uses a strict role hierarchy for access control:

SUPER_ADMIN (Platform administrators)
TENANT_ADMIN (Business owners)
OUTLET_MANAGER (Location managers)
STAFF (Service providers)

Permissions by Role:

Action SUPER_ADMIN TENANT_ADMIN OUTLET_MANAGER STAFF
View all users ✅ All tenants ✅ Own tenant ✅ Own outlets
Create users ✅ Any role ✅ Except SUPER_ADMIN ✅ STAFF only
Update users ✅ Anyone ✅ Own tenant ✅ Own outlets ✅ Self only
Delete users ✅ Except SUPER_ADMIN ✅ Lower roles ✅ STAFF only
Reset passwords ✅ Anyone ✅ Own tenant ✅ Own outlets
Manage outlets ✅ Anyone ✅ Own tenant ✅ Own outlets
View statistics ✅ All ✅ Own tenant ✅ Own outlets

List Users

Get paginated list of users with advanced filtering and role-based access control.

Endpoint

GET /api/v1/users

Authentication: Required (JWT token)

Query Parameters

  • page (optional) - Page number, default: 1
  • size (optional) - Items per page, default: 20, max: 100
  • role (optional) - Filter by role: SUPER_ADMIN, TENANT_ADMIN, OUTLET_MANAGER, STAFF
  • outlet_id (optional) - Filter by outlet assignment
  • search (optional) - Search by name or email (case-insensitive)
  • is_active (optional) - Filter by active status: true or false
  • include_locked (optional) - Include locked accounts, default: false

Response

{
  "items": [
    {
      "id": "60f1b2b3b3b3b3b3b3b3b3b3",
      "email": "john.doe@example.com",
      "first_name": "John",
      "last_name": "Doe",
      "phone": "+6281234567890",
      "role": "STAFF",
      "tenant_ids": ["507f1f77bcf86cd799439011"],
      "outlet_ids": ["507f1f77bcf86cd799439012"],
      "is_active": true,
      "is_locked": false,
      "avatar_url": "https://example.com/avatar.jpg",
      "created_at": "2025-01-15T10:30:00Z",
      "updated_at": "2025-01-20T14:45:00Z"
    }
  ],
  "total": 45,
  "page": 1,
  "size": 20,
  "pages": 3
}

Access Control

  • SUPER_ADMIN: View all users across all tenants (or filtered by tenant context)
  • TENANT_ADMIN: View all users within their tenant
  • OUTLET_MANAGER: View users within their managed outlets only
  • STAFF: Cannot access this endpoint (use /users/me instead)

Examples

Search by email:

curl -X GET "http://localhost:8000/api/v1/users?search=john" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Filter by role and outlet:

curl -X GET "http://localhost:8000/api/v1/users?role=STAFF&outlet_id=507f1f77bcf86cd799439012" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Include locked accounts:

curl -X GET "http://localhost:8000/api/v1/users?include_locked=true" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"


Create User

Create a new user account with role assignment and outlet allocation.

Endpoint

POST /api/v1/users

Authentication: Required (JWT token)

Request Body

{
  "email": "jane.smith@example.com",
  "password": "SecurePass123!",
  "first_name": "Jane",
  "last_name": "Smith",
  "phone": "+6281234567891",
  "role": "STAFF",
  "tenant_ids": ["507f1f77bcf86cd799439011"],
  "outlet_ids": ["507f1f77bcf86cd799439012"],
  "send_welcome_email": true
}

Parameters:

  • email (required) - Unique email address
  • password (optional) - User password (auto-generated if not provided)
  • first_name (required) - User's first name
  • last_name (required) - User's last name
  • phone (optional) - Phone number with country code
  • role (required) - User role (subject to hierarchy restrictions)
  • tenant_ids (required) - Array of tenant IDs (auto-assigned for non-super-admins)
  • outlet_ids (optional) - Array of outlet IDs (validated against tenant)
  • send_welcome_email (optional) - Send welcome email with credentials, default: false

Response

{
  "id": "60f1b2b3b3b3b3b3b3b3b3b4",
  "email": "jane.smith@example.com",
  "first_name": "Jane",
  "last_name": "Smith",
  "phone": "+6281234567891",
  "role": "STAFF",
  "tenant_ids": ["507f1f77bcf86cd799439011"],
  "outlet_ids": ["507f1f77bcf86cd799439012"],
  "is_active": true,
  "is_locked": false,
  "must_change_password": false,
  "created_at": "2025-01-21T09:15:00Z",
  "updated_at": "2025-01-21T09:15:00Z"
}

Access Control

  • SUPER_ADMIN: Can create users with any role in any tenant
  • TENANT_ADMIN: Can create users within their tenant (except SUPER_ADMIN)
  • OUTLET_MANAGER: Can create STAFF users for their managed outlets only
  • STAFF: Cannot create users

Business Rules

  1. Email Uniqueness: Email must be unique across entire system
  2. Role Hierarchy: Cannot create users with role equal to or higher than your own
  3. Tenant Validation: All assigned tenants must exist
  4. Outlet Validation: All assigned outlets must:
  5. Exist in the system
  6. Belong to one of the user's assigned tenants
  7. Subscription Limits: Staff creation checks subscription limits:
  8. FREE plan: Max 5 staff per outlet
  9. PRO plan: Max 50 staff per outlet
  10. ENTERPRISE: Unlimited
  11. Password Policy:
  12. Auto-generated passwords are marked for mandatory change on first login
  13. Custom passwords must meet minimum security requirements
  14. Outlet Assignment:
  15. Outlet managers can only assign users to outlets they manage
  16. Tenant admins inherit tenant context automatically

Subscription Limit Enforcement

When creating a STAFF user, the system checks:

# Get current staff count for each outlet
for outlet_id in user_in.outlet_ids:
    current_staff_count = await count_staff_in_outlet(outlet_id)
    subscription = await get_tenant_subscription(tenant_id)

    if subscription.plan_type == "FREE" and current_staff_count >= 5:
        raise HTTPException(
            status_code=403,
            detail="Staff limit reached for FREE plan. Upgrade to PRO for up to 50 staff per outlet."
        )
    elif subscription.plan_type == "PRO" and current_staff_count >= 50:
        raise HTTPException(
            status_code=403,
            detail="Staff limit reached for PRO plan. Upgrade to ENTERPRISE for unlimited staff."
        )

Error Responses

409 Conflict - Email already exists:

{
  "detail": "User with this email already exists"
}

403 Forbidden - Subscription limit reached:

{
  "detail": "Staff limit reached for FREE plan (5/5). Upgrade to PRO for up to 50 staff per outlet.",
  "error_code": "SUBSCRIPTION_LIMIT_EXCEEDED",
  "upgrade_url": "/api/v1/subscriptions/upgrade"
}

403 Forbidden - Role hierarchy violation:

{
  "detail": "Cannot create super admin users"
}

404 Not Found - Invalid outlet:

{
  "detail": "Outlet 507f1f77bcf86cd799439012 not found"
}


Get Current User Profile

Retrieve the authenticated user's own profile information.

Endpoint

GET /api/v1/users/me

Authentication: Required (JWT token)

Response

{
  "id": "60f1b2b3b3b3b3b3b3b3b3b3",
  "email": "john.doe@example.com",
  "first_name": "John",
  "last_name": "Doe",
  "phone": "+6281234567890",
  "role": "STAFF",
  "tenant_ids": ["507f1f77bcf86cd799439011"],
  "outlet_ids": ["507f1f77bcf86cd799439012"],
  "is_active": true,
  "is_locked": false,
  "must_change_password": false,
  "avatar_url": "https://example.com/avatar.jpg",
  "last_login_at": "2025-01-21T08:30:00Z",
  "password_changed_at": "2025-01-15T10:00:00Z",
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-20T14:45:00Z"
}

Access Control

  • All authenticated users can access their own profile
  • No additional permissions required beyond valid JWT token

Use Cases

  • Display user information in UI header/profile section
  • Check current role and permissions
  • Verify outlet assignments
  • Show account status and security settings

Get User by ID

Retrieve a specific user's profile by their unique ID.

Endpoint

GET /api/v1/users/{user_id}

Authentication: Required (JWT token)

Path Parameters

  • user_id (required) - User's unique ObjectId

Response

Same structure as /users/me endpoint.

Access Control

  • SUPER_ADMIN: Can view any user profile
  • TENANT_ADMIN: Can view users within their tenant
  • OUTLET_MANAGER: Can view users in their managed outlets (must share at least one outlet)
  • STAFF: Can only view their own profile (redirected to use /users/me)

Examples

curl -X GET "http://localhost:8000/api/v1/users/60f1b2b3b3b3b3b3b3b3b3b3" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Error Responses

404 Not Found - User doesn't exist:

{
  "detail": "User not found"
}

403 Forbidden - Insufficient permissions:

{
  "detail": "Cannot view users from other tenants"
}


Update User

Update a user's information with role-based field restrictions.

Endpoint

PUT /api/v1/users/{user_id}

Authentication: Required (JWT token)

Path Parameters

  • user_id (required) - User's unique ObjectId

Request Body

{
  "first_name": "Jane",
  "last_name": "Smith",
  "phone": "+6281234567892",
  "role": "OUTLET_MANAGER",
  "outlet_ids": ["507f1f77bcf86cd799439012", "507f1f77bcf86cd799439013"],
  "is_active": true,
  "avatar_url": "https://example.com/new-avatar.jpg"
}

Updatable Fields (role-dependent):

Field SUPER_ADMIN TENANT_ADMIN OUTLET_MANAGER STAFF (self)
first_name
last_name
phone
avatar_url
email
role ✅ (restrictions)
tenant_ids
outlet_ids ✅ (own outlets)
is_active
is_locked

Response

Returns updated user object with same structure as GET response.

Access Control

  • SUPER_ADMIN: Can update any user with any changes
  • TENANT_ADMIN: Can update users within tenant (cannot promote to SUPER_ADMIN)
  • OUTLET_MANAGER: Can update staff in managed outlets (no role changes)
  • STAFF: Can only update own profile (limited fields: first_name, last_name, phone, avatar_url)

Business Rules

  1. Role Modification Protection:

  2. Cannot modify SUPER_ADMIN accounts unless you are SUPER_ADMIN

  3. Cannot promote users to roles higher than your own
  4. OUTLET_MANAGER cannot change any user's role

  5. Tenant Boundary Enforcement:

  6. Cannot update users from other tenants

  7. Tenant assignment changes require SUPER_ADMIN

  8. Outlet Assignment Validation:

  9. All outlets must exist and belong to user's tenant

  10. OUTLET_MANAGER can only assign to outlets they manage
  11. Changes validated against subscription limits

  12. Field Restrictions:

  13. STAFF can only update: first_name, last_name, phone, avatar_url

  14. Attempting to update restricted fields returns 403 error

Examples

Staff updating own profile:

curl -X PUT "http://localhost:8000/api/v1/users/60f1b2b3b3b3b3b3b3b3b3b3" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Jonathan",
    "phone": "+6281234567899"
  }'

Admin promoting user to manager:

curl -X PUT "http://localhost:8000/api/v1/users/60f1b2b3b3b3b3b3b3b3b3b3" \
  -H "Authorization: Bearer ADMIN_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "OUTLET_MANAGER",
    "outlet_ids": ["507f1f77bcf86cd799439012"]
  }'

Error Responses

403 Forbidden - Field restriction violation:

{
  "detail": "Can only update fields: avatar_url, first_name, last_name, phone"
}

403 Forbidden - Role hierarchy violation:

{
  "detail": "Cannot promote user to super admin"
}


Delete User

Soft delete a user account by marking as inactive and deleted.

Endpoint

DELETE /api/v1/users/{user_id}

Authentication: Required (JWT token)

Path Parameters

  • user_id (required) - User's unique ObjectId

Response

{
  "message": "User has been deleted successfully"
}

Access Control

  • SUPER_ADMIN: Can delete any user except other SUPER_ADMINs
  • TENANT_ADMIN: Can delete users within tenant (no admins, no self)
  • OUTLET_MANAGER: Can delete STAFF in managed outlets only
  • STAFF: Cannot delete any users

Business Rules

  1. Self-Deletion Prevention: Cannot delete your own account
  2. Role Protection: Cannot delete users with same or higher role
  3. Already Deleted Check: Returns 400 if user already deactivated
  4. Soft Delete: User marked as is_active: false, is_deleted: true, data preserved
  5. Tenant Isolation: Can only delete users within accessible scope

Deletion Behavior

When a user is deleted: - is_active set to false - is_deleted set to true - deleted_at timestamp recorded - User data preserved for audit purposes - User cannot log in anymore - User still counts toward subscription limits until purged - Scheduled appointments remain active (business continuity)

Examples

curl -X DELETE "http://localhost:8000/api/v1/users/60f1b2b3b3b3b3b3b3b3b3b3" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Error Responses

400 Bad Request - Self-deletion attempt:

{
  "detail": "Cannot delete your own account"
}

400 Bad Request - Already deleted:

{
  "detail": "User is already deactivated"
}

403 Forbidden - Insufficient permissions:

{
  "detail": "Cannot delete super admin accounts"
}


Reset User Password

Administratively reset a user's password with optional auto-generation.

Endpoint

POST /api/v1/users/{user_id}/reset-password

Authentication: Required (JWT token)

Path Parameters

  • user_id (required) - User's unique ObjectId

Request Body

{
  "new_password": "NewSecure123!",
  "force_change": true,
  "send_notification": true
}

Parameters:

  • new_password (optional) - Custom password (auto-generated if not provided)
  • force_change (optional) - Require password change on next login, default: true
  • send_notification (optional) - Send email notification to user, default: false

Response

With auto-generated password:

{
  "message": "Password reset successfully",
  "temporary_password": "TempPass789!"
}

With custom password:

{
  "message": "Password reset successfully"
}

Access Control

  • SUPER_ADMIN: Can reset any user's password
  • TENANT_ADMIN: Can reset passwords within tenant (except SUPER_ADMIN)
  • OUTLET_MANAGER: Can reset STAFF passwords in managed outlets
  • STAFF: Cannot use this endpoint (use profile endpoint for own password)

Password Reset Behavior

When password is reset:

  1. hashed_password updated with new secure hash
  2. must_change_password set based on force_change parameter
  3. password_changed_at timestamp updated
  4. failed_login_attempts reset to 0
  5. is_locked set to false (account unlocked)
  6. locked_until cleared
  7. Optional email notification sent with temporary credentials

Security Rules

  1. Self-Reset Prevention: Cannot reset your own password via admin endpoint
  2. Auto-Generated Passwords: Cryptographically secure, 12+ characters
  3. Forced Password Change: Auto-generated passwords require change on first login
  4. Account Unlock: Password reset automatically unlocks locked accounts
  5. Audit Trail: Reset action logged with admin user ID and timestamp

Examples

Auto-generate password:

curl -X POST "http://localhost:8000/api/v1/users/60f1b2b3b3b3b3b3b3b3b3b3/reset-password" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "force_change": true,
    "send_notification": true
  }'

Set custom password:

curl -X POST "http://localhost:8000/api/v1/users/60f1b2b3b3b3b3b3b3b3b3b3/reset-password" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "new_password": "SecurePass123!",
    "force_change": false
  }'

Error Responses

400 Bad Request - Self-reset attempt:

{
  "detail": "Use profile endpoint to change your own password"
}

403 Forbidden - Cannot reset super admin:

{
  "detail": "Cannot reset super admin passwords"
}


Update Outlet Assignments

Update which outlets a user is assigned to.

Endpoint

PUT /api/v1/users/{user_id}/outlets

Authentication: Required (JWT token)

Path Parameters

  • user_id (required) - User's unique ObjectId

Request Body

{
  "outlet_ids": [
    "507f1f77bcf86cd799439012",
    "507f1f77bcf86cd799439013"
  ]
}

Parameters:

  • outlet_ids (required) - Array of outlet IDs (replaces existing assignments)

Response

Returns updated user object with new outlet assignments.

Access Control

  • SUPER_ADMIN: Can assign users to any outlet
  • TENANT_ADMIN: Can assign users to any outlet within their tenant
  • OUTLET_MANAGER: Can only assign/remove users to/from their managed outlets
  • STAFF: Cannot modify outlet assignments

Business Rules

  1. Complete Replacement: This endpoint replaces ALL existing outlet assignments
  2. Tenant Validation: All outlets must belong to user's tenant
  3. Manager Restrictions:
  4. OUTLET_MANAGER can only assign to outlets they manage
  5. OUTLET_MANAGER can only modify users already in their outlets
  6. Subscription Limits: Assignment checks staff limits per outlet
  7. Empty Array: Setting outlet_ids: [] removes all outlet assignments

Subscription Enforcement

When assigning users to outlets:

for outlet_id in outlet_assignment.outlet_ids:
    # Count current staff in outlet
    staff_count = await count_staff_in_outlet(outlet_id)
    subscription = await get_outlet_subscription(outlet_id)

    # Check limits based on plan
    if subscription.plan_type == "FREE" and staff_count >= 5:
        raise HTTPException(403, "Outlet has reached FREE plan staff limit (5)")
    elif subscription.plan_type == "PRO" and staff_count >= 50:
        raise HTTPException(403, "Outlet has reached PRO plan staff limit (50)")

Examples

Assign to multiple outlets:

curl -X PUT "http://localhost:8000/api/v1/users/60f1b2b3b3b3b3b3b3b3b3b3/outlets" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "outlet_ids": ["507f1f77bcf86cd799439012", "507f1f77bcf86cd799439013"]
  }'

Remove all outlet assignments:

curl -X PUT "http://localhost:8000/api/v1/users/60f1b2b3b3b3b3b3b3b3b3b3/outlets" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "outlet_ids": []
  }'

Error Responses

403 Forbidden - Subscription limit exceeded:

{
  "detail": "Outlet 507f1f77bcf86cd799439012 has reached FREE plan staff limit (5/5). Upgrade to add more staff.",
  "error_code": "OUTLET_STAFF_LIMIT_EXCEEDED"
}

403 Forbidden - Manager permission denied:

{
  "detail": "You don't have permission to assign users to outlet 507f1f77bcf86cd799439013"
}

404 Not Found - Invalid outlet:

{
  "detail": "Outlet 507f1f77bcf86cd799439099 not found"
}


Get User Statistics

Retrieve comprehensive user analytics and statistics based on access level.

Endpoint

GET /api/v1/users/stats/summary

Authentication: Required (JWT token)

Response

{
  "total_users": 127,
  "active_users": 119,
  "locked_users": 3,
  "users_by_role": {
    "SUPER_ADMIN": 2,
    "TENANT_ADMIN": 5,
    "OUTLET_MANAGER": 15,
    "STAFF": 105
  },
  "recent_signups": 8,
  "subscription_usage": {
    "plan_type": "PRO",
    "staff_limit_per_outlet": 50,
    "outlets_with_limits": [
      {
        "outlet_id": "507f1f77bcf86cd799439012",
        "outlet_name": "Downtown Spa",
        "current_staff": 45,
        "limit": 50,
        "percentage": 90,
        "status": "approaching_limit"
      }
    ]
  }
}

Access Control

  • SUPER_ADMIN: System-wide stats (all tenants or specific tenant context)
  • TENANT_ADMIN: Stats for their tenant only
  • OUTLET_MANAGER: Stats for users in their managed outlets
  • STAFF: Cannot access user statistics

Statistics Included

  1. Total Users: Count of all users in accessible scope
  2. Active Users: Users with is_active: true
  3. Locked Users: Users with is_locked: true (security monitoring)
  4. Users by Role: Breakdown of user distribution across roles
  5. Recent Signups: New users in last 30 days
  6. Subscription Usage: Staff count vs limits per outlet

Examples

curl -X GET "http://localhost:8000/api/v1/users/stats/summary" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Use Cases

  • Dashboard Analytics: Display user growth and distribution
  • Capacity Planning: Monitor staff limits approaching subscription caps
  • Security Monitoring: Track locked accounts and inactive users
  • Subscription Optimization: Identify outlets near capacity for upgrade recommendations

Best Practices

For User Creation

DO:

  • Always validate email uniqueness before creation
  • Check subscription limits before creating STAFF users
  • Use auto-generated passwords for initial setup
  • Force password change for auto-generated credentials
  • Assign users to specific outlets for proper access control
  • Send welcome emails with login instructions

DON'T:

  • Create users without outlet assignments (unless admins)
  • Bypass role hierarchy restrictions
  • Skip subscription limit checks
  • Allow STAFF users to create other users
  • Create users in outlets from other tenants

For User Updates

DO:

  • Validate outlet assignments belong to user's tenant
  • Check role hierarchy before role changes
  • Preserve audit fields (created_at, id)
  • Use partial updates (only send changed fields)
  • Re-validate subscription limits when adding outlets

DON'T:

  • Allow cross-tenant user modifications
  • Permit role escalation beyond hierarchy
  • Let STAFF modify security fields
  • Bypass outlet manager restrictions
  • Update deleted/inactive users without reactivation

For Password Management

DO:

  • Use secure password hashing (bcrypt)
  • Generate cryptographically random temporary passwords
  • Force password change for temporary credentials
  • Reset failed login attempts on password reset
  • Unlock accounts during password reset
  • Log all password reset actions

DON'T:

  • Send passwords in plain text (except secure initial delivery)
  • Allow password reset without authentication
  • Skip password complexity validation
  • Allow self-reset via admin endpoint
  • Reuse old passwords

For Subscription Limits

DO:

  • Check limits before creating staff users
  • Validate limits before outlet assignments
  • Return clear upgrade recommendations
  • Count only active STAFF toward limits
  • Provide limit details in error messages

DON'T:

  • Count admins toward staff limits
  • Allow limit bypass without validation
  • Create users exceeding plan capacity
  • Hide subscription limit information

Troubleshooting

Cannot Create User

Symptoms: User creation fails with validation error

Checks:

  1. Verify email is unique: db.users.find_one({"email": "..."})
  2. Check subscription limits for tenant
  3. Verify outlets exist and belong to tenant
  4. Confirm role hierarchy allows creation
  5. Validate outlet manager has access to assigned outlets

Fix:

  • Use different email address
  • Upgrade subscription plan if at limit
  • Assign to valid outlets within tenant
  • Adjust role to match hierarchy

User Cannot Access Resources

Symptoms: 403 Forbidden errors when accessing features

Checks:

  1. Verify user has correct role: GET /users/{user_id}
  2. Check outlet assignments: user.outlet_ids
  3. Confirm tenant membership: user.tenant_ids
  4. Validate account is active: user.is_active: true
  5. Check account not locked: user.is_locked: false

Fix:

  • Update outlet assignments if incorrect
  • Promote role if needed (with proper permissions)
  • Reactivate account if deactivated
  • Unlock account via password reset

Subscription Limit Errors

Symptoms: Cannot create users, "limit exceeded" errors

Checks:

  1. Get current subscription: GET /subscriptions/current
  2. Count staff per outlet: db.users.count_documents({"role": "STAFF", "outlet_ids": outlet_id})
  3. Review plan limits: FREE=5, PRO=50, ENTERPRISE=unlimited
  4. Check if counting includes inactive users

Fix:

  • Upgrade subscription plan
  • Deactivate/delete unused staff accounts
  • Redistribute staff across multiple outlets
  • Contact support for limit increase

Outlet Assignment Failures

Symptoms: Cannot assign users to outlets

Checks:

  1. Verify outlet exists: GET /outlets/{outlet_id}
  2. Check outlet belongs to user's tenant
  3. Confirm manager has access to outlet (if OUTLET_MANAGER)
  4. Validate subscription limits for outlet

Fix:

  • Use outlets from correct tenant
  • Request manager access to outlet
  • Upgrade plan if outlet at capacity
  • Create user in different outlet

API Reference Summary

Endpoint Method Purpose Access
/users GET List users with filtering OUTLET_MANAGER+
/users POST Create new user OUTLET_MANAGER+
/users/me GET Get own profile All authenticated
/users/{user_id} GET Get user by ID Role-based
/users/{user_id} PUT Update user Role-based
/users/{user_id} DELETE Soft delete user OUTLET_MANAGER+
/users/{user_id}/reset-password POST Reset password OUTLET_MANAGER+
/users/{user_id}/outlets PUT Update outlets TENANT_ADMIN+
/users/stats/summary GET User statistics OUTLET_MANAGER+

Security Considerations

Authentication & Authorization

  • All endpoints require valid JWT token
  • Role hierarchy strictly enforced
  • Tenant isolation on every request
  • Outlet scoping for managers
  • Session validation on each request

Password Security

  • Bcrypt hashing with salt rounds ≥12
  • Temporary passwords auto-generated (cryptographically secure)
  • Failed login attempt tracking (max 5 attempts)
  • Account lockout after failed attempts (30 minute duration)
  • Password change timestamps for audit

Data Protection

  • Soft deletion preserves audit trail
  • Sensitive fields excluded from logs
  • Role-based field access restrictions
  • Tenant data isolation enforced at DB level
  • No cross-tenant data exposure

Audit & Compliance

  • All user actions logged with timestamps
  • Password reset actions tracked with admin ID
  • Role changes require administrative approval
  • Deletion preserves historical data
  • GDPR-compliant data retention policies

Next Steps:

  1. Review role hierarchy and permissions: Role Hierarchy
  2. Check subscription limits for your plan: Subscription Limits
  3. Create your first user: POST /users
  4. Assign outlets: PUT /users/{user_id}/outlets
  5. Monitor usage: GET /users/stats/summary

For subscription management and upgrades, refer to the Subscription Management documentation.