Files
orion/docs/api/rbac-visual-guide.md
Samir Boulahtit 1dcb0e6c33
Some checks failed
CI / ruff (push) Successful in 11s
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / pytest (push) Has been cancelled
feat: RBAC Phase 1 — consolidate user roles into 4-value enum
Consolidate User.role (2-value: admin/store) + User.is_super_admin (boolean)
into a single 4-value UserRole enum: super_admin, platform_admin,
merchant_owner, store_member. Drop stale StoreUser.user_type column.
Fix role="user" bug in merchant creation.

Key changes:
- Expand UserRole enum from 2 to 4 values with computed properties
  (is_admin, is_super_admin, is_platform_admin, is_merchant_owner, is_store_user)
- Add Alembic migration (tenancy_003) for data migration + column drops
- Remove is_super_admin from JWT token payload
- Update all auth dependencies, services, routes, templates, JS, and tests
- Update all RBAC documentation

66 files changed, 1219 unit tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 22:44:29 +01:00

19 KiB

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/*