RBAC documentation
This commit is contained in:
298
docs/__REVAMPING/RBAC/INDEX.md
Normal file
298
docs/__REVAMPING/RBAC/INDEX.md
Normal file
@@ -0,0 +1,298 @@
|
||||
# RBAC Implementation - Deliverables Index
|
||||
|
||||
## Overview
|
||||
|
||||
This package contains a complete RBAC (Role-Based Access Control) implementation for your multi-tenant e-commerce platform. All files are ready to be integrated into your codebase.
|
||||
|
||||
## 📚 Developer Documentation
|
||||
|
||||
### For Your Development Team
|
||||
|
||||
**[RBAC_DEVELOPER_GUIDE.md](RBAC_DEVELOPER_GUIDE.md)** ⭐ **Primary Documentation**
|
||||
- Complete developer guide (800+ lines)
|
||||
- Architecture overview and design principles
|
||||
- Database schema with detailed explanations
|
||||
- Permission system structure
|
||||
- Authentication and authorization flows
|
||||
- Team management workflows
|
||||
- Extensive code examples for all scenarios
|
||||
- Best practices and patterns
|
||||
- Comprehensive testing guidelines
|
||||
- Troubleshooting section
|
||||
- **Give this to your developers** - Everything they need to know
|
||||
|
||||
**[RBAC_QUICK_REFERENCE.md](RBAC_QUICK_REFERENCE.md)** 📋 **Quick Reference**
|
||||
- One-page reference for daily development
|
||||
- Common imports and patterns
|
||||
- Permission constants lookup
|
||||
- Helper methods cheat sheet
|
||||
- Frontend integration snippets
|
||||
- Testing patterns
|
||||
- Debugging commands
|
||||
- **Print and keep at desk** - For quick lookups
|
||||
|
||||
### For Implementation Planning
|
||||
|
||||
**[RBAC_IMPLEMENTATION_SUMMARY.md](RBAC_IMPLEMENTATION_SUMMARY.md)**
|
||||
- Executive summary and key recommendations
|
||||
- Architecture overview and permission hierarchy
|
||||
- Security best practices
|
||||
- Common pitfalls to avoid
|
||||
- Implementation checklist
|
||||
- Q&A section
|
||||
- **For planning** - Read this first for the big picture
|
||||
|
||||
**[RBAC_VISUAL_GUIDE.md](RBAC_VISUAL_GUIDE.md)**
|
||||
- System architecture diagrams
|
||||
- Team invitation flow
|
||||
- Permission check flow
|
||||
- Database relationship diagrams
|
||||
- Permission naming conventions
|
||||
- Role preset visualizations
|
||||
- Security boundaries
|
||||
- **For understanding** - Visual learners start here
|
||||
|
||||
## 🗄️ Database Models
|
||||
|
||||
### **user_model_improved.py**
|
||||
Updated User model with:
|
||||
- Clarified role field (admin/vendor only)
|
||||
- Email verification field
|
||||
- Helper methods for permission checking
|
||||
- Owner/member checking methods
|
||||
- Vendor-specific role retrieval
|
||||
|
||||
**Where to integrate:** Replace/update your `models/database/user.py`
|
||||
|
||||
### **vendor_user_improved.py**
|
||||
Enhanced VendorUser model with:
|
||||
- `user_type` field (owner/member distinction)
|
||||
- Invitation system fields
|
||||
- Permission checking methods
|
||||
- Owner identification
|
||||
|
||||
**Where to integrate:** Update your `models/database/vendor.py` (VendorUser class)
|
||||
|
||||
## 🔐 Permission System
|
||||
|
||||
### **permissions.py**
|
||||
Complete permission system including:
|
||||
- `VendorPermissions` enum (all available permissions)
|
||||
- `PermissionGroups` class (preset role configurations)
|
||||
- `PermissionChecker` utility class
|
||||
- Helper functions
|
||||
|
||||
**Where to integrate:** Create as `app/core/permissions.py`
|
||||
|
||||
## ⚠️ Exception Handling
|
||||
|
||||
### **vendor_exceptions.py**
|
||||
Vendor-specific exceptions:
|
||||
- `VendorAccessDeniedException`
|
||||
- `InsufficientVendorPermissionsException`
|
||||
- `VendorOwnerOnlyException`
|
||||
- `CannotRemoveVendorOwnerException`
|
||||
- `TeamMemberAlreadyExistsException`
|
||||
- `InvalidInvitationTokenException`
|
||||
- And more...
|
||||
|
||||
**Where to integrate:** Add to your `app/exceptions/` directory
|
||||
|
||||
## 🛠️ Dependencies & Route Guards
|
||||
|
||||
### **deps_permissions.py**
|
||||
FastAPI dependencies for permission checking:
|
||||
- `require_vendor_permission(permission)`
|
||||
- `require_vendor_owner()`
|
||||
- `require_any_vendor_permission(*permissions)`
|
||||
- `require_all_vendor_permissions(*permissions)`
|
||||
- `get_user_permissions()`
|
||||
|
||||
**Where to integrate:** Add to your existing `app/api/deps.py`
|
||||
|
||||
## 🔧 Service Layer
|
||||
|
||||
### **vendor_team_service.py**
|
||||
Complete team management service:
|
||||
- `invite_team_member()` - Send team invitations
|
||||
- `accept_invitation()` - Activate invited accounts
|
||||
- `remove_team_member()` - Remove team members
|
||||
- `update_member_role()` - Change member roles
|
||||
- `get_team_members()` - List all team members
|
||||
- Helper methods for token generation and role management
|
||||
|
||||
**Where to integrate:** Create as `app/services/vendor_team_service.py`
|
||||
|
||||
## 📡 API Routes
|
||||
|
||||
### **team_routes_example.py**
|
||||
Complete team management API routes:
|
||||
- GET `/team/members` - List team members
|
||||
- POST `/team/invite` - Invite new member
|
||||
- POST `/team/accept-invitation` - Accept invitation
|
||||
- DELETE `/team/members/{user_id}` - Remove member
|
||||
- PUT `/team/members/{user_id}/role` - Update member role
|
||||
- GET `/team/me/permissions` - Get current user permissions
|
||||
- Example product routes with permission checks
|
||||
|
||||
**Where to integrate:** Create as `app/api/v1/vendor/team.py`
|
||||
|
||||
## 🗃️ Database Migration
|
||||
|
||||
### **rbac_migration_guide.md**
|
||||
Comprehensive migration guide:
|
||||
- Schema changes required
|
||||
- Alembic migration script
|
||||
- Data migration steps (6 steps with SQL)
|
||||
- Post-migration checklist
|
||||
- Verification queries
|
||||
- Rollback plan
|
||||
|
||||
**Use this:** Before deploying to production
|
||||
|
||||
## 📊 File Structure
|
||||
|
||||
```
|
||||
your-project/
|
||||
│
|
||||
├── app/
|
||||
│ ├── api/
|
||||
│ │ ├── deps.py ← Add deps_permissions.py content
|
||||
│ │ └── v1/
|
||||
│ │ ├── admin/
|
||||
│ │ └── vendor/
|
||||
│ │ └── team.py ← Add team_routes_example.py
|
||||
│ │
|
||||
│ ├── core/
|
||||
│ │ └── permissions.py ← Add permissions.py
|
||||
│ │
|
||||
│ ├── exceptions/
|
||||
│ │ └── vendor.py ← Add vendor_exceptions.py content
|
||||
│ │
|
||||
│ └── services/
|
||||
│ └── vendor_team_service.py ← Add vendor_team_service.py
|
||||
│
|
||||
└── models/
|
||||
└── database/
|
||||
├── user.py ← Update with user_model_improved.py
|
||||
└── vendor.py ← Update VendorUser from vendor_user_improved.py
|
||||
```
|
||||
|
||||
## 🚀 Quick Start Integration
|
||||
|
||||
### Step 1: Review & Plan (30 minutes)
|
||||
1. Read `RBAC_IMPLEMENTATION_SUMMARY.md`
|
||||
2. Review `RBAC_VISUAL_GUIDE.md` for architecture
|
||||
3. Check your current codebase against recommendations
|
||||
|
||||
### Step 2: Database Migration (1-2 hours)
|
||||
1. Follow `rbac_migration_guide.md`
|
||||
2. Create Alembic migration
|
||||
3. Test in development environment
|
||||
4. Run migration
|
||||
|
||||
### Step 3: Integrate Models (1 hour)
|
||||
1. Update `models/database/user.py` with improved User model
|
||||
2. Update `models/database/vendor.py` with improved VendorUser
|
||||
3. Test model loading
|
||||
|
||||
### Step 4: Add Permission System (30 minutes)
|
||||
1. Create `app/core/permissions.py`
|
||||
2. Import in your application
|
||||
3. Test permission constants
|
||||
|
||||
### Step 5: Add Exceptions (15 minutes)
|
||||
1. Add vendor exceptions to `app/exceptions/`
|
||||
2. Import in relevant modules
|
||||
|
||||
### Step 6: Add Dependencies (30 minutes)
|
||||
1. Add permission checking functions to `app/api/deps.py`
|
||||
2. Test dependencies work
|
||||
|
||||
### Step 7: Add Service Layer (30 minutes)
|
||||
1. Create `app/services/vendor_team_service.py`
|
||||
2. Test service methods
|
||||
|
||||
### Step 8: Add Routes (30 minutes)
|
||||
1. Create team management routes
|
||||
2. Add permission checks to existing routes
|
||||
3. Test all endpoints
|
||||
|
||||
### Step 9: Frontend Integration (2-4 hours)
|
||||
1. Update login flow to fetch permissions
|
||||
2. Add UI elements for team management
|
||||
3. Show/hide features based on permissions
|
||||
4. Create invitation acceptance page
|
||||
|
||||
### Step 10: Testing (2-3 hours)
|
||||
1. Test all permission combinations
|
||||
2. Test invitation flow
|
||||
3. Test owner protections
|
||||
4. Test admin blocking
|
||||
5. Test multi-vendor access
|
||||
|
||||
## 📝 Implementation Notes
|
||||
|
||||
### Priority Changes (Must Do)
|
||||
|
||||
1. **User.role clarification** - Critical for security
|
||||
2. **VendorUser.user_type** - Required for owner distinction
|
||||
3. **Permission checking in routes** - Security requirement
|
||||
4. **Invitation system** - Required for team management
|
||||
|
||||
### Optional Enhancements
|
||||
|
||||
1. **Custom permissions UI** - Allow owners to create custom roles
|
||||
2. **Permission analytics** - Track permission usage
|
||||
3. **Team activity logs** - Audit trail for team actions
|
||||
4. **Email templates** - Professional invitation emails
|
||||
|
||||
## 🆘 Support & Questions
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Q: Migration fails?**
|
||||
A: Check the verification queries in the migration guide. Likely data inconsistency.
|
||||
|
||||
**Q: Permission checking not working?**
|
||||
A: Ensure middleware sets `request.state.vendor` correctly.
|
||||
|
||||
**Q: Owner can't access routes?**
|
||||
A: Check that owner has `VendorUser` entry with `user_type='owner'`.
|
||||
|
||||
**Q: Invitation emails not sending?**
|
||||
A: Implement `_send_invitation_email()` in service (marked as TODO).
|
||||
|
||||
### Next Steps for You
|
||||
|
||||
1. ✅ Review all documentation
|
||||
2. ✅ Plan integration timeline
|
||||
3. ✅ Set up development environment
|
||||
4. ✅ Run database migration in dev
|
||||
5. ✅ Integrate code changes
|
||||
6. ✅ Test thoroughly
|
||||
7. ✅ Deploy to staging
|
||||
8. ✅ User acceptance testing
|
||||
9. ✅ Deploy to production
|
||||
|
||||
## 📞 Your Questions Answered
|
||||
|
||||
Based on your original question:
|
||||
|
||||
**✅ Admin Creation:** Admins created by super admins on backend *(already correct)*
|
||||
|
||||
**✅ Vendor Owner Creation:** Auto-created when vendor is created *(implement in vendor creation logic)*
|
||||
|
||||
**✅ Team Member Invitation:** Email-based invitation system *(vendor_team_service.py provides this)*
|
||||
|
||||
**✅ Customer Registration:** Self-registration on shop *(separate Customer model is correct)*
|
||||
|
||||
**✅ Role-Based Access:** Full RBAC system *(permissions.py + dependencies)*
|
||||
|
||||
**✅ Multi-Tenant Isolation:** Vendor-scoped roles and permissions *(VendorUser + Role models)*
|
||||
|
||||
## 🎉 You're Ready!
|
||||
|
||||
You now have everything needed to implement a production-ready RBAC system. All code is written, tested patterns are provided, and comprehensive documentation is included.
|
||||
|
||||
Good luck with your implementation! 🚀
|
||||
2529
docs/__REVAMPING/RBAC/RBAC_DEVELOPER_GUIDE.md
Normal file
2529
docs/__REVAMPING/RBAC/RBAC_DEVELOPER_GUIDE.md
Normal file
File diff suppressed because it is too large
Load Diff
474
docs/__REVAMPING/RBAC/RBAC_IMPLEMENTATION_SUMMARY.md
Normal file
474
docs/__REVAMPING/RBAC/RBAC_IMPLEMENTATION_SUMMARY.md
Normal file
@@ -0,0 +1,474 @@
|
||||
# RBAC Implementation Recommendations - Summary
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Your current authentication and authorization system is well-structured. Here are my recommendations to enhance it for proper role-based access control (RBAC) in your multi-tenant e-commerce platform.
|
||||
|
||||
## Key Recommendations
|
||||
|
||||
### 1. ✅ Clarify User.role Field
|
||||
|
||||
**Current Issue:** The `User.role` field is used for both platform-level and vendor-specific roles.
|
||||
|
||||
**Solution:**
|
||||
- `User.role` should ONLY contain: `"admin"` or `"vendor"`
|
||||
- Vendor-specific roles (manager, staff, etc.) belong in `VendorUser.role`
|
||||
- Customers are separate in the `Customer` model (already correct)
|
||||
|
||||
**Benefits:**
|
||||
- Clear separation of concerns
|
||||
- Easier to manage platform-level access
|
||||
- Prevents confusion between contexts
|
||||
|
||||
### 2. ✅ Add VendorUser.user_type Field
|
||||
|
||||
**Why:** Distinguish between vendor owners and team members at the database level.
|
||||
|
||||
**Implementation:**
|
||||
```python
|
||||
class VendorUserType(str, enum.Enum):
|
||||
OWNER = "owner"
|
||||
TEAM_MEMBER = "member"
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Owners have automatic full permissions
|
||||
- Team members use role-based permissions
|
||||
- Easy to query for owners vs. members
|
||||
- Prevents accidentally removing owners
|
||||
|
||||
### 3. ✅ Implement Invitation System
|
||||
|
||||
**Components Needed:**
|
||||
- `invitation_token` field in VendorUser
|
||||
- `invitation_sent_at` and `invitation_accepted_at` timestamps
|
||||
- Email sending service
|
||||
- Invitation acceptance endpoint
|
||||
|
||||
**Flow:**
|
||||
1. Owner invites team member via email
|
||||
2. System creates User account (inactive) and VendorUser (pending)
|
||||
3. Invitation email sent with unique token
|
||||
4. Team member clicks link, sets password, activates account
|
||||
5. VendorUser.is_active set to True
|
||||
|
||||
### 4. ✅ Define Permission Constants
|
||||
|
||||
**Create:** `app/core/permissions.py` with:
|
||||
- `VendorPermissions` enum (all available permissions)
|
||||
- `PermissionGroups` class (preset role permissions)
|
||||
- `PermissionChecker` utility class
|
||||
|
||||
**Example Permissions:**
|
||||
```python
|
||||
PRODUCTS_VIEW = "products.view"
|
||||
PRODUCTS_CREATE = "products.create"
|
||||
PRODUCTS_DELETE = "products.delete"
|
||||
ORDERS_VIEW = "orders.view"
|
||||
TEAM_INVITE = "team.invite" # Owner only
|
||||
SETTINGS_EDIT = "settings.edit" # Owner/Manager only
|
||||
```
|
||||
|
||||
### 5. ✅ Add Permission Checking Dependencies
|
||||
|
||||
**Create FastAPI dependencies:**
|
||||
- `require_vendor_permission(permission)` - Single permission
|
||||
- `require_vendor_owner()` - Owner only
|
||||
- `require_any_vendor_permission(*permissions)` - Any of list
|
||||
- `require_all_vendor_permissions(*permissions)` - All of list
|
||||
- `get_user_permissions()` - Get user's permission list
|
||||
|
||||
**Usage in Routes:**
|
||||
```python
|
||||
@router.post("/products")
|
||||
def create_product(
|
||||
user: User = Depends(require_vendor_permission("products.create"))
|
||||
):
|
||||
# User verified to have products.create permission
|
||||
...
|
||||
```
|
||||
|
||||
### 6. ✅ Create Vendor Team Service
|
||||
|
||||
**Service Responsibilities:**
|
||||
- `invite_team_member()` - Send invitations
|
||||
- `accept_invitation()` - Activate accounts
|
||||
- `remove_team_member()` - Deactivate members
|
||||
- `update_member_role()` - Change permissions
|
||||
- `get_team_members()` - List team
|
||||
|
||||
**Why Service Layer:**
|
||||
- Business logic separate from routes
|
||||
- Reusable across different contexts
|
||||
- Easier to test
|
||||
- Consistent error handling
|
||||
|
||||
### 7. ✅ Add Helper Methods to Models
|
||||
|
||||
**User Model:**
|
||||
```python
|
||||
@property
|
||||
def is_admin(self) -> bool
|
||||
def is_owner_of(self, vendor_id: int) -> bool
|
||||
def is_member_of(self, vendor_id: int) -> bool
|
||||
def get_vendor_role(self, vendor_id: int) -> str
|
||||
def has_vendor_permission(self, vendor_id: int, permission: str) -> bool
|
||||
```
|
||||
|
||||
**VendorUser Model:**
|
||||
```python
|
||||
@property
|
||||
def is_owner(self) -> bool
|
||||
def has_permission(self, permission: str) -> bool
|
||||
def get_all_permissions(self) -> list
|
||||
```
|
||||
|
||||
### 8. ✅ Enhanced Exception Handling
|
||||
|
||||
**Add Vendor-Specific Exceptions:**
|
||||
- `VendorAccessDeniedException` - No access to vendor
|
||||
- `InsufficientVendorPermissionsException` - Missing permission
|
||||
- `VendorOwnerOnlyException` - Owner-only operation
|
||||
- `CannotRemoveVendorOwnerException` - Prevent owner removal
|
||||
- `InvalidInvitationTokenException` - Bad invitation
|
||||
- `MaxTeamMembersReachedException` - Team size limit
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Platform Level │
|
||||
│ User.role: "admin" or "vendor" │
|
||||
│ - Admins: Full platform access │
|
||||
│ - Vendors: Access to their vendor(s) │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Vendor Level │
|
||||
│ VendorUser.user_type: "owner" or "member" │
|
||||
│ - Owners: Full vendor access (all permissions) │
|
||||
│ - Members: Role-based access (limited permissions) │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Role Level │
|
||||
│ Role.permissions: ["products.view", ...] │
|
||||
│ - Presets: Manager, Staff, Support, Viewer, Marketing │
|
||||
│ - Custom: Owner can define custom roles │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Permission Hierarchy
|
||||
|
||||
```
|
||||
Owner (VendorUser.user_type = "owner")
|
||||
└─> ALL permissions automatically
|
||||
|
||||
Team Member (VendorUser.user_type = "member")
|
||||
└─> Role.permissions (from VendorUser.role_id)
|
||||
├─> Manager: Most permissions except critical settings/team
|
||||
├─> Staff: Products, orders, customers (read/write)
|
||||
├─> Support: Orders, customers (support focus)
|
||||
├─> Viewer: Read-only access
|
||||
└─> Custom: Owner-defined permission sets
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### 1. **Cookie Path Isolation** (Already Implemented ✓)
|
||||
- Admin: `/admin` path
|
||||
- Vendor: `/vendor` path
|
||||
- Customer: `/shop` path
|
||||
- Prevents cross-context cookie leakage
|
||||
|
||||
### 2. **Role Checking at Route Level**
|
||||
```python
|
||||
# Good - Check at route definition
|
||||
@router.post("/products")
|
||||
def create_product(
|
||||
user: User = Depends(require_vendor_permission("products.create"))
|
||||
):
|
||||
...
|
||||
|
||||
# Bad - Check inside handler
|
||||
@router.post("/products")
|
||||
def create_product(user: User):
|
||||
if not has_permission(...): # Don't do this
|
||||
raise Exception()
|
||||
```
|
||||
|
||||
### 3. **Block Admin from Vendor Routes**
|
||||
```python
|
||||
# In vendor auth endpoints
|
||||
if user.role == "admin":
|
||||
raise InvalidCredentialsException(
|
||||
"Admins cannot access vendor portal"
|
||||
)
|
||||
```
|
||||
|
||||
### 4. **Owner Cannot Be Removed**
|
||||
```python
|
||||
if vendor_user.is_owner:
|
||||
raise CannotRemoveVendorOwnerException(vendor.vendor_code)
|
||||
```
|
||||
|
||||
### 5. **Inactive Users Have No Permissions**
|
||||
```python
|
||||
if not user.is_active or not vendor_user.is_active:
|
||||
return False # No permissions
|
||||
```
|
||||
|
||||
## Frontend Integration
|
||||
|
||||
### 1. **Get User Permissions on Load**
|
||||
```javascript
|
||||
// On vendor dashboard load
|
||||
const response = await fetch('/api/v1/vendor/team/me/permissions');
|
||||
const { permissions } = await response.json();
|
||||
|
||||
// Store in state
|
||||
localStorage.setItem('permissions', JSON.stringify(permissions));
|
||||
```
|
||||
|
||||
### 2. **Show/Hide UI Elements**
|
||||
```javascript
|
||||
// Check permission before rendering
|
||||
function canViewProducts() {
|
||||
const permissions = JSON.parse(localStorage.getItem('permissions'));
|
||||
return permissions.includes('products.view');
|
||||
}
|
||||
|
||||
// In template
|
||||
{canViewProducts() && <ProductsList />}
|
||||
```
|
||||
|
||||
### 3. **Disable Actions Without Permission**
|
||||
```javascript
|
||||
<button
|
||||
disabled={!permissions.includes('products.delete')}
|
||||
onClick={handleDelete}
|
||||
>
|
||||
Delete Product
|
||||
</button>
|
||||
```
|
||||
|
||||
## Database Schema Summary
|
||||
|
||||
```
|
||||
users
|
||||
├── id (PK)
|
||||
├── email (unique)
|
||||
├── username (unique)
|
||||
├── role ('admin' | 'vendor') ← Platform role only
|
||||
├── is_active
|
||||
└── is_email_verified ← New field
|
||||
|
||||
vendors
|
||||
├── id (PK)
|
||||
├── vendor_code (unique)
|
||||
├── owner_user_id (FK → users.id)
|
||||
└── ...
|
||||
|
||||
vendor_users (junction table with role info)
|
||||
├── id (PK)
|
||||
├── vendor_id (FK → vendors.id)
|
||||
├── user_id (FK → users.id)
|
||||
├── user_type ('owner' | 'member') ← New field
|
||||
├── role_id (FK → roles.id, nullable) ← NULL for owners
|
||||
├── invitation_token ← New field
|
||||
├── invitation_sent_at ← New field
|
||||
├── invitation_accepted_at ← New field
|
||||
└── is_active
|
||||
|
||||
roles (vendor-specific)
|
||||
├── id (PK)
|
||||
├── vendor_id (FK → vendors.id)
|
||||
├── name (e.g., 'Manager', 'Staff')
|
||||
└── permissions (JSON: ["products.view", ...])
|
||||
|
||||
customers (separate, vendor-scoped)
|
||||
├── id (PK)
|
||||
├── vendor_id (FK → vendors.id)
|
||||
├── email (unique within vendor)
|
||||
└── ... (separate auth from User)
|
||||
```
|
||||
|
||||
## Implementation Checklist
|
||||
|
||||
### Phase 1: Database & Models
|
||||
- [ ] Add `is_email_verified` to User model
|
||||
- [ ] Update User.role to only accept 'admin'/'vendor'
|
||||
- [ ] Add `user_type` to VendorUser model
|
||||
- [ ] Add invitation fields to VendorUser
|
||||
- [ ] Make VendorUser.role_id nullable
|
||||
- [ ] Create permissions.py with constants
|
||||
- [ ] Add helper methods to User model
|
||||
- [ ] Add helper methods to VendorUser model
|
||||
- [ ] Run database migration
|
||||
|
||||
### Phase 2: Services & Logic
|
||||
- [ ] Create vendor_team_service.py
|
||||
- [ ] Implement invite_team_member()
|
||||
- [ ] Implement accept_invitation()
|
||||
- [ ] Implement remove_team_member()
|
||||
- [ ] Implement update_member_role()
|
||||
- [ ] Add vendor-specific exceptions
|
||||
- [ ] Set up email sending for invitations
|
||||
|
||||
### Phase 3: API & Dependencies
|
||||
- [ ] Add permission checking dependencies to deps.py
|
||||
- [ ] Update vendor auth endpoint to block admins
|
||||
- [ ] Create team management routes
|
||||
- [ ] Add permission checks to existing routes
|
||||
- [ ] Create invitation acceptance endpoint (public)
|
||||
- [ ] Add /me/permissions endpoint
|
||||
|
||||
### Phase 4: Testing
|
||||
- [ ] Test owner has all permissions
|
||||
- [ ] Test team members respect role permissions
|
||||
- [ ] Test invitation flow end-to-end
|
||||
- [ ] Test cannot remove owner
|
||||
- [ ] Test admin blocked from vendor routes
|
||||
- [ ] Test permission checking in all routes
|
||||
- [ ] Test inactive users have no access
|
||||
|
||||
### Phase 5: Frontend
|
||||
- [ ] Load user permissions on login
|
||||
- [ ] Show/hide UI based on permissions
|
||||
- [ ] Implement invitation acceptance page
|
||||
- [ ] Add team management UI (owner only)
|
||||
- [ ] Add role selector when inviting
|
||||
- [ ] Show permission lists for roles
|
||||
|
||||
## Migration Steps
|
||||
|
||||
1. **Backup database**
|
||||
2. **Run Alembic migration** (see migration guide)
|
||||
3. **Update User roles** (convert 'user' to 'vendor')
|
||||
4. **Set vendor owners** in vendor_users
|
||||
5. **Create default roles** for all vendors
|
||||
6. **Assign roles** to existing team members
|
||||
7. **Verify migration** with SQL queries
|
||||
8. **Test system** thoroughly
|
||||
9. **Deploy** to production
|
||||
|
||||
## Common Pitfalls to Avoid
|
||||
|
||||
### ❌ Don't: Mix Platform and Vendor Roles
|
||||
```python
|
||||
# Bad
|
||||
user.role = "manager" # Vendor role in User table
|
||||
```
|
||||
|
||||
```python
|
||||
# Good
|
||||
user.role = "vendor" # Platform role
|
||||
vendor_user.role.name = "manager" # Vendor role
|
||||
```
|
||||
|
||||
### ❌ Don't: Check Permissions in Business Logic
|
||||
```python
|
||||
# Bad
|
||||
def create_product(user, product_data):
|
||||
if not has_permission(user, "products.create"):
|
||||
raise Exception()
|
||||
# ... create product
|
||||
```
|
||||
|
||||
```python
|
||||
# Good
|
||||
@router.post("/products")
|
||||
def create_product(
|
||||
product_data: ProductCreate,
|
||||
user: User = Depends(require_vendor_permission("products.create"))
|
||||
):
|
||||
# Permission already checked by dependency
|
||||
return service.create_product(user, product_data)
|
||||
```
|
||||
|
||||
### ❌ Don't: Allow Owner Removal
|
||||
```python
|
||||
# Bad
|
||||
def remove_team_member(vendor, user_id):
|
||||
vendor_user = get_vendor_user(vendor, user_id)
|
||||
vendor_user.is_active = False
|
||||
```
|
||||
|
||||
```python
|
||||
# Good
|
||||
def remove_team_member(vendor, user_id):
|
||||
vendor_user = get_vendor_user(vendor, user_id)
|
||||
if vendor_user.is_owner:
|
||||
raise CannotRemoveVendorOwnerException(vendor.vendor_code)
|
||||
vendor_user.is_active = False
|
||||
```
|
||||
|
||||
### ❌ Don't: Forget to Check is_active
|
||||
```python
|
||||
# Bad
|
||||
def has_permission(user, vendor_id, permission):
|
||||
return permission in user.get_vendor_role(vendor_id).permissions
|
||||
```
|
||||
|
||||
```python
|
||||
# Good
|
||||
def has_permission(user, vendor_id, permission):
|
||||
if not user.is_active:
|
||||
return False
|
||||
|
||||
vendor_user = get_vendor_user(user, vendor_id)
|
||||
if not vendor_user or not vendor_user.is_active:
|
||||
return False
|
||||
|
||||
return vendor_user.has_permission(permission)
|
||||
```
|
||||
|
||||
## Questions & Answers
|
||||
|
||||
**Q: Can a user be a team member of multiple vendors?**
|
||||
A: Yes! A user can have multiple VendorUser entries, one per vendor. Each has independent role/permissions.
|
||||
|
||||
**Q: Can a vendor have multiple owners?**
|
||||
A: No. Each vendor has one owner (Vendor.owner_user_id). The owner can delegate management via Manager role, but there's only one true owner.
|
||||
|
||||
**Q: What happens to team members when owner changes?**
|
||||
A: Team members remain. Update Vendor.owner_user_id and both old/new owner's VendorUser.user_type.
|
||||
|
||||
**Q: Can admins access vendor dashboards?**
|
||||
A: No. Admins are blocked from vendor routes. This is intentional security.
|
||||
|
||||
**Q: How do customers authenticate?**
|
||||
A: Customers use the Customer model with separate authentication. They're vendor-scoped and can't access vendor/admin areas.
|
||||
|
||||
**Q: Can permissions be customized per team member?**
|
||||
A: Yes! When inviting, pass `custom_permissions` array to override role presets.
|
||||
|
||||
**Q: How do invitation links work?**
|
||||
A: Invitation token is a secure random string stored in VendorUser. Link format: `/vendor/invitation/accept?token=<token>`. Token is single-use and expires in 7 days.
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Review all generated files in `/home/claude/`
|
||||
2. Integrate changes into your codebase
|
||||
3. Create and run database migration
|
||||
4. Update existing routes with permission checks
|
||||
5. Implement team management UI
|
||||
6. Test thoroughly in development
|
||||
7. Deploy to staging for user acceptance testing
|
||||
8. Deploy to production with monitoring
|
||||
|
||||
## Support
|
||||
|
||||
All implementation files have been created in `/home/claude/`:
|
||||
- `user_model_improved.py` - Updated User model
|
||||
- `vendor_user_improved.py` - Updated VendorUser model
|
||||
- `permissions.py` - Permission system
|
||||
- `vendor_exceptions.py` - Vendor exceptions
|
||||
- `deps_permissions.py` - Permission dependencies
|
||||
- `vendor_team_service.py` - Team management service
|
||||
- `team_routes_example.py` - Example routes
|
||||
- `rbac_migration_guide.md` - Database migration guide
|
||||
|
||||
These are ready to be integrated into your project structure.
|
||||
513
docs/__REVAMPING/RBAC/RBAC_QUICK_REFERENCE.md
Normal file
513
docs/__REVAMPING/RBAC/RBAC_QUICK_REFERENCE.md
Normal file
@@ -0,0 +1,513 @@
|
||||
# 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') && (
|
||||
<CreateButton />
|
||||
)}
|
||||
|
||||
// Disable button
|
||||
<button disabled={!hasPermission('products.edit')}>
|
||||
Edit
|
||||
</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.md`
|
||||
316
docs/__REVAMPING/RBAC/RBAC_VISUAL_GUIDE.md
Normal file
316
docs/__REVAMPING/RBAC/RBAC_VISUAL_GUIDE.md
Normal file
@@ -0,0 +1,316 @@
|
||||
# RBAC Architecture Visual Guide
|
||||
|
||||
## System Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ PLATFORM LEVEL │
|
||||
│ │
|
||||
│ ┌──────────────────┐ ┌──────────────────┐ │
|
||||
│ │ Admin Users │ │ Vendor Users │ │
|
||||
│ │ role="admin" │ │ role="vendor" │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ • Full platform │ │ • Can own/join │ │
|
||||
│ │ access │ │ vendors │ │
|
||||
│ │ • Cannot access │ │ • Cannot access │ │
|
||||
│ │ vendor portal │ │ admin portal │ │
|
||||
│ └──────────────────┘ └──────────────────┘ │
|
||||
│ │ │
|
||||
└──────────────────────────────────────────────┼──────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ VENDOR LEVEL │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||
│ │ Vendor: ACME │ │
|
||||
│ │ │ │
|
||||
│ │ ┌──────────────┐ ┌──────────────────────┐ │ │
|
||||
│ │ │ Owner │ │ Team Members │ │ │
|
||||
│ │ │ user_type= │ │ user_type= │ │ │
|
||||
│ │ │ "owner" │ │ "member" │ │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ │ • All perms │ │ • Role-based perms │ │ │
|
||||
│ │ │ • Can invite │ │ • Manager/Staff/etc │ │ │
|
||||
│ │ │ • Can remove │ │ • Can be invited │ │ │
|
||||
│ │ │ • Cannot be │ │ • Can be removed │ │ │
|
||||
│ │ │ removed │ │ │ │ │
|
||||
│ │ └──────────────┘ └──────────────────────┘ │ │
|
||||
│ │ │ │ │
|
||||
│ │ ▼ │ │
|
||||
│ │ ┌──────────────────────────────┐ │ │
|
||||
│ │ │ Roles │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ • Manager (many perms) │ │ │
|
||||
│ │ │ • Staff (moderate perms) │ │ │
|
||||
│ │ │ • Support (limited perms) │ │ │
|
||||
│ │ │ • Viewer (read-only) │ │ │
|
||||
│ │ │ • Custom (owner-defined) │ │ │
|
||||
│ │ └──────────────────────────────┘ │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ CUSTOMER LEVEL │
|
||||
│ (Separate from Users) │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||
│ │ Customers (per vendor) │ │
|
||||
│ │ │ │
|
||||
│ │ • Vendor-scoped authentication │ │
|
||||
│ │ • Can self-register │ │
|
||||
│ │ • Access own account + shop catalog │ │
|
||||
│ │ • Cannot access admin/vendor portals │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Team Invitation Flow
|
||||
|
||||
```
|
||||
┌──────────┐
|
||||
│ Owner │
|
||||
│ (ACME) │
|
||||
└────┬─────┘
|
||||
│
|
||||
│ 1. Click "Invite Team Member"
|
||||
│ Email: jane@example.com
|
||||
│ Role: Manager
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ System Creates: │
|
||||
│ • User account │
|
||||
│ • VendorUser │
|
||||
│ • 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 │
|
||||
│ • VendorUser. │
|
||||
│ is_active │
|
||||
└────┬────────────────┘
|
||||
│
|
||||
│ 4. Jane can now login
|
||||
│
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ Jane logs in to │
|
||||
│ ACME vendor portal │
|
||||
│ with Manager perms │
|
||||
└──────────────────────┘
|
||||
```
|
||||
|
||||
## Permission Check Flow
|
||||
|
||||
```
|
||||
┌────────────────┐
|
||||
│ User makes │
|
||||
│ request to: │
|
||||
│ POST /products │
|
||||
└───────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────────────────────┐
|
||||
│ FastAPI Dependency: │
|
||||
│ require_vendor_permission( │
|
||||
│ "products.create" │
|
||||
│ ) │
|
||||
└───────┬────────────────────────┘
|
||||
│
|
||||
│ 1. Get vendor from request.state
|
||||
│ 2. Get user from JWT
|
||||
│
|
||||
▼
|
||||
┌────────────────────────────────┐
|
||||
│ Is user a member of vendor? │
|
||||
└───────┬────────────────────────┘
|
||||
│
|
||||
├─ No ──> ❌ VendorAccessDeniedException
|
||||
│
|
||||
▼ Yes
|
||||
┌────────────────────────────────┐
|
||||
│ Is user the owner? │
|
||||
└───────┬────────────────────────┘
|
||||
│
|
||||
├─ Yes ──> ✅ Allow (owners have all perms)
|
||||
│
|
||||
▼ No
|
||||
┌────────────────────────────────┐
|
||||
│ Get user's role and │
|
||||
│ permissions from VendorUser │
|
||||
└───────┬────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────────────────────┐
|
||||
│ Does role contain │
|
||||
│ "products.create"? │
|
||||
└───────┬────────────────────────┘
|
||||
│
|
||||
├─ No ──> ❌ InsufficientVendorPermissionsException
|
||||
│
|
||||
▼ Yes
|
||||
┌────────────────────────────────┐
|
||||
│ ✅ Allow request │
|
||||
│ Handler executes │
|
||||
└────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Database Relationships
|
||||
|
||||
```
|
||||
┌──────────────────┐
|
||||
│ users │
|
||||
│ │
|
||||
│ id (PK) │◄────┐
|
||||
│ email │ │
|
||||
│ role │ │
|
||||
│ ('admin' or │ │
|
||||
│ 'vendor') │ │
|
||||
└──────────────────┘ │
|
||||
│ │
|
||||
│ owner_user_id │
|
||||
│ │
|
||||
▼ │
|
||||
┌──────────────────┐ │
|
||||
│ vendors │ │
|
||||
│ │ │
|
||||
│ id (PK) │ │
|
||||
│ vendor_code │ │
|
||||
│ owner_user_id ──┼─────┘
|
||||
└──────────────────┘
|
||||
│
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ vendor_users │ │ roles │
|
||||
│ │ │ │
|
||||
│ id (PK) │ │ id (PK) │
|
||||
│ vendor_id (FK) │ │ vendor_id (FK) │
|
||||
│ user_id (FK) │ │ name │
|
||||
│ role_id (FK) ───┼────►│ permissions │
|
||||
│ user_type │ │ (JSON) │
|
||||
│ ('owner' or │ └──────────────────┘
|
||||
│ 'member') │
|
||||
│ invitation_* │
|
||||
│ is_active │
|
||||
└──────────────────┘
|
||||
|
||||
Separate hierarchy:
|
||||
|
||||
┌──────────────────┐
|
||||
│ customers │
|
||||
│ │
|
||||
│ id (PK) │
|
||||
│ vendor_id (FK) │
|
||||
│ email │
|
||||
│ hashed_password │
|
||||
│ (vendor-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
|
||||
|
||||
Admin → Vendor Portal Admin → Admin Portal
|
||||
Vendor → Admin Portal Vendor → Vendor Portal
|
||||
Customer → Admin Portal Customer → Shop Catalog
|
||||
Customer → Vendor Portal Customer → Own Account
|
||||
|
||||
Cookie Isolation:
|
||||
admin_token (path=/admin) ← Only sent to /admin/*
|
||||
vendor_token (path=/vendor) ← Only sent to /vendor/*
|
||||
customer_token (path=/shop) ← Only sent to /shop/*
|
||||
```
|
||||
Reference in New Issue
Block a user