10 KiB
Slice 1 Implementation Guide
Admin Creates Vendor → Vendor Owner Logs In
This guide provides complete instructions for implementing Slice 1 of the multi-tenant ecommerce platform.
✅ What We've Built
Backend Components
-
Enhanced Admin Service (
app/services/admin_service.py)create_vendor_with_owner()- Creates vendor + owner user + default roles- Generates secure temporary password
- Auto-verifies admin-created vendors
-
Enhanced Admin API (
app/api/v1/admin.py)POST /admin/vendors- Create vendor with ownerGET /admin/vendors- List vendors with filteringGET /admin/dashboard- Dashboard statisticsPUT /admin/vendors/{id}/verify- Verify vendorPUT /admin/vendors/{id}/status- Toggle vendor status
-
Vendor Schema Updates (
models/schemas/vendor.py)- Added
owner_emailfield toVendorCreate - Created
VendorCreateResponsewith credentials
- Added
-
Vendor Context Middleware (
middleware/vendor_context.py)- Subdomain detection (production)
- Path-based detection (development)
- Vendor isolation enforcement
Frontend Components
-
Admin Login Page (
static/admin/login.html)- Clean, modern UI
- JWT authentication
- Role validation (admin only)
-
Admin Dashboard (
static/admin/dashboard.html)- Statistics overview
- Recent vendors list
- Recent import jobs
- Navigation to all sections
-
Vendor Creation Page (
static/admin/vendors.html)- Complete vendor creation form
- Auto-formatting inputs
- Displays generated credentials
- One-time password display
-
API Client Utility (
static/js/shared/api-client.js)- Authenticated API calls
- Token management
- Error handling
- Utility functions
📋 Prerequisites
Before implementing Slice 1, ensure you have:
- ✅ PostgreSQL database running
- ✅ Python 3.11+ with FastAPI
- ✅ All dependencies installed (
pip install -r requirements.txt) - ✅
.envfile configured with database URL and JWT secret
🚀 Implementation Steps
Step 1: Update Database Models
Ensure your models/database/vendor.py includes:
class Vendor(Base, TimestampMixin):
__tablename__ = "vendors"
id = Column(Integer, primary_key=True, index=True)
vendor_code = Column(String, unique=True, nullable=False, index=True)
subdomain = Column(String(100), unique=True, nullable=False, index=True)
name = Column(String, nullable=False)
description = Column(Text)
owner_user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
# Business information
business_email = Column(String)
business_phone = Column(String)
contact_email = Column(String)
contact_phone = Column(String)
website = Column(String)
business_address = Column(Text)
tax_number = Column(String)
# Status flags
is_active = Column(Boolean, default=True)
is_verified = Column(Boolean, default=False)
verified_at = Column(DateTime, nullable=True)
# Theme and configuration
theme_config = Column(JSON, default=dict)
# CSV URLs for marketplace integration
letzshop_csv_url_fr = Column(String)
letzshop_csv_url_en = Column(String)
letzshop_csv_url_de = Column(String)
# Relationships
owner = relationship("User", back_populates="owned_vendors")
Step 2: Create Database Migration
Create a new Alembic migration:
# Generate migration
alembic revision --autogenerate -m "Add vendor and role tables for slice 1"
# Review the generated migration file
# Then apply it:
alembic upgrade head
Step 3: Create Default Admin User
Run the script to create initial admin:
# scripts/create_admin.py
from sqlalchemy.orm import Session
from app.core.database import SessionLocal
from middleware.auth import AuthManager
from models.database.user import User
def create_admin():
db = SessionLocal()
auth_manager = AuthManager()
# Check if admin exists
admin = db.query(User).filter(User.username == "admin").first()
if not admin:
admin = User(
email="admin@platform.com",
username="admin",
hashed_password=auth_manager.hash_password("admin123"),
role="admin",
is_active=True
)
db.add(admin)
db.commit()
print("✅ Admin user created:")
print(" Username: admin")
print(" Password: admin123")
print(" Email: admin@platform.com")
else:
print("ℹ️ Admin user already exists")
db.close()
if __name__ == "__main__":
create_admin()
Run it:
python scripts/create_admin.py
Step 4: Deploy Frontend Files
Ensure the following structure exists:
static/
├── admin/
│ ├── login.html
│ ├── dashboard.html
│ └── vendors.html
├── js/
│ └── shared/
│ └── api-client.js
└── css/
├── shared/
│ └── base.css
└── admin/
└── admin.css
Step 5: Update API Router
Ensure app/api/main.py includes admin routes:
from app.api.v1 import admin
api_router.include_router(
admin.router,
prefix="/admin",
tags=["admin"]
)
Step 6: Start the Application
# Start the server
uvicorn main:app --reload --port 8000
# Or with hot reload
python main.py
Step 7: Test the Flow
7.1 Admin Login
- Navigate to
http://localhost:8000/static/admin/login.html - Login with:
- Username:
admin - Password:
admin123
- Username:
- Should redirect to dashboard
7.2 Create Vendor
- Click "Create New Vendor" button
- Fill in the form:
- Vendor Code:
TECHSTORE - Name:
Tech Store Luxembourg - Subdomain:
techstore - Owner Email:
owner@techstore.com
- Vendor Code:
- Submit the form
- Save the displayed credentials!
7.3 Verify Vendor Creation
- Check database:
SELECT * FROM vendors WHERE vendor_code = 'TECHSTORE';
SELECT * FROM users WHERE email = 'owner@techstore.com';
SELECT * FROM roles WHERE vendor_id = (SELECT id FROM vendors WHERE vendor_code = 'TECHSTORE');
- Check admin dashboard - vendor should appear in "Recent Vendors"
🧪 Testing Checklist
Admin Interface Tests
- Admin can login with correct credentials
- Admin login rejects non-admin users
- Dashboard displays vendor statistics
- Dashboard displays user statistics
- Recent vendors list shows newest vendors
- Vendor creation form validates inputs
- Vendor code is auto-uppercased
- Subdomain is auto-lowercased
- Duplicate vendor code is rejected
- Duplicate subdomain is rejected
- Generated credentials are displayed once
- Admin can view all vendors
- Admin can verify/unverify vendors
- Admin can activate/deactivate vendors
Vendor Context Tests
- Subdomain detection works:
vendor.localhost:8000 - Path detection works:
localhost:8000/vendor/vendorname/ - Admin routes are excluded from vendor context
- API routes are excluded from vendor context
- Invalid vendor returns 404
Database Tests
- Vendor record created correctly
- Owner user record created
- Owner has correct relationship to vendor
- Default roles created (Owner, Manager, Editor, Viewer)
- Vendor is auto-verified when created by admin
- Timestamps are set correctly
🔐 Security Considerations
-
Password Security
- Temporary passwords are 12+ characters
- Include letters, numbers, and symbols
- Hashed with bcrypt before storage
- Displayed only once
-
Admin Access Control
- JWT token required for all admin endpoints
- Role validation on every request
- Token expiration enforced
-
Vendor Isolation
- Vendor context middleware enforces boundaries
- All queries filtered by vendor_id
- Cross-vendor access prevented
📝 Configuration
Environment Variables
# Database
DATABASE_URL=postgresql://user:pass@localhost:5432/dbname
# JWT
JWT_SECRET_KEY=your-secret-key-change-in-production
JWT_EXPIRE_MINUTES=30
# Server
SERVER_ADDRESS=http://localhost:8000
DEBUG=True
# Platform
PROJECT_NAME="Multi-Tenant Ecommerce Platform"
ALLOWED_HOSTS=["*"]
Development vs Production
Development Mode (path-based):
http://localhost:8000/vendor/techstore/
http://localhost:8000/admin/
Production Mode (subdomain-based):
https://techstore.platform.com/
https://admin.platform.com/
🐛 Troubleshooting
Issue: Admin login fails
Solution: Check that admin user exists and role is "admin"
python scripts/create_admin.py
Issue: Vendor creation returns 401
Solution: Check that JWT token is valid and not expired
// In browser console
localStorage.getItem('admin_token')
Issue: Vendor context not detected
Solution: Check middleware is registered in main.py:
app.middleware("http")(vendor_context_middleware)
Issue: Database foreign key error
Solution: Run migrations in correct order:
alembic upgrade head
📊 Success Metrics
Slice 1 is complete when:
- Admin can log into admin interface
- Admin can create new vendors
- System generates vendor owner credentials
- Vendor owner can log into vendor-specific interface
- Vendor context detection works in dev and production modes
- Database properly isolates vendor data
- All tests pass
- Documentation is complete
🎯 Next Steps - Slice 2
Once Slice 1 is complete and tested, proceed to Slice 2: Vendor Imports Products from Letzshop:
- Implement marketplace CSV import
- Create MarketplaceProduct staging table
- Build product import UI
- Add background job processing with Celery
- Create import job monitoring
💡 Tips
- Always test in order: Admin login → Vendor creation → Context detection
- Save credentials immediately: Password is shown only once
- Use browser dev tools: Check console for API errors
- Check database directly: Verify data is created correctly
- Test both detection modes: Path-based (dev) and subdomain (prod)