# RBAC Quick Reference Card **For Daily Development** | Keep this handy while coding --- ## Common Imports ```python # Authentication dependencies from app.api.deps import ( get_current_admin_from_cookie_or_header, get_current_vendor_from_cookie_or_header, require_vendor_permission, require_vendor_owner, get_user_permissions ) # Permission constants from app.core.permissions import VendorPermissions # Exceptions from app.exceptions import ( InsufficientVendorPermissionsException, VendorOwnerOnlyException ) # Services from app.services.vendor_team_service import vendor_team_service ``` --- ## Route Patterns ### Admin Route (Cookie OR Header) ```python @router.get("/admin/vendors") def list_vendors( user: User = Depends(get_current_admin_from_cookie_or_header) ): # user is authenticated admin ... ``` ### Admin API (Header Only) ```python @router.post("/api/v1/admin/vendors") def create_vendor( user: User = Depends(get_current_admin_api) ): # user is authenticated admin (header required) ... ``` ### Vendor Route with Permission ```python @router.post("/vendor/{code}/products") def create_product( user: User = Depends(require_vendor_permission( VendorPermissions.PRODUCTS_CREATE.value )) ): # user has products.create permission vendor = request.state.vendor ... ``` ### Owner-Only Route ```python @router.post("/vendor/{code}/team/invite") def invite_member( user: User = Depends(require_vendor_owner) ): # user is vendor owner vendor = request.state.vendor ... ``` ### Multi-Permission Route ```python @router.post("/vendor/{code}/products/bulk") def bulk_operation( user: User = Depends(require_all_vendor_permissions( VendorPermissions.PRODUCTS_VIEW.value, VendorPermissions.PRODUCTS_EDIT.value )) ): # user has ALL specified permissions ... ``` --- ## Permission Constants ### Quick Lookup ```python # Dashboard VendorPermissions.DASHBOARD_VIEW # Products VendorPermissions.PRODUCTS_VIEW VendorPermissions.PRODUCTS_CREATE VendorPermissions.PRODUCTS_EDIT VendorPermissions.PRODUCTS_DELETE VendorPermissions.PRODUCTS_IMPORT VendorPermissions.PRODUCTS_EXPORT # Stock VendorPermissions.STOCK_VIEW VendorPermissions.STOCK_EDIT VendorPermissions.STOCK_TRANSFER # Orders VendorPermissions.ORDERS_VIEW VendorPermissions.ORDERS_EDIT VendorPermissions.ORDERS_CANCEL VendorPermissions.ORDERS_REFUND # Customers VendorPermissions.CUSTOMERS_VIEW VendorPermissions.CUSTOMERS_EDIT VendorPermissions.CUSTOMERS_DELETE VendorPermissions.CUSTOMERS_EXPORT # Marketing VendorPermissions.MARKETING_VIEW VendorPermissions.MARKETING_CREATE VendorPermissions.MARKETING_SEND # Reports VendorPermissions.REPORTS_VIEW VendorPermissions.REPORTS_FINANCIAL VendorPermissions.REPORTS_EXPORT # Settings VendorPermissions.SETTINGS_VIEW VendorPermissions.SETTINGS_EDIT VendorPermissions.SETTINGS_THEME VendorPermissions.SETTINGS_DOMAINS # Team VendorPermissions.TEAM_VIEW VendorPermissions.TEAM_INVITE VendorPermissions.TEAM_EDIT VendorPermissions.TEAM_REMOVE # Imports VendorPermissions.IMPORTS_VIEW VendorPermissions.IMPORTS_CREATE VendorPermissions.IMPORTS_CANCEL ``` --- ## User Helper Methods ```python # Check if admin user.is_admin # bool # Check if vendor user.is_vendor # bool # Check vendor ownership user.is_owner_of(vendor_id) # bool # Check vendor membership user.is_member_of(vendor_id) # bool # Get role in vendor user.get_vendor_role(vendor_id) # str: "owner" | "member" | None # Check specific permission user.has_vendor_permission(vendor_id, "products.create") # bool ``` --- ## VendorUser Helper Methods ```python # Check if owner vendor_user.is_owner # bool # Check if team member vendor_user.is_team_member # bool # Check invitation status vendor_user.is_invitation_pending # bool # Check permission vendor_user.has_permission("products.create") # bool # Get all permissions vendor_user.get_all_permissions() # list[str] ``` --- ## Service Methods ### Team Management ```python # Invite team member vendor_team_service.invite_team_member( db=db, vendor=vendor, inviter=current_user, email="member@example.com", role_name="Staff", custom_permissions=None # Optional ) # Accept invitation vendor_team_service.accept_invitation( db=db, invitation_token=token, password="password123", first_name="John", last_name="Doe" ) # Remove team member vendor_team_service.remove_team_member( db=db, vendor=vendor, user_id=member_id ) # Update member role vendor_team_service.update_member_role( db=db, vendor=vendor, user_id=member_id, new_role_name="Manager", custom_permissions=None ) # Get team members members = vendor_team_service.get_team_members( db=db, vendor=vendor, include_inactive=False ) ``` --- ## Exception Handling ```python from app.exceptions import ( InsufficientVendorPermissionsException, VendorOwnerOnlyException, VendorAccessDeniedException, InvalidInvitationTokenException, CannotRemoveVendorOwnerException, TeamMemberAlreadyExistsException ) # Raise permission error raise InsufficientVendorPermissionsException( required_permission="products.create", vendor_code=vendor.vendor_code ) # Raise owner-only error raise VendorOwnerOnlyException( operation="team management", vendor_code=vendor.vendor_code ) # Raise access denied raise VendorAccessDeniedException( vendor_code=vendor.vendor_code, user_id=user.id ) ``` --- ## Frontend Permission Checks ### JavaScript/Alpine.js ```javascript // Check permission function hasPermission(permission) { const permissions = JSON.parse( localStorage.getItem('permissions') || '[]' ); return permissions.includes(permission); } // Conditional rendering {hasPermission('products.create') && ( )} // Disable button // Get permissions on login async function getPermissions() { const response = await fetch( '/api/v1/vendor/team/me/permissions', { headers: { 'Authorization': `Bearer ${token}` } } ); const data = await response.json(); localStorage.setItem( 'permissions', JSON.stringify(data.permissions) ); } ``` --- ## Testing Patterns ### Unit Test ```python def test_owner_has_all_permissions(): vendor_user = create_vendor_user(user_type="owner") assert vendor_user.has_permission("products.create") assert vendor_user.has_permission("team.invite") ``` ### Integration Test ```python def test_create_product_with_permission(client): user = create_user_with_permission("products.create") token = create_token(user) response = client.post( "/api/v1/vendor/ACME/products", json={"name": "Test"}, headers={"Authorization": f"Bearer {token}"} ) assert response.status_code == 201 ``` --- ## Common Mistakes to Avoid ### ❌ DON'T: Check permissions in service layer ```python # BAD def create_product(user, data): if not user.has_permission("products.create"): raise Exception() ``` ### ✅ DO: Check permissions at route level ```python # GOOD @router.post("/products") def create_product( user: User = Depends(require_vendor_permission("products.create")) ): return service.create_product(data) ``` --- ### ❌ DON'T: Use magic strings ```python # BAD require_vendor_permission("products.creat") # Typo! ``` ### ✅ DO: Use constants ```python # GOOD require_vendor_permission(VendorPermissions.PRODUCTS_CREATE.value) ``` --- ### ❌ DON'T: Mix contexts ```python # BAD - Admin trying to access vendor route # This will be blocked automatically ``` ### ✅ DO: Use correct portal ```python # GOOD - Admins use /admin/*, vendors use /vendor/* ``` --- ## Debugging Commands ### Check User Access ```python user = db.query(User).get(user_id) vendor = db.query(Vendor).get(vendor_id) print(f"Is owner: {user.is_owner_of(vendor.id)}") print(f"Is member: {user.is_member_of(vendor.id)}") print(f"Role: {user.get_vendor_role(vendor.id)}") print(f"Has products.create: {user.has_vendor_permission(vendor.id, 'products.create')}") ``` ### Decode JWT Token ```python import jwt token = "eyJ0eXAi..." decoded = jwt.decode(token, verify=False) print(f"User ID: {decoded['sub']}") print(f"Username: {decoded['username']}") print(f"Role: {decoded['role']}") print(f"Expires: {decoded['exp']}") ``` ### Check Cookie ```javascript // In browser console document.cookie.split(';').forEach(c => console.log(c.trim())); ``` --- ## Role Presets | Role | Typical Permissions | |------|---------------------| | **Owner** | ALL (automatic) | | **Manager** | Most operations, no team management | | **Staff** | Products, orders, customers (CRUD) | | **Support** | Orders, customers (support focus) | | **Viewer** | Read-only access | | **Marketing** | Customers, marketing, reports | --- ## File Locations ``` app/ ├── api/ │ ├── deps.py ← All auth dependencies │ └── v1/ │ ├── admin/ │ │ └── auth.py ← Admin login │ ├── vendor/ │ │ ├── auth.py ← Vendor login │ │ └── team.py ← Team management │ └── public/ │ └── vendors/auth.py ← Customer login │ ├── core/ │ └── permissions.py ← Permission constants │ ├── exceptions/ │ ├── admin.py │ ├── vendor.py │ └── auth.py │ ├── services/ │ ├── auth_service.py │ └── vendor_team_service.py ← Team management │ └── models/ └── database/ ├── user.py ← User model ├── vendor.py ← Vendor, VendorUser, Role └── customer.py ← Customer model ``` --- ## Status Codes | Code | Meaning | Common Cause | |------|---------|--------------| | 200 | OK | Success | | 201 | Created | Resource created | | 401 | Unauthorized | No/invalid token | | 403 | Forbidden | No permission | | 404 | Not Found | Resource not found | | 422 | Validation Error | Invalid input | --- ## Environment Variables ```bash JWT_SECRET_KEY=your-secret-key JWT_ALGORITHM=HS256 JWT_EXPIRATION=3600 # seconds (1 hour) ENVIRONMENT=development|staging|production ``` --- **Print and keep at your desk!** For full documentation: See [RBAC Developer Guide](../api/rbac.md)