# RBAC Architecture Visual Guide ## System Overview ``` ┌─────────────────────────────────────────────────────────────────┐ │ PLATFORM LEVEL │ │ User.role (4-value enum) │ │ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ Super Admin │ │ Platform Admin │ │ │ │ role= │ │ role= │ │ │ │ "super_admin" │ │ "platform_admin"│ │ │ │ │ │ │ │ │ │ • Full platform │ │ • Scoped to │ │ │ │ access │ │ assigned │ │ │ │ • All platforms │ │ platforms │ │ │ │ • Cannot access │ │ • Cannot access │ │ │ │ store portal │ │ store portal │ │ │ └──────────────────┘ └──────────────────┘ │ │ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ Merchant Owner │ │ Store Member │ │ │ │ role= │ │ role= │ │ │ │ "merchant_owner"│ │ "store_member" │ │ │ │ │ │ │ │ │ │ • Owns stores │ │ • Invited to │ │ │ │ • All perms in │ │ stores │ │ │ │ own stores │ │ • Role-based │ │ │ │ • Cannot access │ │ permissions │ │ │ │ admin portal │ │ • Cannot access │ │ │ └──────────────────┘ │ admin portal │ │ │ └──────────────────┘ │ │ │ │ └──────────────────────────────────────────────┼──────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ STORE LEVEL │ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Store: ACME │ │ │ │ │ │ │ │ ┌──────────────┐ ┌──────────────────────┐ │ │ │ │ │ Owner │ │ Team Members │ │ │ │ │ │ role= │ │ role= │ │ │ │ │ │ "merchant_ │ │ "store_member" │ │ │ │ │ │ owner" │ │ │ │ │ │ │ │ │ │ • Role-based perms │ │ │ │ │ │ • All perms │ │ • Manager/Staff/etc │ │ │ │ │ │ • Can invite │ │ • Can be invited │ │ │ │ │ │ • Can remove │ │ • Can be removed │ │ │ │ │ │ • Cannot be │ │ │ │ │ │ │ │ removed │ │ │ │ │ │ │ └──────────────┘ └──────────────────────┘ │ │ │ │ │ │ │ │ │ Ownership via Merchant.owner_user_id ▼ │ │ │ │ ┌──────────────────────────────┐ │ │ │ │ │ Roles │ │ │ │ │ │ │ │ │ │ │ │ • Manager (many perms) │ │ │ │ │ │ • Staff (moderate perms) │ │ │ │ │ │ • Support (limited perms) │ │ │ │ │ │ • Viewer (read-only) │ │ │ │ │ │ • Custom (owner-defined) │ │ │ │ │ └──────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────┐ │ CUSTOMER LEVEL │ │ (Separate from Users) │ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Customers (per store) │ │ │ │ │ │ │ │ • Store-scoped authentication │ │ │ │ • Can self-register │ │ │ │ • Access own account + shop catalog │ │ │ │ • Cannot access admin/store portals │ │ │ └──────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ## Team Invitation Flow ``` ┌──────────┐ │ Owner │ │ (ACME) │ └────┬─────┘ │ │ 1. Click "Invite Team Member" │ Email: jane@example.com │ Role: Manager ▼ ┌─────────────────────┐ │ System Creates: │ │ • User account │ │ • StoreUser │ │ • Invitation token │ └────┬────────────────┘ │ │ 2. Email sent to jane@example.com │ ▼ ┌──────────────────────┐ │ Jane clicks link │ │ /invitation/accept? │ │ token=abc123... │ └────┬─────────────────┘ │ │ 3. Jane sets password │ Enters name │ ▼ ┌─────────────────────┐ │ Account Activated: │ │ • User.is_active │ │ • StoreUser. │ │ is_active │ └────┬────────────────┘ │ │ 4. Jane can now login │ ▼ ┌──────────────────────┐ │ Jane logs in to │ │ ACME store portal │ │ with Manager perms │ └──────────────────────┘ ``` ## Permission Check Flow ``` ┌────────────────┐ │ User makes │ │ request to: │ │ POST /products │ └───────┬────────┘ │ ▼ ┌────────────────────────────────┐ │ FastAPI Dependency: │ │ require_store_permission( │ │ "products.create" │ │ ) │ └───────┬────────────────────────┘ │ │ 1. Get store from request.state │ 2. Get user from JWT │ ▼ ┌────────────────────────────────┐ │ Is user a member of store? │ └───────┬────────────────────────┘ │ ├─ No ──> ❌ StoreAccessDeniedException │ ▼ Yes ┌────────────────────────────────┐ │ Is user the owner? │ └───────┬────────────────────────┘ │ ├─ Yes ──> ✅ Allow (owners have all perms) │ ▼ No ┌────────────────────────────────┐ │ Get user's role and │ │ permissions from StoreUser │ └───────┬────────────────────────┘ │ ▼ ┌────────────────────────────────┐ │ Does role contain │ │ "products.create"? │ └───────┬────────────────────────┘ │ ├─ No ──> ❌ InsufficientStorePermissionsException │ ▼ Yes ┌────────────────────────────────┐ │ ✅ Allow request │ │ Handler executes │ └────────────────────────────────┘ ``` ## Database Relationships ``` ┌──────────────────┐ │ users │ │ │ │ id (PK) │◄────┐ │ email │ │ │ role │ │ │ ('super_admin', │ │ │ 'platform_ │ │ │ admin', │ │ │ 'merchant_ │ │ │ owner', │ │ │ 'store_member') │ │ └──────────────────┘ │ │ │ │ owner_user_id │ │ │ ▼ │ ┌──────────────────┐ │ │ stores │ │ │ │ │ │ id (PK) │ │ │ store_code │ │ │ owner_user_id ──┼─────┘ └──────────────────┘ │ │ ▼ ┌──────────────────┐ ┌──────────────────┐ │ store_users │ │ roles │ │ │ │ │ │ id (PK) │ │ id (PK) │ │ store_id (FK) │ │ store_id (FK) │ │ user_id (FK) │ │ name │ │ role_id (FK) ───┼────►│ permissions │ │ invitation_* │ │ (JSON) │ │ is_active │ └──────────────────┘ └──────────────────┘ (no user_type column; ownership via Merchant.owner_user_id) Separate hierarchy: ┌──────────────────┐ │ customers │ │ │ │ id (PK) │ │ store_id (FK) │ │ email │ │ hashed_password │ │ (store-scoped) │ └──────────────────┘ ``` ## Permission Naming Convention ``` Resource.Action Examples: ✓ dashboard.view ✓ products.view ✓ products.create ✓ products.edit ✓ products.delete ✓ products.import ✓ products.export ✓ orders.view ✓ orders.edit ✓ orders.cancel ✓ orders.refund ✓ customers.view ✓ customers.edit ✓ reports.financial ✓ team.invite ✓ team.remove ✓ settings.edit ``` ## Role Presets ``` ┌──────────────────────────────────────────────────────────────┐ │ OWNER │ │ ALL PERMISSIONS (automatic, not stored in role) │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ MANAGER │ │ Most permissions except: │ │ • team.invite/remove (owner only) │ │ • Critical settings (owner only) │ │ │ │ Has: products.*, orders.*, customers.*, reports.* │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ STAFF │ │ Day-to-day operations: │ │ • products.view/create/edit │ │ • stock.view/edit │ │ • orders.view/edit │ │ • customers.view │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ SUPPORT │ │ Customer service focus: │ │ • orders.view/edit │ │ • customers.view/edit │ │ • products.view (read-only) │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ VIEWER │ │ Read-only access: │ │ • *.view permissions only │ │ • No edit/create/delete │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ │ MARKETING │ │ Marketing & analytics focus: │ │ • customers.view/export │ │ • marketing.* (all marketing actions) │ │ • reports.view │ └──────────────────────────────────────────────────────────────┘ ``` ## Security Boundaries ``` ❌ BLOCKED ✅ ALLOWED super_admin → Store Portal super_admin → Admin Portal platform_admin → Store Portal platform_admin → Admin Portal merchant_owner → Admin Portal merchant_owner → Store Portal store_member → Admin Portal store_member → Store Portal Customer → Admin Portal Customer → Shop Catalog Customer → Store Portal Customer → Own Account Cookie Isolation: admin_token (path=/admin) ← Only sent to /admin/* store_token (path=/store) ← Only sent to /store/* customer_token (path=/shop) ← Only sent to /shop/* ```