compiling project documentation

This commit is contained in:
2025-10-26 20:00:39 +01:00
parent 99863ad80b
commit 6746d0af37
10 changed files with 0 additions and 5519 deletions

View File

@@ -1,617 +0,0 @@
# Stripe Payment Integration - Multi-Tenant Ecommerce Platform
## Architecture Overview
The payment integration uses **Stripe Connect** to handle multi-vendor payments, enabling:
- Each vendor to receive payments directly
- Platform to collect fees/commissions
- Proper financial isolation between vendors
- Compliance with financial regulations
## Payment Models
### Database Models
```python
# models/database/payment.py
from decimal import Decimal
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey, Text, Numeric
from sqlalchemy.orm import relationship
from app.core.database import Base
from .base import TimestampMixin
class VendorPaymentConfig(Base, TimestampMixin):
"""Vendor-specific payment configuration."""
__tablename__ = "vendor_payment_configs"
id = Column(Integer, primary_key=True, index=True)
vendor_id = Column(Integer, ForeignKey("vendors.id"), nullable=False, unique=True)
# Stripe Connect configuration
stripe_account_id = Column(String(255)) # Stripe Connect account ID
stripe_account_status = Column(String(50)) # pending, active, restricted, inactive
stripe_onboarding_url = Column(Text) # Onboarding link for vendor
stripe_dashboard_url = Column(Text) # Vendor's Stripe dashboard
# Payment settings
accepts_payments = Column(Boolean, default=False)
currency = Column(String(3), default="EUR")
platform_fee_percentage = Column(Numeric(5, 2), default=2.5) # Platform commission
# Payout settings
payout_schedule = Column(String(20), default="weekly") # daily, weekly, monthly
minimum_payout = Column(Numeric(10, 2), default=20.00)
# Relationships
vendor = relationship("Vendor", back_populates="payment_config")
def __repr__(self):
return f"<VendorPaymentConfig(vendor_id={self.vendor_id}, stripe_account_id='{self.stripe_account_id}')>"
class Payment(Base, TimestampMixin):
"""Payment records for orders."""
__tablename__ = "payments"
id = Column(Integer, primary_key=True, index=True)
vendor_id = Column(Integer, ForeignKey("vendors.id"), nullable=False)
order_id = Column(Integer, ForeignKey("orders.id"), nullable=False)
customer_id = Column(Integer, ForeignKey("customers.id"), nullable=False)
# Stripe payment details
stripe_payment_intent_id = Column(String(255), unique=True, index=True)
stripe_charge_id = Column(String(255), index=True)
stripe_transfer_id = Column(String(255)) # Transfer to vendor account
# Payment amounts (in cents to avoid floating point issues)
amount_total = Column(Integer, nullable=False) # Total customer payment
amount_vendor = Column(Integer, nullable=False) # Amount to vendor
amount_platform_fee = Column(Integer, nullable=False) # Platform commission
currency = Column(String(3), default="EUR")
# Payment status
status = Column(String(50), nullable=False) # pending, succeeded, failed, refunded
payment_method = Column(String(50)) # card, bank_transfer, etc.
# Metadata
stripe_metadata = Column(Text) # JSON string of Stripe metadata
failure_reason = Column(Text)
refund_reason = Column(Text)
# Timestamps
paid_at = Column(DateTime)
refunded_at = Column(DateTime)
# Relationships
vendor = relationship("Vendor")
order = relationship("Order", back_populates="payment")
customer = relationship("Customer")
def __repr__(self):
return f"<Payment(id={self.id}, order_id={self.order_id}, status='{self.status}')>"
@property
def amount_total_euros(self):
"""Convert cents to euros for display."""
return self.amount_total / 100
@property
def amount_vendor_euros(self):
"""Convert cents to euros for display."""
return self.amount_vendor / 100
class PaymentMethod(Base, TimestampMixin):
"""Saved customer payment methods."""
__tablename__ = "payment_methods"
id = Column(Integer, primary_key=True, index=True)
vendor_id = Column(Integer, ForeignKey("vendors.id"), nullable=False)
customer_id = Column(Integer, ForeignKey("customers.id"), nullable=False)
# Stripe payment method details
stripe_payment_method_id = Column(String(255), nullable=False, index=True)
payment_method_type = Column(String(50), nullable=False) # card, sepa_debit, etc.
# Card details (if applicable)
card_brand = Column(String(50)) # visa, mastercard, etc.
card_last4 = Column(String(4))
card_exp_month = Column(Integer)
card_exp_year = Column(Integer)
# Settings
is_default = Column(Boolean, default=False)
is_active = Column(Boolean, default=True)
# Relationships
vendor = relationship("Vendor")
customer = relationship("Customer")
def __repr__(self):
return f"<PaymentMethod(id={self.id}, customer_id={self.customer_id}, type='{self.payment_method_type}')>"
```
### Updated Order Model
```python
# Update models/database/order.py
class Order(Base, TimestampMixin):
# ... existing fields ...
# Payment integration
payment_status = Column(String(50), default="pending") # pending, paid, failed, refunded
payment_intent_id = Column(String(255)) # Stripe PaymentIntent ID
total_amount_cents = Column(Integer, nullable=False) # Amount in cents
# Relationships
payment = relationship("Payment", back_populates="order", uselist=False)
@property
def total_amount_euros(self):
"""Convert cents to euros for display."""
return self.total_amount_cents / 100 if self.total_amount_cents else 0
```
## Payment Service Integration
### Stripe Service
```python
# services/payment_service.py
import stripe
import json
import logging
from decimal import Decimal
from typing import Dict, Optional
from sqlalchemy.orm import Session
from app.core.config import settings
from models.database.payment import Payment, VendorPaymentConfig
from models.database.order import Order
from models.database.vendor import Vendor
from app.exceptions.payment import *
logger = logging.getLogger(__name__)
# Configure Stripe
stripe.api_key = settings.stripe_secret_key
class PaymentService:
"""Service for handling Stripe payments in multi-tenant environment."""
def __init__(self, db: Session):
self.db = db
def create_payment_intent(
self,
vendor_id: int,
order_id: int,
amount_euros: Decimal,
customer_email: str,
metadata: Optional[Dict] = None
) -> Dict:
"""Create Stripe PaymentIntent for vendor order."""
# Get vendor payment configuration
payment_config = self.get_vendor_payment_config(vendor_id)
if not payment_config.accepts_payments:
raise PaymentNotConfiguredException(f"Vendor {vendor_id} not configured for payments")
# Calculate amounts
amount_cents = int(amount_euros * 100)
platform_fee_cents = int(amount_cents * (payment_config.platform_fee_percentage / 100))
vendor_amount_cents = amount_cents - platform_fee_cents
try:
# Create PaymentIntent with Stripe Connect
payment_intent = stripe.PaymentIntent.create(
amount=amount_cents,
currency=payment_config.currency.lower(),
application_fee_amount=platform_fee_cents,
transfer_data={
'destination': payment_config.stripe_account_id,
},
metadata={
'vendor_id': str(vendor_id),
'order_id': str(order_id),
'platform': 'multi_tenant_ecommerce',
**(metadata or {})
},
receipt_email=customer_email,
description=f"Order payment for vendor {vendor_id}"
)
# Create payment record
payment = Payment(
vendor_id=vendor_id,
order_id=order_id,
customer_id=self.get_order_customer_id(order_id),
stripe_payment_intent_id=payment_intent.id,
amount_total=amount_cents,
amount_vendor=vendor_amount_cents,
amount_platform_fee=platform_fee_cents,
currency=payment_config.currency,
status='pending',
stripe_metadata=json.dumps(payment_intent.metadata)
)
self.db.add(payment)
# Update order
order = self.db.query(Order).filter(Order.id == order_id).first()
if order:
order.payment_intent_id = payment_intent.id
order.payment_status = 'pending'
self.db.commit()
return {
'payment_intent_id': payment_intent.id,
'client_secret': payment_intent.client_secret,
'amount_total': amount_euros,
'amount_vendor': vendor_amount_cents / 100,
'platform_fee': platform_fee_cents / 100,
'currency': payment_config.currency
}
except stripe.error.StripeError as e:
logger.error(f"Stripe error creating PaymentIntent: {e}")
raise PaymentProcessingException(f"Payment processing failed: {str(e)}")
def confirm_payment(self, payment_intent_id: str) -> Payment:
"""Confirm payment and update records."""
try:
# Retrieve PaymentIntent from Stripe
payment_intent = stripe.PaymentIntent.retrieve(payment_intent_id)
# Find payment record
payment = self.db.query(Payment).filter(
Payment.stripe_payment_intent_id == payment_intent_id
).first()
if not payment:
raise PaymentNotFoundException(f"Payment not found for intent {payment_intent_id}")
# Update payment status based on Stripe status
if payment_intent.status == 'succeeded':
payment.status = 'succeeded'
payment.stripe_charge_id = payment_intent.charges.data[0].id if payment_intent.charges.data else None
payment.paid_at = datetime.utcnow()
# Update order status
order = self.db.query(Order).filter(Order.id == payment.order_id).first()
if order:
order.payment_status = 'paid'
order.status = 'processing' # Move order to processing
elif payment_intent.status == 'payment_failed':
payment.status = 'failed'
payment.failure_reason = payment_intent.last_payment_error.message if payment_intent.last_payment_error else "Unknown error"
# Update order status
order = self.db.query(Order).filter(Order.id == payment.order_id).first()
if order:
order.payment_status = 'failed'
self.db.commit()
return payment
except stripe.error.StripeError as e:
logger.error(f"Stripe error confirming payment: {e}")
raise PaymentProcessingException(f"Payment confirmation failed: {str(e)}")
def create_vendor_stripe_account(self, vendor_id: int, vendor_data: Dict) -> str:
"""Create Stripe Connect account for vendor."""
try:
# Create Stripe Connect Express account
account = stripe.Account.create(
type='express',
country='LU', # Luxembourg
email=vendor_data.get('business_email'),
capabilities={
'card_payments': {'requested': True},
'transfers': {'requested': True},
},
business_type='company',
company={
'name': vendor_data.get('business_name'),
'phone': vendor_data.get('business_phone'),
'address': {
'line1': vendor_data.get('address_line1'),
'city': vendor_data.get('city'),
'postal_code': vendor_data.get('postal_code'),
'country': 'LU'
}
},
metadata={
'vendor_id': str(vendor_id),
'platform': 'multi_tenant_ecommerce'
}
)
# Update or create payment configuration
payment_config = self.get_or_create_vendor_payment_config(vendor_id)
payment_config.stripe_account_id = account.id
payment_config.stripe_account_status = account.charges_enabled and account.payouts_enabled and 'active' or 'pending'
self.db.commit()
return account.id
except stripe.error.StripeError as e:
logger.error(f"Stripe error creating account: {e}")
raise PaymentConfigurationException(f"Failed to create payment account: {str(e)}")
def create_onboarding_link(self, vendor_id: int) -> str:
"""Create Stripe onboarding link for vendor."""
payment_config = self.get_vendor_payment_config(vendor_id)
if not payment_config.stripe_account_id:
raise PaymentNotConfiguredException("Vendor does not have Stripe account")
try:
account_link = stripe.AccountLink.create(
account=payment_config.stripe_account_id,
refresh_url=f"{settings.frontend_url}/vendor/admin/payments/refresh",
return_url=f"{settings.frontend_url}/vendor/admin/payments/success",
type='account_onboarding',
)
# Update onboarding URL
payment_config.stripe_onboarding_url = account_link.url
self.db.commit()
return account_link.url
except stripe.error.StripeError as e:
logger.error(f"Stripe error creating onboarding link: {e}")
raise PaymentConfigurationException(f"Failed to create onboarding link: {str(e)}")
def get_vendor_payment_config(self, vendor_id: int) -> VendorPaymentConfig:
"""Get vendor payment configuration."""
config = self.db.query(VendorPaymentConfig).filter(
VendorPaymentConfig.vendor_id == vendor_id
).first()
if not config:
raise PaymentNotConfiguredException(f"No payment configuration for vendor {vendor_id}")
return config
def webhook_handler(self, event_type: str, event_data: Dict) -> None:
"""Handle Stripe webhook events."""
if event_type == 'payment_intent.succeeded':
payment_intent_id = event_data['object']['id']
self.confirm_payment(payment_intent_id)
elif event_type == 'payment_intent.payment_failed':
payment_intent_id = event_data['object']['id']
self.confirm_payment(payment_intent_id)
elif event_type == 'account.updated':
# Update vendor account status
account_id = event_data['object']['id']
self.update_vendor_account_status(account_id, event_data['object'])
# Add more webhook handlers as needed
```
## API Endpoints
### Payment APIs
```python
# app/api/v1/vendor/payments.py
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from app.core.database import get_db
from middleware.vendor_context import require_vendor_context
from models.database.vendor import Vendor
from services.payment_service import PaymentService
router = APIRouter(prefix="/payments", tags=["vendor-payments"])
@router.get("/config")
async def get_payment_config(
vendor: Vendor = Depends(require_vendor_context()),
db: Session = Depends(get_db)
):
"""Get vendor payment configuration."""
payment_service = PaymentService(db)
try:
config = payment_service.get_vendor_payment_config(vendor.id)
return {
"stripe_account_id": config.stripe_account_id,
"account_status": config.stripe_account_status,
"accepts_payments": config.accepts_payments,
"currency": config.currency,
"platform_fee_percentage": float(config.platform_fee_percentage),
"needs_onboarding": config.stripe_account_status != 'active'
}
except Exception:
return {
"stripe_account_id": None,
"account_status": "not_configured",
"accepts_payments": False,
"needs_setup": True
}
@router.post("/setup")
async def setup_payments(
setup_data: dict,
vendor: Vendor = Depends(require_vendor_context()),
db: Session = Depends(get_db)
):
"""Set up Stripe payments for vendor."""
payment_service = PaymentService(db)
vendor_data = {
"business_name": vendor.name,
"business_email": vendor.business_email,
"business_phone": vendor.business_phone,
**setup_data
}
account_id = payment_service.create_vendor_stripe_account(vendor.id, vendor_data)
onboarding_url = payment_service.create_onboarding_link(vendor.id)
return {
"stripe_account_id": account_id,
"onboarding_url": onboarding_url,
"message": "Payment setup initiated. Complete onboarding to accept payments."
}
# app/api/v1/public/vendors/payments.py
@router.post("/{vendor_id}/payments/create-intent")
async def create_payment_intent(
vendor_id: int,
payment_data: dict,
db: Session = Depends(get_db)
):
"""Create payment intent for customer order."""
payment_service = PaymentService(db)
payment_intent = payment_service.create_payment_intent(
vendor_id=vendor_id,
order_id=payment_data['order_id'],
amount_euros=Decimal(str(payment_data['amount'])),
customer_email=payment_data['customer_email'],
metadata=payment_data.get('metadata', {})
)
return payment_intent
@router.post("/webhooks/stripe")
async def stripe_webhook(
request: Request,
db: Session = Depends(get_db)
):
"""Handle Stripe webhook events."""
import stripe
payload = await request.body()
sig_header = request.headers.get('stripe-signature')
try:
event = stripe.Webhook.construct_event(
payload, sig_header, settings.stripe_webhook_secret
)
except ValueError:
raise HTTPException(status_code=400, detail="Invalid payload")
except stripe.error.SignatureVerificationError:
raise HTTPException(status_code=400, detail="Invalid signature")
payment_service = PaymentService(db)
payment_service.webhook_handler(event['type'], event['data'])
return {"status": "success"}
```
## Frontend Integration
### Checkout Process
```javascript
// frontend/js/shop/checkout.js
class CheckoutManager {
constructor(vendorId) {
this.vendorId = vendorId;
this.stripe = Stripe(STRIPE_PUBLISHABLE_KEY);
this.elements = this.stripe.elements();
this.paymentElement = null;
}
async initializePayment(orderData) {
// Create payment intent
const response = await fetch(`/api/v1/public/vendors/${this.vendorId}/payments/create-intent`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
order_id: orderData.orderId,
amount: orderData.total,
customer_email: orderData.customerEmail
})
});
const { client_secret, amount_total, platform_fee } = await response.json();
// Display payment breakdown
this.displayPaymentBreakdown(amount_total, platform_fee);
// Create payment element
this.paymentElement = this.elements.create('payment', {
clientSecret: client_secret
});
this.paymentElement.mount('#payment-element');
}
async confirmPayment(orderData) {
const { error } = await this.stripe.confirmPayment({
elements: this.elements,
confirmParams: {
return_url: `${window.location.origin}/shop/order-confirmation`,
receipt_email: orderData.customerEmail
}
});
if (error) {
this.showPaymentError(error.message);
}
}
}
```
## Updated Workflow Integration
### Enhanced Customer Purchase Workflow
```
Customer adds products to cart
Customer proceeds to checkout
System creates Order (payment_status: pending)
Frontend calls POST /api/v1/public/vendors/{vendor_id}/payments/create-intent
PaymentService creates Stripe PaymentIntent with vendor destination
Customer completes payment with Stripe Elements
Stripe webhook confirms payment
PaymentService updates Order (payment_status: paid, status: processing)
Vendor receives order for fulfillment
```
### Payment Configuration Workflow
```
Vendor accesses payment settings
POST /api/v1/vendor/payments/setup
System creates Stripe Connect account
Vendor completes Stripe onboarding
Webhook updates account status to 'active'
Vendor can now accept payments
```
This integration provides secure, compliant payment processing while maintaining vendor isolation and enabling proper revenue distribution between vendors and the platform.

View File

@@ -1,781 +0,0 @@
# Multi-Tenant Ecommerce Platform
A production-ready, multi-tenant ecommerce platform that enables vendors to operate independent webshops while integrating with external marketplaces. Built with complete vendor isolation, comprehensive business features, and modern reactive frontend.
## 🚀 Features
### Core Business Features
- **Multi-Vendor Marketplace**: Complete vendor isolation with independent webshops
- **Marketplace Integration**: Import and curate products from external marketplaces (Letzshop CSV)
- **Product Catalog Management**: Vendor-scoped product publishing from marketplace imports
- **Inventory Management**: Real-time stock tracking with location-based inventory
- **Order Management**: Complete order lifecycle with status tracking and fulfillment
- **Customer Management**: Vendor-scoped customer accounts with order history
- **Team Management**: Role-based access control with granular permissions
- **Shopping Cart**: Session-based cart with real-time updates
### Technical Features
- **Modern Frontend Stack**: Alpine.js for reactive UI with zero build step
- **RESTful API Architecture**: FastAPI with comprehensive OpenAPI documentation
- **Service Layer Pattern**: Clean separation of business logic and data access
- **Exception-First Error Handling**: Frontend-friendly error responses with consistent error codes
- **Multi-tenant Security**: Complete data isolation with vendor context detection
- **Background Job Processing**: Async marketplace imports with status tracking
- **Comprehensive API**: Admin, Vendor, and Public (Customer) endpoints
### Security & Compliance
- **Complete Data Isolation**: Chinese wall between vendor data
- **JWT Authentication**: Secure token-based authentication for all user types
- **Role-Based Access Control**: Granular permissions (Owner, Manager, Editor, Viewer)
- **Vendor Context Detection**: Subdomain and path-based tenant isolation
- **Input Validation**: Pydantic models for all API requests
- **Exception Handling**: Structured error responses with proper HTTP status codes
## 🏗️ Architecture
### Technology Stack
- **Backend**: Python 3.13+ with FastAPI
- **Database**: PostgreSQL with SQLAlchemy ORM
- **Frontend**: Vanilla HTML, CSS, JavaScript with Alpine.js (CDN-based, no build step)
- **Authentication**: JWT tokens with role-based permissions
- **Background Jobs**: Async CSV import processing
- **API Documentation**: Auto-generated OpenAPI/Swagger
### Multi-Tenancy Model
```
Platform
├── Admin Portal (admin.platform.com or /admin)
│ ├── Vendor management
│ ├── User administration
│ ├── Platform statistics
│ └── Import job monitoring
├── Vendor A (vendor-a.platform.com or /vendor/{code})
│ ├── Marketplace product imports
│ ├── Product catalog publishing
│ ├── Order management
│ ├── Customer management
│ ├── Team management
│ └── Inventory tracking
├── Vendor B (vendor-b.platform.com or /vendor/{code})
│ └── Completely isolated from Vendor A
└── Customer Shop (/shop or subdomain)
├── Product browsing
├── Shopping cart
├── Order placement
└── Order history
```
### Data Flow
```
Marketplace CSV → Import Job → MarketplaceProduct (Staging) → Product (Catalog) → Order → Customer
↓ ↓ ↓
Job Status Product Selection Inventory Tracking
```
## 📁 Project Structure
```
├── main.py # FastAPI application entry point
├── app/
│ ├── api/
│ │ ├── main.py # API router aggregation
│ │ ├── deps.py # Dependency injection (auth, context)
│ │ └── v1/ # API version 1
│ │ ├── admin/ # Admin endpoints
│ │ │ ├── __init__.py
│ │ │ ├── auth.py
│ │ │ ├── vendors.py
│ │ │ ├── users.py
│ │ │ ├── marketplace.py
│ │ │ └── dashboard.py
│ │ ├── vendor/ # Vendor endpoints
│ │ │ ├── __init__.py
│ │ │ ├── auth.py
│ │ │ ├── dashboard.py
│ │ │ ├── products.py
│ │ │ ├── orders.py
│ │ │ ├── marketplace.py
│ │ │ ├── inventory.py
│ │ │ └── vendor.py
│ │ └── public/ # Customer endpoints
│ │ ├── __init__.py
│ │ └── vendors/
│ │ ├── auth.py
│ │ ├── products.py
│ │ ├── cart.py
│ │ └── orders.py
│ ├── core/
│ │ ├── database.py # Database configuration
│ │ ├── security.py # JWT and password utilities
│ │ └── config.py # Application settings
│ ├── exceptions/ # Custom exceptions
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── auth.py
│ │ ├── vendor.py
│ │ ├── customer.py
│ │ ├── product.py
│ │ ├── order.py
│ │ ├── inventory.py
│ │ ├── team.py
│ │ ├── marketplace_product.py
│ │ ├── marketplace_import_job.py
│ │ └── admin.py
│ └── services/ # Business logic layer
│ ├── auth_service.py
│ ├── admin_service.py
│ ├── vendor_service.py
│ ├── customer_service.py
│ ├── product_service.py
│ ├── order_service.py
│ ├── cart_service.py
│ ├── inventory_service.py
│ ├── team_service.py
│ ├── marketplace_service.py
│ └── stats_service.py
├── models/
│ ├── database/ # SQLAlchemy ORM models
│ │ ├── base.py
│ │ ├── user.py
│ │ ├── vendor.py
│ │ ├── customer.py
│ │ ├── product.py
│ │ ├── order.py
│ │ ├── inventory.py
│ │ ├── marketplace_product.py
│ │ └── marketplace_import_job.py
│ └── schemas/ # Pydantic validation models
│ ├── auth.py
│ ├── vendor.py
│ ├── customer.py
│ ├── product.py
│ ├── order.py
│ ├── inventory.py
│ ├── marketplace_product.py
│ ├── marketplace_import_job.py
│ └── stats.py
├── middleware/
│ ├── auth.py # JWT authentication
│ ├── vendor_context.py # Multi-tenant context detection
│ ├── rate_limiter.py # API rate limiting
│ └── decorators.py # Utility decorators
├── static/ # Frontend assets (no build step required)
│ ├── admin/ # Admin interface
│ │ ├── login.html
│ │ ├── dashboard.html
│ │ └── vendors.html
│ ├── vendor/ # Vendor management UI
│ │ ├── login.html
│ │ ├── dashboard.html
│ │ └── admin/
│ │ ├── products.html
│ │ ├── orders.html
│ │ └── marketplace.html
│ ├── shop/ # Customer shop interface
│ │ ├── products.html
│ │ ├── product.html # Alpine.js product detail
│ │ ├── cart.html
│ │ └── account/
│ │ ├── register.html
│ │ ├── login.html
│ │ └── orders.html
│ ├── css/
│ │ ├── shared/
│ │ │ ├── base.css # CSS variables, utility classes
│ │ │ └── auth.css
│ │ ├── admin/
│ │ │ └── admin.css
│ │ ├── vendor/
│ │ │ └── vendor.css
│ │ └── shop/
│ │ └── shop.css
│ └── js/
│ └── shared/
│ ├── api-client.js
│ ├── vendor-context.js
│ └── utils.js
├── scripts/
│ ├── init_db.py # Database initialization
│ └── create_admin.py # Admin user creation
└── tests/
├── unit/
├── integration/
└── e2e/
```
## 🚀 Quick Start
### Prerequisites
- Python 3.13+
- PostgreSQL 14+ (SQLite for development)
- Node.js (optional, only for development tools)
### Development Setup
#### 1. Clone and Setup Environment
```bash
git clone <repository-url>
cd multi-tenant-ecommerce
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt
```
#### 2. Database Setup
```bash
# Create database
createdb ecommerce_db
# Run migrations
python scripts/init_db.py
# Create initial admin user
python scripts/create_admin.py
```
#### 3. Environment Configuration
```bash
cp .env.example .env
# Edit .env with your configuration
```
Minimal `.env`:
```env
DATABASE_URL=postgresql://user:pass@localhost:5432/ecommerce_db
SECRET_KEY=your-secret-key-here-generate-with-openssl
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
DEVELOPMENT_MODE=true
```
#### 4. Start Application
```bash
# Start FastAPI application
uvicorn main:app --reload --port 8000
```
#### 5. Access the Platform
- **Admin Panel**: http://localhost:8000/admin/
- **Vendor Login**: http://localhost:8000/vendor/login
- **Customer Shop**: http://localhost:8000/shop/
- **API Documentation**: http://localhost:8000/docs
- **Health Check**: http://localhost:8000/health
### First Steps
1. **Login to Admin Panel**
- URL: http://localhost:8000/admin/
- Credentials: Created via `create_admin.py`
2. **Create First Vendor**
- Navigate to Admin → Vendors
- Click "Create Vendor"
- Fill in vendor details (name, code, subdomain)
- System creates vendor + owner user account
- Note the temporary password
3. **Login as Vendor Owner**
- URL: http://localhost:8000/vendor/login (or subdomain)
- Use vendor owner credentials
4. **Import Products from Marketplace**
- Navigate to Vendor → Marketplace Import
- Configure Letzshop CSV URL
- Trigger import job
- Monitor import status
5. **Publish Products to Catalog**
- Review imported products in staging
- Select products to publish
- Configure pricing and inventory
- Publish to customer-facing catalog
## 📋 API Structure
### Admin APIs (`/api/v1/admin`)
**Authentication:**
```
POST /auth/login # Admin login
```
**Vendor Management:**
```
GET /vendors # List all vendors
POST /vendors # Create vendor with owner
GET /vendors/{id} # Get vendor details
PUT /vendors/{id}/verify # Verify/unverify vendor
PUT /vendors/{id}/status # Toggle active status
DELETE /vendors/{id} # Delete vendor
```
**User Management:**
```
GET /users # List all users
PUT /users/{id}/status # Toggle user status
```
**Marketplace Monitoring:**
```
GET /marketplace-import-jobs # Monitor all import jobs
```
**Dashboard & Statistics:**
```
GET /dashboard # Admin dashboard
GET /dashboard/stats # Comprehensive statistics
GET /dashboard/stats/marketplace # Marketplace breakdown
GET /dashboard/stats/platform # Platform-wide metrics
```
### Vendor APIs (`/api/v1/vendor`)
**Authentication:**
```
POST /auth/login # Vendor team login
POST /auth/logout # Logout
```
**Dashboard:**
```
GET /dashboard/stats # Vendor-specific statistics
```
**Product Management:**
```
GET /products # List catalog products
POST /products # Add product to catalog
GET /products/{id} # Get product details
PUT /products/{id} # Update product
DELETE /products/{id} # Remove from catalog
POST /products/from-import/{id} # Publish from marketplace
PUT /products/{id}/toggle-active # Toggle product active
PUT /products/{id}/toggle-featured # Toggle featured status
```
**Order Management:**
```
GET /orders # List vendor orders
GET /orders/{id} # Get order details
PUT /orders/{id}/status # Update order status
```
**Marketplace Integration:**
```
POST /marketplace/import # Trigger import job
GET /marketplace/jobs # List import jobs
GET /marketplace/jobs/{id} # Get job status
GET /marketplace/products # List staged products
POST /marketplace/products/publish # Bulk publish to catalog
```
**Inventory Management:**
```
GET /inventory # List inventory items
POST /inventory # Add inventory
PUT /inventory/{id} # Update inventory
GET /inventory/movements # Inventory movement history
```
### Public/Customer APIs (`/api/v1/public/vendors`)
**Authentication:**
```
POST /{vendor_id}/auth/register # Customer registration
POST /{vendor_id}/auth/login # Customer login
POST /{vendor_id}/auth/logout # Customer logout
```
**Product Browsing:**
```
GET /{vendor_id}/products # Browse product catalog
GET /{vendor_id}/products/{id} # Product details
GET /{vendor_id}/products/search # Search products
```
**Shopping Cart:**
```
GET /{vendor_id}/cart/{session} # Get cart
POST /{vendor_id}/cart/{session}/items # Add to cart
PUT /{vendor_id}/cart/{session}/items/{id} # Update quantity
DELETE /{vendor_id}/cart/{session}/items/{id} # Remove item
DELETE /{vendor_id}/cart/{session} # Clear cart
```
**Order Placement:**
```
POST /{vendor_id}/orders # Place order
GET /{vendor_id}/customers/{id}/orders # Order history
GET /{vendor_id}/customers/{id}/orders/{id} # Order details
```
## 🎨 Frontend Architecture
### Alpine.js Integration
#### Why Alpine.js?
- ✅ Lightweight (15KB) - perfect for multi-tenant platform
- ✅ No build step required - works directly in HTML
- ✅ Reactive state management - modern UX without complexity
- ✅ Perfect Jinja2 integration - server + client harmony
- ✅ Scoped components - natural vendor isolation
#### Example: Product Detail Page
```html
<div x-data="productDetail()" x-init="loadProduct()">
<!-- Reactive product display -->
<h1 x-text="product?.title"></h1>
<p class="price"><span x-text="product?.price"></span></p>
<!-- Quantity selector with validation -->
<input
type="number"
x-model.number="quantity"
:min="product?.min_quantity"
:max="product?.available_inventory"
>
<!-- Add to cart with loading state -->
<button
@click="addToCart()"
:disabled="!canAddToCart || addingToCart"
>
<span x-show="!addingToCart">Add to Cart</span>
<span x-show="addingToCart">Adding...</span>
</button>
</div>
```
### CSS Architecture
#### CSS Variables for Multi-Tenant Theming
```css
/* Base variables in base.css */
:root {
--primary-color: #3b82f6;
--primary-dark: #2563eb;
--success-color: #10b981;
--danger-color: #ef4444;
--warning-color: #f59e0b;
/* Typography */
--font-base: 16px;
--font-sm: 0.875rem;
--font-xl: 1.25rem;
/* Spacing */
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
/* Borders & Shadows */
--radius-md: 0.375rem;
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
}
/* Vendor-specific overrides */
[data-vendor-theme="dark"] {
--primary-color: #1f2937;
--background-color: #111827;
}
```
## 🔒 Security Implementation
### Authentication Flow
**Admin Login:**
```
1. POST /api/v1/admin/auth/login
2. Verify credentials + admin role
3. Generate JWT token
4. Store token in localStorage
5. Include in Authorization header for protected routes
```
**Vendor Team Login:**
```
1. POST /api/v1/vendor/auth/login
2. Detect vendor context (subdomain or path)
3. Verify credentials + vendor membership
4. Generate JWT token with vendor context
5. All subsequent requests validated against vendor
```
**Customer Login:**
```
1. POST /api/v1/public/vendors/{id}/auth/login
2. Verify customer credentials for specific vendor
3. Generate JWT token with customer context
4. Customer can only access their own data
```
### Vendor Context Detection
```python
# Automatic vendor detection from:
1. Subdomain: vendor-a.platform.com
2. Path parameter: /vendor/VENDOR_A/
3. JWT token: Embedded vendor_id in claims
# Complete data isolation:
- All queries automatically scoped to vendor_id
- Cross-vendor access prevented at service layer
- Exception raised if vendor mismatch detected
```
### Exception Handling Pattern
```python
# Frontend-friendly error responses
{
"detail": "Human-readable error message",
"error_code": "PRODUCT_NOT_FOUND",
"status_code": 404,
"timestamp": "2025-01-10T12:00:00Z",
"request_id": "abc123"
}
# Consistent error codes across platform
- VENDOR_NOT_FOUND
- PRODUCT_NOT_IN_CATALOG
- INSUFFICIENT_INVENTORY
- INVALID_ORDER_STATUS
- UNAUTHORIZED_VENDOR_ACCESS
```
## 📊 Database Schema
### Core Tables
**Multi-Tenant Foundation:**
```sql
vendors # Vendor accounts
users # Platform/admin users
vendor_users # Vendor team members (many-to-many)
roles # Role definitions per vendor
customers # Vendor-scoped customers
customer_addresses
```
**Product & Inventory:**
```sql
marketplace_products # Imported from marketplaces (staging)
marketplace_import_jobs # Import tracking
products # Published vendor catalog
inventory # Stock tracking by location
inventory_movements
```
**Orders & Commerce:**
```sql
orders
order_items
shipping_address (FK to customer_addresses)
billing_address (FK to customer_addresses)
```
### Key Relationships
```
Vendor (1) ──→ (N) Products
Vendor (1) ──→ (N) Customers
Vendor (1) ──→ (N) Orders
Vendor (1) ──→ (N) MarketplaceProducts
Product (1) ──→ (N) Inventory
Product (1) ──→ (1) MarketplaceProduct
Order (1) ──→ (N) OrderItems
Order (1) ──→ (1) Customer
Order (1) ──→ (1) ShippingAddress
Order (1) ──→ (1) BillingAddress
```
## 🧪 Testing
### Current Test Coverage
```bash
# Run all tests
pytest tests/
# Run with coverage
pytest --cov=app --cov=models --cov=middleware tests/
# Run specific test category
pytest tests/unit/
pytest tests/integration/
pytest tests/e2e/
```
### Test Structure
- **Unit Tests**: Service layer logic, model validation
- **Integration Tests**: API endpoints, database operations
- **E2E Tests**: Complete user workflows (admin creates vendor → vendor imports products → customer places order)
## 🚦 Development Status
### ✅ Completed Features
**Slice 1: Multi-Tenant Foundation**
- ✅ Admin creates vendors through admin interface
- ✅ Vendor owner login with context detection
- ✅ Complete vendor data isolation
- ✅ Role-based access control
- ✅ JWT authentication system
**Slice 2: Marketplace Integration**
- ✅ CSV import from Letzshop
- ✅ Background job processing
- ✅ Import status tracking
- ✅ Product staging area
- 🚧 Real-time Alpine.js status updates
**Slice 3: Product Catalog**
- ✅ Product publishing from marketplace staging
- ✅ Vendor product catalog management
- ✅ Product CRUD operations
- ✅ Inventory tracking
- ✅ Product filtering and search
**Slice 4: Customer Shopping**
- ✅ Customer service implementation
- ✅ Customer registration/login
- ✅ Product browsing interface
- ✅ Shopping cart with Alpine.js
- ✅ Product detail page (Alpine.js)
**Slice 5: Order Processing**
- ✅ Order creation from cart
- ✅ Order management (vendor)
- ✅ Order history (customer)
- ✅ Order status tracking
- ✅ Inventory reservation
### 🚧 In Progress (BOOTS)
**Current Sprint:**
- 🚧 Customer account dashboard (Alpine.js)
- 🚧 Multi-step checkout flow
- 🚧 Payment integration placeholder (Stripe ready)
- 🚧 Order confirmation page
- 🚧 Email notifications (order confirmations)
## 📋 Roadmap
### Phase 1: Core Platform (90% Complete)
- ✅ Multi-tenant architecture
- ✅ Vendor management
- ✅ Product catalog system
- ✅ Order processing
- ✅ Customer management
- 🚧 Payment integration (ready for Stripe)
- 🚧 Email notifications
### Phase 2: Advanced Features (Next)
- Persistent cart storage (Redis/Database)
- Order search and filtering
- Advanced inventory management
- Product variants support
- Customer reviews and ratings
- Vendor analytics dashboard
### Phase 3: Enterprise Features (Future)
- Multi-language support
- Advanced reporting and exports
- Webhook integrations
- API rate limiting enhancements
- Performance monitoring
- Automated backups
## 📝 Naming Conventions
The project follows strict naming conventions for consistency:
### Files
- **API files**: Plural (`products.py`, `orders.py`)
- **Model files**: Singular (`product.py`, `order.py`)
- **Service files**: Singular + service (`product_service.py`)
- **Exception files**: Singular (`product.py`, `order.py`)
### Terminology
- **inventory** (not stock)
- **vendor** (not shop)
- **customer** (not user for end-users)
- **team** (not staff)
See `docs/6.complete_naming_convention.md` for full details.
## 🤝 Contributing
### Development Workflow
1. Fork the repository
2. Create feature branch: `git checkout -b feature/amazing-feature`
3. Follow existing patterns (service layer, exceptions, Alpine.js)
4. Add tests for new features
5. Update API documentation
6. Submit pull request
### Code Quality
```bash
# Format code
black app/ models/ middleware/
# Sort imports
isort app/ models/ middleware/
# Lint
flake8 app/ models/ middleware/
```
## 📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
## 🆘 Support
### Documentation
- **API Reference**: http://localhost:8000/docs
- **Development Guides**: `/docs/`
- **Naming Conventions**: `/docs/6.complete_naming_convention.md`
- **Vertical Slice Plan**: `/docs/3.vertical_slice_roadmap.md`
### Key Features
- **Zero Build Step**: Frontend works without compilation
- **Alpine.js Reactive UI**: Modern UX without framework complexity
- **Service Layer Pattern**: Clean, testable business logic
- **Exception-First**: Consistent error handling
- **Multi-Tenant by Design**: Complete vendor isolation
---
Built with FastAPI, PostgreSQL, Alpine.js, and modern Python patterns for a scalable, maintainable multi-tenant ecommerce platform. 🚀

View File

@@ -1,313 +0,0 @@
# Multi-Tenant Ecommerce Platform - Complete Application Workflows
## Overview
This document describes the complete workflows for the production-ready multi-tenant ecommerce platform, from marketplace import to customer analytics. Each workflow shows the interaction between different user types and the data flow through all system components including notifications, payments, media management, and monitoring.
## Core Data Flow Architecture
```
Marketplace CSV → MarketplaceProduct (staging) → Product (catalog) → Customer Orders → Analytics
↓ ↓ ↓
Email Notifications Media Files Payment Processing
↓ ↓ ↓
Audit Logging Search Index Performance Monitoring
```
## Workflow 1: Platform Setup and Vendor Onboarding
### Participants
- **Admin**: Platform administrator
- **New Vendor**: Business owner registering
- **System**: Automated onboarding processes
### Workflow Steps
#### 1.1 Admin Creates Vendor
```
Admin → Access admin panel (admin.platform.com)
POST /api/v1/admin/auth/login
Admin dashboard loads with platform metrics
Admin → Create new vendor
POST /api/v1/admin/vendors
System creates:
- Vendor record with subdomain
- Owner user account
- Default role structure (Owner, Manager, Editor, Viewer)
- Default notification templates
- Vendor payment configuration (inactive)
- Initial search index
- Audit log entry
Email notification sent to vendor owner
Vendor appears in admin vendor list
```
#### 1.2 Vendor Owner Account Activation
```
Vendor Owner → Receives welcome email
Click activation link → vendor.platform.com/admin/login
POST /api/v1/vendor/auth/login
Vendor context middleware detects vendor from subdomain
Dashboard loads with vendor setup checklist:
- ✅ Account created
- ⏸️ Payment setup pending
- ⏸️ Marketplace integration pending
- ⏸️ First product pending
```
#### 1.3 Payment Configuration
```
Vendor → Configure payments
GET /api/v1/vendor/payments/config (returns needs_setup: true)
POST /api/v1/vendor/payments/setup
System creates Stripe Connect account
Vendor redirected to Stripe onboarding
Stripe webhook updates account status
VendorPaymentConfig.accepts_payments = true
Audit log: payment configuration completed
```
### Data States After Onboarding
- **Vendor**: Active with configured payments
- **User**: Owner with full permissions
- **Notifications**: Welcome sequence completed
- **Audit Trail**: Complete onboarding history
---
## Workflow 2: Marketplace Import and Product Curation
### Participants
- **Vendor**: Store owner/manager
- **Background System**: Import processing
- **Notification System**: Status updates
### Workflow Steps
#### 2.1 Marketplace Configuration
```
Vendor → Configure Letzshop integration
POST /api/v1/vendor/settings/marketplace
Update Vendor.letzshop_csv_url
Configuration validated and saved
Audit log: marketplace configuration updated
```
#### 2.2 Import Execution
```
Vendor → Trigger import
POST /api/v1/vendor/marketplace/import
System creates MarketplaceImportJob (status: pending)
Background task queued: process_marketplace_import.delay(job_id)
TaskLog created with progress tracking
Celery worker processes import:
- Downloads CSV from marketplace
- Validates data format
- Creates MarketplaceProduct records (staging)
- Updates SearchIndex for browsing
- Generates product image thumbnails
- Updates job status with progress
Email notification: import completed
Audit log: import job completed
```
#### 2.3 Product Discovery and Selection
```
Vendor → Browse imported products
GET /api/v1/vendor/marketplace/imports/{job_id}/products
Cache check for search results
Display MarketplaceProduct records with:
- Search and filtering capabilities
- Thumbnail images
- Selection status indicators
- Bulk selection options
Vendor → Select products for review
POST /api/v1/vendor/marketplace/products/{id}/select
MarketplaceProduct updated:
- is_selected: true
- selected_at: timestamp
Search index updated
Cache invalidation for product lists
```
#### 2.4 Product Customization and Publishing
```
Vendor → Customize selected product
Vendor uploads custom images:
POST /api/v1/vendor/media/upload
MediaService processes:
- Creates vendor-scoped file path
- Generates image variants (thumbnail, small, medium, large)
- Uploads to storage backend (local/S3)
- Creates MediaFile record
Vendor customizes:
- SKU (vendor-specific)
- Price (markup from cost)
- Description (enhanced/localized)
- Images (vendor-uploaded + marketplace)
- Categories (vendor taxonomy)
- Inventory settings
Vendor → Publish to catalog
POST /api/v1/vendor/marketplace/products/{id}/publish
System creates Product record:
- Vendor-customized data
- marketplace_product_id link
- is_active: true
Updates:
- MarketplaceProduct: is_published: true
- SearchIndex: product catalog entry
- Cache invalidation: product catalogs
Product now visible in vendor catalog
Audit log: product published to catalog
```
### Data States After Publication
- **MarketplaceProduct**: Selected and published
- **Product**: Active in vendor catalog
- **MediaFile**: Vendor-specific product images
- **SearchIndex**: Searchable in catalog
- **Cache**: Invalidated and refreshed
---
## Workflow 3: Customer Shopping Experience
### Participants
- **Customer**: End user shopping
- **Vendor**: Store owner (indirect)
- **Search System**: Product discovery
- **Payment System**: Transaction processing
### Workflow Steps
#### 3.1 Store Discovery and Browsing
```
Customer → Access vendor store
vendor.platform.com OR platform.com/vendor/vendorname
Vendor context middleware:
- Identifies vendor from URL
- Loads vendor-specific theme
- Sets vendor_id context for all operations
GET /api/v1/public/vendors/{vendor_id}/shop-info
Cache check for vendor theme and configuration
Store homepage loads with vendor branding
```
#### 3.2 Product Search and Discovery
```
Customer → Search for products
GET /api/v1/public/vendors/{vendor_id}/products/search?q=query
SearchService processes query:
- Cache check for search results
- Elasticsearch query (if available) OR database search
- Vendor-scoped results only
- Logs search query for analytics
Results include:
- Product details with vendor customizations
- Media files (images with variants)
- Real-time inventory levels
- Vendor-specific pricing
Search analytics updated
Cache results for future queries
```
#### 3.3 Product Details and Media
```
Customer → View product details
GET /api/v1/public/vendors/{vendor_id}/products/{id}
System returns:
- Product information from vendor catalog
- Media gallery with all variants
- Inventory availability
- Vendor-specific descriptions and pricing
Media files served from CDN for performance
```
#### 3.4 Shopping Cart Management
```
Customer → Add to cart
POST /api/v1/public/vendors/{vendor_id}/cart/{session_id}/items
System:
- Validates product availability
- Checks inventory levels
- Creates/updates session-based cart
- Price validation against current Product prices
Cart data cached for session
```
#### 3.5 Customer Account Management
```
Customer → Create account
POST /api/v1/public/vendors/{vendor_id}/customers/register
System creates:
- Customer record (vendor_id scoped)
- Email unique within vendor only
- Vendor-specific customer number
- Default notification preferences
Welcome email sent using vendor

View File

@@ -1,510 +0,0 @@
# Multi-Tenant Ecommerce Platform - Complete Project Structure
## Project Overview
This document outlines the complete project structure for a production-ready multi-tenant ecommerce platform with marketplace integration. The platform implements complete vendor isolation with comprehensive business features including notifications, media management, search, caching, audit logging, and monitoring.
## Technology Stack
- **Backend**: Python FastAPI with PostgreSQL
- **Frontend**: Vanilla HTML, CSS, JavaScript with Alpine.js (CDN-based, no build step)
- **Background Jobs**: Celery with Redis
- **Search**: Elasticsearch with database fallback
- **Caching**: Redis multi-layer caching
- **Storage**: Local/S3 with CDN integration
- **Monitoring**: Custom monitoring with alerting
- **Deployment**: Docker with environment-based configuration
## Complete Directory Structure
```
├── main.py # FastAPI application entry point
├── app/
│ ├── api/
│ │ ├── deps.py # Common dependencies (auth, context)
│ │ ├── main.py # API router setup
│ │ └── v1/ # API version 1 routes
│ │ ├── admin/ # Super admin endpoints
│ │ │ ├── __init__.py # Admin router aggregation
│ │ │ ├── auth.py # Admin authentication
│ │ │ ├── vendors.py # Vendor management (CRUD, bulk operations)
│ │ │ ├── dashboard.py # Admin dashboard & statistics
│ │ │ ├── users.py # User management across vendors
│ │ │ ├── marketplace.py # System-wide marketplace monitoring
│ │ │ ├── audit.py # Audit log endpoints
│ │ │ ├── settings.py # Platform settings management
│ │ │ ├── notifications.py # Admin notifications & alerts
│ │ │ └── monitoring.py # Platform monitoring & health checks
│ │ ├── vendor/ # Vendor-scoped endpoints
│ │ │ ├── __init__.py
│ │ │ ├── auth.py # Vendor team authentication
│ │ │ ├── dashboard.py # Vendor dashboard & statistics
│ │ │ ├── products.py # Vendor catalog management (Product table)
│ │ │ ├── marketplace.py # Marketplace import & selection (MarketplaceProduct)
│ │ │ ├── orders.py # Vendor order management
│ │ │ ├── customers.py # Vendor customer management
│ │ │ ├── teams.py # Team member management
│ │ │ ├── inventory.py # Inventory operations (vendor catalog)
│ │ │ ├── payments.py # Payment configuration & processing
│ │ │ ├── media.py # File and media management
│ │ │ ├── notifications.py # Vendor notification management
│ │ │ └── settings.py # Vendor settings & configuration
│ │ ├── public/ # Public customer-facing endpoints
│ │ │ ├── __init__.py
│ │ │ └── vendors/ # Vendor-specific public APIs
│ │ │ ├── shop.py # Public shop info
│ │ │ ├── products.py # Public product catalog (Product table only)
│ │ │ ├── search.py # Product search functionality
│ │ │ ├── cart.py # Shopping cart operations
│ │ │ ├── orders.py # Order placement
│ │ │ ├── payments.py # Payment processing
│ │ │ └── auth.py # Customer authentication
│ │ └── shared/ # Shared/utility endpoints
│ │ ├── health.py # Health checks
│ │ ├── webhooks.py # External webhooks (Stripe, etc.)
│ │ └── uploads.py # File upload handling
│ ├── core/
│ │ ├── config.py # Configuration settings
│ │ ├── database.py # Database setup
│ │ ├── security.py # Security utilities (JWT, passwords)
│ │ └── lifespan.py # App lifecycle management
│ ├── exceptions/ # Custom exception handling
│ │ ├── __init__.py # All exception exports
│ │ ├── base.py # Base exception classes
│ │ ├── handler.py # Unified FastAPI exception handlers
│ │ ├── auth.py # Authentication/authorization exceptions
│ │ ├── admin.py # Admin operation exceptions
│ │ ├── marketplace.py # Import/marketplace exceptions
│ │ ├── marketplace_product.py # Marketplace staging exceptions
│ │ ├── product.py # Vendor catalog exceptions
│ │ ├── vendor.py # Vendor management exceptions
│ │ ├── customer.py # Customer management exceptions
│ │ ├── order.py # Order management exceptions
│ │ ├── payment.py # Payment processing exceptions
│ │ ├── inventory.py # Inventory management exceptions
│ │ ├── media.py # Media/file management exceptions
│ │ ├── notification.py # Notification exceptions
│ │ ├── search.py # Search exceptions
│ │ ├── monitoring.py # Monitoring exceptions
│ │ └── backup.py # Backup/recovery exceptions
│ └── services/ # Business logic layer
│ ├── auth_service.py # Authentication/authorization services
│ ├── admin_service.py # Admin services (vendor/user management)
│ ├── admin_audit_service.py # Audit logging services
│ ├── admin_settings_service.py # Platform settings services
│ ├── vendor_service.py # Vendor management services
│ ├── customer_service.py # Customer services (vendor-scoped)
│ ├── team_service.py # Team management services
│ ├── marketplace_service.py # Marketplace import services
│ ├── marketplace_product_service.py # Marketplace staging services
│ ├── product_service.py # Vendor catalog services (Product)
│ ├── order_service.py # Order services (vendor-scoped)
│ ├── payment_service.py # Payment processing services
│ ├── inventory_service.py # Inventory services (vendor catalog)
│ ├── media_service.py # File and media management services
│ ├── notification_service.py # Email/notification services
│ ├── search_service.py # Search and indexing services
│ ├── cache_service.py # Caching services
│ ├── monitoring_service.py # Application monitoring services
│ ├── backup_service.py # Backup and recovery services
│ ├── configuration_service.py # Configuration management services
│ └── stats_service.py # Statistics services (vendor-aware)
├── tasks/ # Background task processing
│ ├── __init__.py
│ ├── task_manager.py # Celery configuration and task management
│ ├── marketplace_import.py # Marketplace CSV import tasks
│ ├── email_tasks.py # Email sending tasks
│ ├── media_processing.py # Image processing and optimization tasks
│ ├── search_indexing.py # Search index maintenance tasks
│ ├── analytics_tasks.py # Analytics and reporting tasks
│ ├── cleanup_tasks.py # Data cleanup and maintenance tasks
│ └── backup_tasks.py # Backup and recovery tasks
├── models/
│ ├── database/ # SQLAlchemy ORM models
│ │ ├── __init__.py # Import all models for easy access
│ │ ├── base.py # Base model class and common mixins (TimestampMixin)
│ │ ├── user.py # User model (with vendor relationships)
│ │ ├── vendor.py # Vendor, VendorUser, Role models
│ │ ├── customer.py # Customer, CustomerAddress models (vendor-scoped)
│ │ ├── marketplace_product.py # MarketplaceProduct model (staging data)
│ │ ├── product.py # Product model (vendor catalog)
│ │ ├── order.py # Order, OrderItem models (vendor-scoped)
│ │ ├── payment.py # Payment, PaymentMethod, VendorPaymentConfig models
│ │ ├── inventory.py # Inventory, InventoryMovement models (catalog products)
│ │ ├── marketplace.py # MarketplaceImportJob model
│ │ ├── media.py # MediaFile, ProductMedia models
│ │ ├── notification.py # NotificationTemplate, NotificationQueue, NotificationLog
│ │ ├── search.py # SearchIndex, SearchQuery models
│ │ ├── audit.py # AuditLog, DataExportLog models
│ │ ├── monitoring.py # PerformanceMetric, ErrorLog, SystemAlert models
│ │ ├── backup.py # BackupLog, RestoreLog models
│ │ ├── configuration.py # PlatformConfig, VendorConfig, FeatureFlag models
│ │ ├── task.py # TaskLog model
│ │ └── admin.py # Admin-specific models
│ │ # - AdminAuditLog: Track all admin actions
│ │ # - AdminNotification: System alerts for admins
│ │ # - AdminSetting: Platform-wide settings
│ │ # - PlatformAlert: System health alerts
│ │ # - AdminSession: Admin login session tracking
│ └── schema/ # Pydantic models for API validation
│ ├── __init__.py # Common imports
│ ├── base.py # Base Pydantic models
│ ├── auth.py # Login, Token, User response models
│ ├── vendor.py # Vendor management models
│ ├── customer.py # Customer request/response models
│ ├── team.py # Team management models
│ ├── marketplace_product.py # Marketplace staging models
│ ├── product.py # Vendor catalog models
│ ├── order.py # Order models (vendor-scoped)
│ ├── payment.py # Payment models
│ ├── inventory.py # Inventory operation models
│ ├── marketplace.py # Marketplace import job models
│ ├── media.py # Media/file management models
│ ├── notification.py # Notification models
│ ├── search.py # Search models
│ ├── monitoring.py # Monitoring models
│ ├── admin.py # Admin operation models
│ │ # - AdminAuditLog schemas (Response, Filters, List)
│ │ # - AdminNotification schemas (Create, Response, Update, List)
│ │ # - AdminSetting schemas (Create, Response, Update, List)
│ │ # - PlatformAlert schemas (Create, Response, Resolve, List)
│ │ # - BulkOperation schemas (BulkVendorAction, BulkUserAction)
│ │ # - AdminDashboardStats, SystemHealthResponse
│ │ # - AdminSession schemas
│ └── stats.py # Statistics response models
├── middleware/
│ ├── auth.py # JWT authentication
│ ├── vendor_context.py # Vendor context detection and injection
│ ├── rate_limiter.py # Rate limiting
│ ├── logging_middleware.py # Request logging
│ └── decorators.py # Cross-cutting concern decorators
├── storage/ # Storage backends
│ ├── __init__.py
│ ├── backends.py # Storage backend implementations
│ └── utils.py # Storage utilities
├── static/ # Frontend assets (No build step!)
│ ├── admin/ # Super admin interface
│ │ ├── login.html # Admin login page
│ │ ├── dashboard.html # Admin dashboard
│ │ ├── vendors.html # Vendor management
│ │ ├── users.html # User management
│ │ ├── marketplace.html # System-wide marketplace monitoring
│ │ ├── audit_logs.html # Audit log viewer (NEW - TO CREATE)
│ │ ├── settings.html # Platform settings (NEW - TO CREATE)
│ │ ├── notifications.html # Admin notifications (NEW - TO CREATE)
│ │ └── monitoring.html # System monitoring
│ ├── vendor/ # Vendor admin interface
│ │ ├── login.html # Vendor team login (TO COMPLETE)
│ │ ├── dashboard.html # Vendor dashboard (TO COMPLETE)
│ │ └── admin/ # Vendor admin pages
│ │ ├── products.html # Catalog management (Product table)
│ │ ├── marketplace/ # Marketplace integration
│ │ │ ├── imports.html # Import jobs & history
│ │ │ ├── browse.html # Browse marketplace products (staging)
│ │ │ ├── selected.html # Selected products (pre-publish)
│ │ │ └── config.html # Marketplace configuration
│ │ ├── orders.html # Order management
│ │ ├── customers.html # Customer management
│ │ ├── teams.html # Team management
│ │ ├── inventory.html # Inventory management (catalog products)
│ │ ├── payments.html # Payment configuration
│ │ ├── media.html # Media library
│ │ ├── notifications.html # Notification templates & logs
│ │ └── settings.html # Vendor settings
│ ├── shop/ # Customer-facing shop interface
│ │ ├── home.html # Shop homepage
│ │ ├── products.html # Product catalog (Product table only)
│ │ ├── product.html # Product detail page
│ │ ├── search.html # Search results page
│ │ ├── cart.html # Shopping cart
│ │ ├── checkout.html # Checkout process
│ │ └── account/ # Customer account pages
│ │ ├── login.html # Customer login
│ │ ├── register.html # Customer registration
│ │ ├── profile.html # Customer profile
│ │ ├── orders.html # Order history
│ │ └── addresses.html # Address management
│ ├── css/
│ │ ├── admin/ # Admin interface styles
│ │ │ └── admin.css
│ │ ├── vendor/ # Vendor interface styles
│ │ │ └── vendor.css
│ │ ├── shop/ # Customer shop styles
│ │ │ └── shop.css
│ │ ├── shared/ # Common styles (base.css, auth.css)
│ │ │ ├── base.css # CSS variables, utility classes
│ │ │ └── auth.css # Login/auth page styles
│ │ └── themes/ # Vendor-specific themes (future)
│ └── js/
│ ├── shared/ # Common JavaScript utilities
│ │ ├── vendor-context.js # Vendor context detection & management
│ │ ├── api-client.js # API communication utilities
│ │ ├── notification.js # Notification handling
│ │ ├── media-upload.js # File upload utilities
│ │ └── utils.js # General utilities
│ ├── admin/ # Admin interface scripts (Alpine.js components)
│ │ ├── dashboard.js # Admin dashboard
│ │ ├── vendors.js # Vendor management
│ │ ├── audit-logs.js # Audit log viewer (NEW - TO CREATE)
│ │ ├── settings.js # Platform settings (NEW - TO CREATE)
│ │ ├── monitoring.js # System monitoring
│ │ └── analytics.js # Admin analytics
│ ├── vendor/ # Vendor interface scripts (Alpine.js components)
│ │ ├── products.js # Catalog management
│ │ ├── marketplace.js # Marketplace integration
│ │ ├── orders.js # Order management
│ │ ├── payments.js # Payment configuration
│ │ ├── media.js # Media management
│ │ └── dashboard.js # Vendor dashboard
│ └── shop/ # Customer shop scripts (Alpine.js components)
│ ├── catalog.js # Product browsing
│ ├── search.js # Product search
│ ├── cart.js # Shopping cart
│ ├── checkout.js # Checkout process
│ └── account.js # Customer account
├── tests/ # Comprehensive test suite
│ ├── unit/ # Unit tests
│ │ ├── services/ # Service layer tests
│ │ │ ├── test_admin_service.py
│ │ │ ├── test_admin_audit_service.py # NEW
│ │ │ ├── test_admin_settings_service.py # NEW
│ │ │ ├── test_marketplace_service.py
│ │ │ ├── test_product_service.py
│ │ │ ├── test_payment_service.py
│ │ │ ├── test_notification_service.py
│ │ │ ├── test_search_service.py
│ │ │ ├── test_media_service.py
│ │ │ └── test_cache_service.py
│ │ ├── models/ # Model tests
│ │ │ ├── test_admin_models.py # NEW
│ │ │ ├── test_marketplace_product.py
│ │ │ ├── test_product.py
│ │ │ ├── test_payment.py
│ │ │ └── test_vendor.py
│ │ └── api/ # API endpoint tests
│ │ ├── test_admin_api.py
│ │ ├── test_admin_audit_api.py # NEW
│ │ ├── test_admin_settings_api.py # NEW
│ │ ├── test_vendor_api.py
│ │ └── test_public_api.py
│ ├── integration/ # Integration tests
│ │ ├── test_marketplace_workflow.py
│ │ ├── test_order_workflow.py
│ │ ├── test_payment_workflow.py
│ │ ├── test_audit_workflow.py # NEW
│ │ └── test_notification_workflow.py
│ ├── e2e/ # End-to-end tests
│ │ ├── test_vendor_onboarding.py
│ │ ├── test_customer_journey.py
│ │ └── test_admin_operations.py
│ └── fixtures/ # Test data fixtures
│ ├── marketplace_data.py # Sample marketplace import data
│ ├── catalog_data.py # Sample vendor catalog data
│ ├── order_data.py # Sample order data
│ └── user_data.py # Sample user and vendor data
├── scripts/ # Utility scripts
│ ├── init_db.py # Database initialization
│ ├── create_admin.py # Create initial admin user
│ ├── init_platform_settings.py # Create default platform settings
│ ├── backup_database.py # Manual backup script
│ ├── seed_data.py # Development data seeding
│ └── migrate_data.py # Data migration utilities
├── docker/ # Docker configuration
│ ├── Dockerfile # Application container
│ ├── docker-compose.yml # Development environment
│ ├── docker-compose.prod.yml # Production environment
│ └── nginx.conf # Nginx configuration
├── docs/ # Documentation
│ ├── slices/ # Vertical slice documentation
│ │ ├── 00_slices_overview.md
│ │ ├── 00_implementation_roadmap.md
│ │ ├── 01_slice1_admin_vendor_foundation.md
│ │ ├── 02_slice2_marketplace_import.md
│ │ ├── 03_slice3_product_catalog.md
│ │ ├── 04_slice4_customer_shopping.md
│ │ └── 05_slice5_order_processing.md
│ ├── api/ # API documentation
│ ├── deployment/ # Deployment guides
│ ├── development/ # Development setup
│ ├── user_guides/ # User manuals
│ ├── 6.complete_naming_convention.md
│ ├── 10.stripe_payment_integration.md
│ ├── 12.project_readme_final.md
│ ├── 13.updated_application_workflows_final.md
│ └── 14.updated_complete_project_structure_final.md
├── .env.example # Environment variables template
├── requirements.txt # Python dependencies
├── requirements-dev.txt # Development dependencies
├── README.md # Project documentation
└── DEPLOYMENT.md # Deployment instructions
```
## Key Changes from Previous Version
### Admin Infrastructure
**Database Models** (`models/database/admin.py`):
-`AdminAuditLog` - Complete audit trail of all admin actions
-`AdminNotification` - System notifications for admins
-`AdminSetting` - Platform-wide configuration with encryption support
-`PlatformAlert` - System health and issue tracking
-`AdminSession` - Admin login session tracking
**Pydantic Schemas** (`models/schema/admin.py`):
- ✅ Comprehensive request/response models for all admin operations
- ✅ Filtering and pagination schemas
- ✅ Bulk operation schemas (vendor/user actions)
- ✅ System health monitoring schemas
**Services**:
-`admin_audit_service.py` - Audit logging functionality
-`admin_settings_service.py` - Platform settings with type conversion
**API Endpoints**:
-`/api/v1/admin/audit/*` - Audit log querying and filtering
-`/api/v1/admin/settings/*` - Settings CRUD operations
-`/api/v1/admin/notifications/*` - Notifications & alerts (structure ready)
### Naming Convention Fixes
- ✅ Changed `models/schemas/` to `models/schema/` (singular)
- ✅ All schema files now consistently use singular naming
### Current Development Status (Slice 1)
**Completed (✅)**:
- Backend database models (User, Vendor, Role, VendorUser, Admin models)
- JWT authentication with bcrypt
- Admin service layer with audit logging capability
- Admin API endpoints (CRUD, dashboard, audit, settings)
- Vendor context middleware
- Admin login page (Alpine.js)
- Admin dashboard (Alpine.js)
- Admin vendor creation page (Alpine.js)
**In Progress (⏳)**:
- Vendor login page (frontend)
- Vendor dashboard page (frontend)
- Admin audit logs page (frontend)
- Admin platform settings page (frontend)
**To Do (📋)**:
- Complete vendor login/dashboard pages
- Integrate audit logging into existing admin operations
- Create admin audit logs frontend
- Create platform settings frontend
- Full testing of Slice 1
- Deployment to staging
## Architecture Principles
### Multi-Tenancy Model
- **Complete Vendor Isolation**: Each vendor operates independently with no data sharing
- **Chinese Wall**: Strict separation between vendor data and operations
- **Self-Service**: Vendors manage their own teams, products, and marketplace integrations
- **Scalable**: Single codebase serves all vendors with vendor-specific customization
### Data Flow Architecture
```
Marketplace CSV → MarketplaceProduct (staging) → Product (catalog) → Order → Analytics
Admin Audit Logs → Platform Settings → Notifications → Monitoring
```
### API Structure
- **Admin APIs** (`/api/v1/admin/`): Platform-level administration
- Vendor management, user management, audit logs, settings, alerts
- **Vendor APIs** (`/api/v1/vendor/`): Vendor-scoped operations (requires vendor context)
- Products, orders, customers, teams, marketplace integration
- **Public APIs** (`/api/v1/public/vendors/{vendor_id}/`): Customer-facing operations
- Shop, products, cart, orders, checkout
- **Shared APIs** (`/api/v1/shared/`): Utility endpoints (health, webhooks)
### Service Layer Architecture
- **Domain Services**: Each service handles one business domain
- **Cross-Cutting Services**: Audit, cache, monitoring, notifications
- **Integration Services**: Payments, search, storage
### Frontend Architecture
- **Zero Build Step**: Alpine.js from CDN, vanilla CSS, no compilation
- **Server-Side Rendering**: Jinja2 templates with Alpine.js enhancement
- **Context-Aware**: Automatic vendor detection via subdomain or path
- **Dynamic Theming**: Vendor-specific customization via CSS variables
- **Role-Based UI**: Permission-driven interface elements
## Key Features
### Core Business Features
- Multi-vendor marketplace with complete isolation
- Marketplace product import and curation workflow
- Comprehensive order and payment processing
- Customer management with vendor-scoped accounts
- Team management with role-based permissions
- Inventory tracking and management
### Advanced Features
- Email notification system with vendor branding
- File and media management with CDN integration
- Advanced search with Elasticsearch
- Multi-layer caching for performance
- Comprehensive audit logging for compliance
- Real-time monitoring and alerting
- Automated backup and disaster recovery
- Configuration management with feature flags
### Security Features
- JWT-based authentication with vendor context
- Role-based access control with granular permissions
- Complete vendor data isolation at all layers
- Audit trails for all operations
- Secure file storage with access controls
- Rate limiting and abuse prevention
### Integration Capabilities
- Stripe Connect for multi-vendor payments
- Marketplace integrations (Letzshop with extensible framework)
- Multiple storage backends (Local, S3, GCS)
- Search engines (Elasticsearch with database fallback)
- Email providers (SendGrid, SMTP)
- Monitoring and alerting systems
## Technology Integration
### Database Layer
- **PostgreSQL**: Primary database with ACID compliance (SQLite for development)
- **Redis**: Caching and session storage
- **Elasticsearch**: Search and analytics (optional)
### Background Processing
- **Celery**: Distributed task processing
- **Redis**: Message broker and result backend
- **Monitoring**: Task progress and error tracking
### External Services
- **Stripe Connect**: Multi-vendor payment processing
- **SendGrid/SMTP**: Email delivery with vendor branding
- **AWS S3/GCS**: Cloud storage for media files
- **CloudFront/CloudFlare**: CDN for static assets
### Monitoring & Compliance
- **Admin Audit Logs**: Complete trail of all admin actions
- **Platform Settings**: Centralized configuration management
- **System Alerts**: Automated health monitoring
- **Error Tracking**: Comprehensive error logging
## Deployment Modes
### Development Mode
- **Path-based routing**: `localhost:8000/vendor/vendorname/`
- **Admin access**: `localhost:8000/admin/`
- **Easy context switching**: Clear vendor separation in URLs
- **Local storage**: Files stored locally with hot reload
### Production Mode
- **Subdomain routing**: `vendorname.platform.com`
- **Admin subdomain**: `admin.platform.com`
- **Custom domains**: `customdomain.com` (enterprise feature)
- **CDN integration**: Optimized asset delivery
- **Distributed caching**: Redis cluster for performance
- **Automated backups**: Scheduled database and file backups
This structure provides a robust foundation for a scalable, multi-tenant ecommerce platform with enterprise-grade features while maintaining clean separation of concerns and supporting multiple deployment modes.

File diff suppressed because it is too large Load Diff

View File

@@ -1,399 +0,0 @@
# Work Plan - October 22, 2025
## Jinja2 Migration: Polish & Complete Admin Panel
**Current Status:** Core migration complete ✅ | Auth loop fixed ✅ | Minor issues remaining ⚠️
---
## 🎯 Today's Goals
1. ✅ Fix icon system and utils.js conflicts
2. ✅ Test and verify logout flow
3. ✅ Test all admin pages (vendors, users)
4. ✅ Create remaining templates
5. ✅ Clean up and remove old code
**Estimated Time:** 3-4 hours
---
## 📋 Task List
### Priority 1: Fix Icon/Utils Conflicts (HIGH) ⚠️
**Issue Reported:**
> "Share some outputs about $icons issues and utils already declared"
#### Task 1.1: Investigate Icon Issues
- [ ] Check browser console for icon-related errors
- [ ] Verify `icons.js` is loaded only once
- [ ] Check for duplicate `window.icon` declarations
- [ ] Test icon rendering in all templates
**Files to Check:**
- `static/shared/js/icons.js`
- `app/templates/admin/base.html` (script order)
- `app/templates/admin/login.html` (script order)
**Expected Issues:**
```javascript
// Possible duplicate declaration
Uncaught SyntaxError: Identifier 'icon' has already been declared
// or
Warning: window.icon is already defined
```
**Fix:**
- Ensure `icons.js` loaded only once per page
- Remove any duplicate `icon()` function declarations
- Verify Alpine magic helper `$icon()` is registered correctly
#### Task 1.2: Investigate Utils Issues
- [ ] Check for duplicate `Utils` object declarations
- [ ] Verify `utils.js` loaded only once
- [ ] Test all utility functions (formatDate, showToast, etc.)
**Files to Check:**
- `static/shared/js/utils.js`
- `static/shared/js/api-client.js` (Utils defined here too?)
**Potential Fix:**
```javascript
// Option 1: Use namespace to avoid conflicts
if (typeof window.Utils === 'undefined') {
window.Utils = { /* ... */ };
}
// Option 2: Remove duplicate definitions
// Keep Utils only in one place (either utils.js OR api-client.js)
```
---
### Priority 2: Test Logout Flow (HIGH) 🔐
#### Task 2.1: Test Logout Button
- [ ] Click logout in header
- [ ] Verify cookie is deleted
- [ ] Verify localStorage is cleared
- [ ] Verify redirect to login page
- [ ] Verify cannot access dashboard after logout
**Test Script:**
```javascript
// Before logout
console.log('Cookie:', document.cookie);
console.log('localStorage:', localStorage.getItem('admin_token'));
// Click logout
// After logout (should be empty)
console.log('Cookie:', document.cookie); // Should not contain admin_token
console.log('localStorage:', localStorage.getItem('admin_token')); // Should be null
```
#### Task 2.2: Update Logout Endpoint (if needed)
**File:** `app/api/v1/admin/auth.py`
Already implemented, just verify:
```python
@router.post("/logout")
def admin_logout(response: Response):
# Clears the cookie
response.delete_cookie(key="admin_token", path="/")
return {"message": "Logged out successfully"}
```
#### Task 2.3: Update Header Logout Button
**File:** `app/templates/partials/header.html`
Verify logout button calls the correct endpoint:
```html
<button @click="handleLogout()">
Logout
</button>
<script>
function handleLogout() {
// Call logout API
fetch('/api/v1/admin/auth/logout', { method: 'POST' })
.then(() => {
// Clear localStorage
localStorage.clear();
// Redirect
window.location.href = '/admin/login';
});
}
</script>
```
---
### Priority 3: Test All Admin Pages (MEDIUM) 📄
#### Task 3.1: Test Vendors Page
- [ ] Navigate to `/admin/vendors`
- [ ] Verify page loads with authentication
- [ ] Check if template exists or needs creation
- [ ] Test vendor list display
- [ ] Test vendor creation button
**If template missing:**
Create `app/templates/admin/vendors.html`
#### Task 3.2: Test Users Page
- [ ] Navigate to `/admin/users`
- [ ] Verify page loads with authentication
- [ ] Check if template exists or needs creation
- [ ] Test user list display
**If template missing:**
Create `app/templates/admin/users.html`
#### Task 3.3: Test Navigation
- [ ] Click all sidebar links
- [ ] Verify no 404 errors
- [ ] Verify active state highlights correctly
- [ ] Test breadcrumbs (if applicable)
---
### Priority 4: Create Missing Templates (MEDIUM) 📝
#### Task 4.1: Create Vendors Template
**File:** `app/templates/admin/vendors.html`
```jinja2
{% extends "admin/base.html" %}
{% block title %}Vendors Management{% endblock %}
{% block alpine_data %}adminVendors(){% endblock %}
{% block content %}
<div class="my-6">
<h2 class="text-2xl font-semibold text-gray-700 dark:text-gray-200">
Vendors Management
</h2>
</div>
<!-- Vendor list content -->
<div x-data="adminVendors()">
<!-- Your existing vendors.html content here -->
</div>
{% endblock %}
{% block extra_scripts %}
<script src="{{ url_for('static', path='admin/js/vendors.js') }}"></script>
{% endblock %}
```
#### Task 4.2: Create Users Template
**File:** `app/templates/admin/users.html`
Similar structure to vendors template.
#### Task 4.3: Verify Vendor Edit Page
Check if vendor-edit needs a template or if it's a modal/overlay.
---
### Priority 5: Cleanup (LOW) 🧹
#### Task 5.1: Remove Old Static HTML Files
- [ ] Delete `static/admin/dashboard.html` (if exists)
- [ ] Delete `static/admin/vendors.html` (if exists)
- [ ] Delete `static/admin/users.html` (if exists)
- [ ] Delete `static/admin/partials/` directory
**Before deleting:** Backup files just in case!
#### Task 5.2: Remove Partial Loader
- [ ] Delete `static/shared/js/partial-loader.js`
- [ ] Remove any references to `partialLoader` in code
- [ ] Search codebase: `grep -r "partial-loader" .`
#### Task 5.3: Clean Up frontend.py
**File:** `app/routes/frontend.py`
- [ ] Remove commented-out admin routes
- [ ] Or delete file entirely if only contained admin routes
- [ ] Update imports if needed
#### Task 5.4: Production Mode Preparation
- [ ] Set log levels to production (INFO or WARN)
- [ ] Update cookie `secure=True` for production
- [ ] Remove debug console.logs
- [ ] Test with production settings
**Update log levels:**
```javascript
// static/admin/js/log-config.js
GLOBAL_LEVEL: isDevelopment ? 4 : 2, // Debug in dev, Warnings in prod
LOGIN: isDevelopment ? 4 : 1, // Full debug in dev, errors only in prod
API_CLIENT: isDevelopment ? 3 : 1, // Info in dev, errors only in prod
```
---
## 🧪 Testing Checklist
### Comprehensive Testing
- [ ] Fresh login (clear all data first)
- [ ] Dashboard loads correctly
- [ ] Stats cards display data
- [ ] Recent vendors table works
- [ ] Sidebar navigation works
- [ ] Dark mode toggle works
- [ ] Logout clears auth and redirects
- [ ] Cannot access dashboard after logout
- [ ] Vendors page loads
- [ ] Users page loads
- [ ] No console errors
- [ ] No 404 errors in Network tab
- [ ] Icons display correctly
- [ ] All Alpine.js components work
### Browser Testing
- [ ] Chrome/Edge
- [ ] Firefox
- [ ] Safari (if available)
- [ ] Mobile view (responsive)
---
## 🐛 Debugging Guide
### If Icons Don't Display:
```javascript
// Check in console:
console.log('window.icon:', typeof window.icon);
console.log('window.Icons:', typeof window.Icons);
console.log('$icon available:', typeof Alpine !== 'undefined' && Alpine.magic('icon'));
// Test manually:
document.body.innerHTML += window.icon('home', 'w-6 h-6');
```
### If Utils Undefined:
```javascript
// Check in console:
console.log('Utils:', typeof Utils);
console.log('Utils methods:', Object.keys(Utils || {}));
// Test manually:
Utils.showToast('Test message', 'info');
```
### If Auth Fails:
```javascript
// Check storage:
console.log('localStorage token:', localStorage.getItem('admin_token'));
console.log('Cookie:', document.cookie);
// Test API manually:
fetch('/api/v1/admin/auth/me', {
headers: { 'Authorization': `Bearer ${localStorage.getItem('admin_token')}` }
}).then(r => r.json()).then(console.log);
```
---
## 📝 Documentation Tasks
### Update Documentation
- [ ] Update project README with new architecture
- [ ] Document authentication flow (cookies + localStorage)
- [ ] Document template structure
- [ ] Add deployment notes (dev vs production)
- [ ] Update API documentation if needed
### Code Comments
- [ ] Add comments to complex authentication code
- [ ] Document cookie settings and rationale
- [ ] Explain dual token storage pattern
- [ ] Add JSDoc comments to JavaScript functions
---
## 🚀 Next Phase Preview (After Today)
### Vendor Portal Migration
1. Apply same Jinja2 pattern to vendor routes
2. Create vendor templates (login, dashboard, etc.)
3. Implement vendor authentication (separate cookie: `vendor_token`)
4. Test vendor flows
### Customer/Shop Migration
1. Customer authentication system
2. Shop templates
3. Shopping cart (consider cookie vs localStorage)
4. "Remember Me" implementation
### Advanced Features
1. "Remember Me" checkbox (30-day cookies)
2. Session management
3. Multiple device logout
4. Security enhancements (CSRF tokens)
---
## ⏰ Time Estimates
| Task | Estimated Time | Priority |
|------|---------------|----------|
| Fix icon/utils issues | 30-45 min | HIGH |
| Test logout flow | 15-30 min | HIGH |
| Test admin pages | 30 min | MEDIUM |
| Create missing templates | 45-60 min | MEDIUM |
| Cleanup old code | 30 min | LOW |
| Testing & verification | 30-45 min | HIGH |
| Documentation | 30 min | LOW |
**Total: 3-4 hours**
---
## ✅ Success Criteria for Today
By end of day, we should have:
- [ ] All icons displaying correctly
- [ ] No JavaScript errors in console
- [ ] Logout flow working perfectly
- [ ] All admin pages accessible and working
- [ ] Templates for vendors and users pages
- [ ] Old code cleaned up
- [ ] Comprehensive testing completed
- [ ] Documentation updated
---
## 🎯 Stretch Goals (If Time Permits)
1. Add loading states to all buttons
2. Improve error messages (user-friendly)
3. Add success/error toasts to all operations
4. Implement "Remember Me" checkbox
5. Start vendor portal migration
6. Add unit tests for authentication
---
## 📞 Support Resources
### If Stuck:
- Review yesterday's complete file implementations
- Check browser console for detailed logs (log level 4)
- Use test-auth-flow.html for systematic testing
- Check Network tab for HTTP requests/responses
### Reference Files:
- `static/admin/test-auth-flow.html` - Testing interface
- `TESTING_CHECKLIST.md` - Systematic testing guide
- Yesterday's complete file updates (in conversation)
---
**Good luck with today's tasks! 🚀**
Remember: Take breaks, test

View File

@@ -1,520 +0,0 @@
# Jinja2 Migration Progress - Admin Panel
**Date:** October 20, 2025
**Project:** Multi-Tenant E-commerce Platform
**Goal:** Migrate from static HTML files to Jinja2 server-rendered templates
---
## 🎯 Current Status: DEBUGGING AUTH LOOP
We successfully set up the Jinja2 infrastructure but are experiencing authentication redirect loops. We're in the process of simplifying the auth flow to resolve this.
---
## ✅ What's Been Completed
### 1. Infrastructure Setup ✅
- [x] Added Jinja2Templates to `main.py`
- [x] Created `app/templates/` directory structure
- [x] Created `app/api/v1/admin/pages.py` for HTML routes
- [x] Integrated pages router into the main app
**Files Created:**
```
app/
├── templates/
│ ├── admin/
│ │ ├── base.html ✅ Created
│ │ ├── login.html ✅ Created
│ │ └── dashboard.html ✅ Created
│ └── partials/
│ ├── header.html ✅ Moved from static
│ └── sidebar.html ✅ Moved from static
└── api/
└── v1/
└── admin/
└── pages.py ✅ Created
```
### 2. Route Configuration ✅
**New Jinja2 Routes (working):**
- `/admin/` → redirects to `/admin/dashboard`
- `/admin/login` → login page (no auth)
- `/admin/dashboard` → dashboard page (requires auth)
- `/admin/vendors` → vendors page (requires auth)
- `/admin/users` → users page (requires auth)
**Old Static Routes (disabled):**
- Commented out admin routes in `app/routes/frontend.py`
- Old `/static/admin/*.html` routes no longer active
### 3. Exception Handler Updates ✅
- [x] Updated `app/exceptions/handler.py` to redirect HTML requests on 401
- [x] Added `_is_html_page_request()` helper function
- [x] Server-side redirects working for unauthenticated page access
### 4. JavaScript Updates ✅
Updated all JavaScript files to use new routes:
**Files Updated:**
- `static/admin/js/dashboard.js` - viewVendor() uses `/admin/vendors`
- `static/admin/js/login.js` - redirects to `/admin/dashboard`
- `static/admin/js/vendors.js` - auth checks use `/admin/login`
- `static/admin/js/vendor-edit.js` - all redirects updated
- `static/shared/js/api-client.js` - handleUnauthorized() uses `/admin/login`
### 5. Template Structure ✅
**Base Template (`app/templates/admin/base.html`):**
- Server-side includes for header and sidebar (no more AJAX loading!)
- Proper script loading order
- Alpine.js integration
- No more `partial-loader.js`
**Dashboard Template (`app/templates/admin/dashboard.html`):**
- Extends base template
- Uses Alpine.js `adminDashboard()` component
- Stats cards and recent vendors table
**Login Template (`app/templates/admin/login.html`):**
- Standalone page (doesn't extend base)
- Uses Alpine.js `adminLogin()` component
---
## ❌ Current Problem: Authentication Loop
### Issue Description
Getting infinite redirect loops in various scenarios:
1. After login → redirects back to login
2. On login page → continuous API calls to `/admin/auth/me`
3. Dashboard → redirects to login → redirects to dashboard
### Root Causes Identified
1. **Multiple redirect handlers fighting:**
- Server-side: `handler.py` redirects on 401 for HTML pages
- Client-side: `api-client.js` also redirects on 401
- Both triggering simultaneously
2. **Login page checking auth on init:**
- Calls `/admin/auth/me` on page load
- Gets 401 → triggers redirect
- Creates loop
3. **Token not being sent properly:**
- Token stored but API calls not including it
- Gets 401 even with valid token
### Latest Approach (In Progress)
Simplifying to minimal working version:
- Login page does NOTHING on init (no auth checking)
- API client does NOT redirect (just throws errors)
- Server ONLY redirects browser HTML requests (not API calls)
- One source of truth for auth handling
---
## 📝 Files Modified (Complete List)
### Backend Files
1. **`main.py`**
```python
# Added:
- Jinja2Templates import and configuration
- admin_pages router include at /admin prefix
```
2. **`app/api/main.py`** (unchanged - just includes v1 routes)
3. **`app/api/v1/admin/__init__.py`**
```python
# Added:
- import pages
- router.include_router(pages.router, tags=["admin-pages"])
```
4. **`app/api/v1/admin/pages.py`** (NEW FILE)
```python
# Contains:
- @router.get("/") - root redirect
- @router.get("/login") - login page
- @router.get("/dashboard") - dashboard page
- @router.get("/vendors") - vendors page
- @router.get("/users") - users page
```
5. **`app/routes/frontend.py`**
```python
# Changed:
- Commented out all /admin/ routes
- Left vendor and shop routes active
```
6. **`app/exceptions/handler.py`**
```python
# Added:
- 401 redirect logic for HTML pages
- _is_html_page_request() helper
# Status: Needs simplification
```
### Frontend Files
1. **`static/admin/js/login.js`**
```javascript
// Changed:
- Removed /static/admin/ paths
- Updated to /admin/ paths
- checkExistingAuth() logic
# Status: Needs simplification
```
2. **`static/admin/js/dashboard.js`**
```javascript
// Changed:
- viewVendor() uses /admin/vendors
# Status: Working
```
3. **`static/admin/js/vendors.js`**
```javascript
// Changed:
- checkAuth() redirects to /admin/login
- handleLogout() redirects to /admin/login
# Status: Not tested yet
```
4. **`static/admin/js/vendor-edit.js`**
```javascript
// Changed:
- All /static/admin/ paths to /admin/
# Status: Not tested yet
```
5. **`static/shared/js/api-client.js`**
```javascript
// Changed:
- handleUnauthorized() uses /admin/login
# Status: Needs simplification - causing loops
```
6. **`static/shared/js/utils.js`** (unchanged - working fine)
### Template Files (NEW)
1. **`app/templates/admin/base.html`** ✅
- Master layout with sidebar and header
- Script loading in correct order
- No partial-loader.js
2. **`app/templates/admin/login.html`** ✅
- Standalone login page
- Alpine.js adminLogin() component
3. **`app/templates/admin/dashboard.html`** ✅
- Extends base.html
- Alpine.js adminDashboard() component
4. **`app/templates/partials/header.html`** ✅
- Top navigation bar
- Updated logout link to /admin/login
5. **`app/templates/partials/sidebar.html`** ✅
- Side navigation menu
- Updated all links to /admin/* paths
---
## 🔧 Next Steps (Tomorrow)
### Immediate Priority: Fix Auth Loop
Apply the simplified approach from the last message:
1. **Simplify `login.js`:**
```javascript
// Remove all auth checking on init
// Just show login form
// Only redirect after successful login
```
2. **Simplify `api-client.js`:**
```javascript
// Remove handleUnauthorized() redirect logic
// Just throw errors, don't redirect
// Let server handle redirects
```
3. **Simplify `handler.py`:**
```javascript
// Only redirect browser HTML requests (text/html accept header)
// Don't redirect API calls (application/json)
// Don't redirect if already on login page
```
**Test Flow:**
1. Navigate to `/admin/login` → should show form (no loops)
2. Login → should redirect to `/admin/dashboard`
3. Dashboard → should load with sidebar/header
4. No console errors, no 404s for partials
### After Auth Works
1. **Create remaining page templates:**
- `app/templates/admin/vendors.html`
- `app/templates/admin/users.html`
- `app/templates/admin/vendor-edit.html`
2. **Test all admin flows:**
- Login ✓
- Dashboard ✓
- Vendors list
- Vendor create
- Vendor edit
- User management
3. **Cleanup:**
- Remove old static HTML files
- Remove `app/routes/frontend.py` admin routes completely
- Remove `partial-loader.js`
4. **Migrate vendor portal:**
- Same process for `/vendor/*` routes
- Create vendor templates
- Update vendor JavaScript files
---
## 📚 Key Learnings
### What Worked
1. ✅ **Server-side template rendering** - Clean, fast, no AJAX for partials
2. ✅ **Jinja2 integration** - Easy to set up, works with FastAPI
3. ✅ **Route separation** - HTML routes in `pages.py`, API routes separate
4. ✅ **Template inheritance** - `base.html` + `{% extends %}` pattern
### What Caused Issues
1. ❌ **Multiple redirect handlers** - Client + server both handling 401
2. ❌ **Auth checking on login page** - Created loops
3. ❌ **Complex error handling** - Too many places making decisions
4. ❌ **Path inconsistencies** - Old `/static/admin/` vs new `/admin/`
### Best Practices Identified
1. **Single source of truth for redirects** - Choose server OR client, not both
2. **Login page should be dumb** - No auth checking, just show form
3. **API client should be simple** - Fetch data, throw errors, don't redirect
4. **Server handles page-level auth** - FastAPI dependencies + exception handler
5. **Clear separation** - HTML pages vs API endpoints
---
## 🗂️ Project Structure (Current)
```
project/
├── main.py ✅ Updated
├── app/
│ ├── api/
│ │ ├── main.py ✅ Unchanged
│ │ └── v1/
│ │ └── admin/
│ │ ├── __init__.py ✅ Updated
│ │ ├── pages.py ✅ NEW
│ │ ├── auth.py ✅ Existing (API routes)
│ │ ├── vendors.py ✅ Existing (API routes)
│ │ └── dashboard.py ✅ Existing (API routes)
│ ├── routes/
│ │ └── frontend.py ⚠️ Partially disabled
│ ├── exceptions/
│ │ └── handler.py ⚠️ Needs simplification
│ └── templates/ ✅ NEW
│ ├── admin/
│ │ ├── base.html
│ │ ├── login.html
│ │ └── dashboard.html
│ └── partials/
│ ├── header.html
│ └── sidebar.html
└── static/
├── admin/
│ ├── js/
│ │ ├── login.js ⚠️ Needs simplification
│ │ ├── dashboard.js ✅ Updated
│ │ ├── vendors.js ✅ Updated
│ │ └── vendor-edit.js ✅ Updated
│ └── css/
│ └── tailwind.output.css ✅ Unchanged
└── shared/
└── js/
├── api-client.js ⚠️ Needs simplification
├── utils.js ✅ Working
└── icons.js ✅ Working
```
**Legend:**
- ✅ = Working correctly
- ⚠️ = Needs attention/debugging
- ❌ = Not working/causing issues
---
## 🐛 Debug Commands
### Clear localStorage (Browser Console)
```javascript
localStorage.clear();
```
### Check stored tokens
```javascript
console.log('admin_token:', localStorage.getItem('admin_token'));
console.log('admin_user:', localStorage.getItem('admin_user'));
```
### Test API call manually
```javascript
fetch('/api/v1/admin/auth/me', {
headers: {
'Authorization': `Bearer ${localStorage.getItem('admin_token')}`
}
}).then(r => r.json()).then(d => console.log(d));
```
### Check current route
```javascript
console.log('Current path:', window.location.pathname);
console.log('Full URL:', window.location.href);
```
---
## 📖 Reference: Working Code Snippets
### Minimal Login.js (To Try Tomorrow)
```javascript
function adminLogin() {
return {
dark: false,
credentials: { username: '', password: '' },
loading: false,
error: null,
success: null,
errors: {},
init() {
this.dark = localStorage.getItem('theme') === 'dark';
// NO AUTH CHECKING - just show form
},
async handleLogin() {
if (!this.validateForm()) return;
this.loading = true;
try {
const response = await fetch('/api/v1/admin/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: this.credentials.username,
password: this.credentials.password
})
});
const data = await response.json();
if (!response.ok) throw new Error(data.message);
localStorage.setItem('admin_token', data.access_token);
localStorage.setItem('admin_user', JSON.stringify(data.user));
this.success = 'Login successful!';
setTimeout(() => window.location.href = '/admin/dashboard', 500);
} catch (error) {
this.error = error.message;
} finally {
this.loading = false;
}
}
}
}
```
### Simplified API Client Request Method
```javascript
async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const config = {
...options,
headers: this.getHeaders(options.headers)
};
const response = await fetch(url, config);
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || 'Request failed');
}
return data;
// NO REDIRECT LOGIC HERE!
}
```
### Simplified Exception Handler
```python
if exc.status_code == 401:
accept_header = request.headers.get("accept", "")
is_browser = "text/html" in accept_header
if is_browser and not request.url.path.endswith("/login"):
if request.url.path.startswith("/admin"):
return RedirectResponse(url="/admin/login", status_code=302)
# Return JSON for API calls
return JSONResponse(status_code=exc.status_code, content=exc.to_dict())
```
---
## 💡 Questions to Answer Tomorrow
1. Does the simplified auth flow work without loops?
2. Can we successfully login and access dashboard?
3. Are tokens being sent correctly in API requests?
4. Do we need the auth check on login page at all?
5. Should we move ALL redirect logic to server-side?
---
## 🎯 Success Criteria
The migration will be considered successful when:
- [ ] Login page loads without loops
- [ ] Login succeeds and redirects to dashboard
- [ ] Dashboard displays with sidebar and header
- [ ] No 404 errors for partials
- [ ] Icons display correctly
- [ ] Stats cards load data from API
- [ ] Navigation between admin pages works
- [ ] Logout works correctly
---
**End of Session - October 20, 2025**
Good work today! We made significant progress on the infrastructure. Tomorrow we'll resolve the auth loop and complete the admin panel migration.

View File

@@ -1,392 +0,0 @@
# Multi-Tenant Ecommerce Platform - Complete Naming Convention Guide
## Overview
This document establishes consistent naming conventions across the entire multi-tenant ecommerce platform. Consistent naming improves code readability, reduces developer confusion, and ensures maintainable architecture.
## Core Principles
### 1. Context-Based Naming
- **Collections/Endpoints**: Use PLURAL (handle multiple items)
- **Entities/Models**: Use SINGULAR (represent individual items)
- **Domains/Services**: Use SINGULAR (focus on one domain area)
### 2. Terminology Standardization
- Use **"inventory"** not "stock" (more business-friendly)
- Use **"vendor"** not "shop" (multi-tenant architecture)
- Use **"customer"** not "user" for end customers (clarity)
### 3. File Naming Patterns
- **API files**: `entities.py` (plural)
- **Model files**: `entity.py` (singular)
- **Service files**: `entity_service.py` (singular + service)
- **Exception files**: `entity.py` (singular domain)
## Detailed Naming Rules
### API Endpoint Files (PLURAL)
**Rule**: API files handle collections of resources, so use plural names.
**Location**: `app/api/v1/*/`
**Examples**:
```
app/api/v1/admin/
├── vendors.py # Handles multiple vendors
├── users.py # Handles multiple users
└── dashboard.py # Exception: not a resource collection
app/api/v1/vendor/
├── products.py # Handles vendor's products
├── orders.py # Handles vendor's orders
├── customers.py # Handles vendor's customers
├── teams.py # Handles team members
├── inventory.py # Handles inventory items
└── settings.py # Exception: not a resource collection
app/api/v1/public/vendors/
├── products.py # Public product catalog
├── orders.py # Order placement
└── auth.py # Exception: authentication service
```
**Rationale**: REST endpoints typically operate on collections (`GET /products`, `POST /orders`).
### Database Model Files (SINGULAR)
**Rule**: Model files represent individual entity definitions, so use singular names.
**Location**: `models/database/`
**Examples**:
```
models/database/
├── user.py # User, UserProfile classes
├── vendor.py # Vendor, VendorUser, Role classes
├── customer.py # Customer, CustomerAddress classes
├── product.py # Product, ProductVariant classes
├── order.py # Order, OrderItem classes
├── inventory.py # Inventory, InventoryMovement classes
├── marketplace.py # MarketplaceImportJob class
└── admin.py # Admin-specific models
```
**Class Names Within Files**:
```python
# models/database/product.py
class Product(Base): # Singular
class ProductVariant(Base): # Singular
# models/database/inventory.py
class Inventory(Base): # Singular
class InventoryMovement(Base): # Singular
```
**Rationale**: Each model class represents a single entity instance in the database.
### Schema/Pydantic Model Files (SINGULAR)
**Rule**: Schema files define validation for individual entities, so use singular names.
**Location**: `models/schema/`
**Examples**:
```
models/schema/
├── user.py # UserCreate, UserResponse classes
├── vendor.py # VendorCreate, VendorResponse classes
├── customer.py # CustomerCreate, CustomerResponse classes
├── product.py # ProductCreate, ProductResponse classes
├── order.py # OrderCreate, OrderResponse classes
├── inventory.py # InventoryCreate, InventoryResponse classes
├── marketplace.py # MarketplaceImportRequest class
└── admin.py # Admin operation schemas
```
**Class Names Within Files**:
```python
# models/schema/product.py
class ProductCreate(BaseModel): # Singular entity
class ProductUpdate(BaseModel): # Singular entity
class ProductResponse(BaseModel): # Singular entity
```
**Rationale**: Schema models validate individual entity data structures.
### Service Files (SINGULAR + "service")
**Rule**: Service files handle business logic for one domain area, so use singular + "service".
**Location**: `services/`
**Examples**:
```
services/
├── auth_service.py # Authentication domain
├── admin_service.py # Admin operations domain
├── vendor_service.py # Vendor management domain
├── customer_service.py # Customer operations domain
├── team_service.py # Team management domain
├── product_service.py # Product operations domain
├── order_service.py # Order operations domain
├── inventory_service.py # Inventory operations domain
├── marketplace_service.py # Marketplace integration domain
└── stats_service.py # Statistics domain
```
**Class Names Within Files**:
```python
# services/product_service.py
class ProductService: # Singular domain focus
def create_product() # Operates on single product
def get_products() # Can return multiple, but service is singular
```
**Rationale**: Each service focuses on one business domain area.
### Exception Files (SINGULAR)
**Rule**: Exception files handle errors for one domain area, so use singular names.
**Location**: `app/exceptions/`
**Examples**:
```
app/exceptions/
├── base.py # Base exception classes
├── handler.py # Exception handlers
├── auth.py # Authentication domain exceptions
├── admin.py # Admin domain exceptions
├── vendor.py # Vendor domain exceptions
├── customer.py # Customer domain exceptions
├── product.py # Product domain exceptions
├── order.py # Order domain exceptions
├── inventory.py # Inventory domain exceptions
└── marketplace.py # Marketplace domain exceptions
```
**Class Names Within Files**:
```python
# app/exceptions/product.py
class ProductNotFoundException(ResourceNotFoundException):
class ProductAlreadyExistsException(ConflictException):
class ProductValidationException(ValidationException):
```
**Rationale**: Exception files are domain-focused, not collection-focused.
### Middleware Files (DESCRIPTIVE)
**Rule**: Middleware files use descriptive names based on their function.
**Location**: `middleware/`
**Examples**:
```
middleware/
├── auth.py # Authentication middleware
├── vendor_context.py # Vendor context detection
├── rate_limiter.py # Rate limiting functionality
├── logging_middleware.py # Request logging
└── decorators.py # Cross-cutting decorators
```
**Rationale**: Middleware serves specific cross-cutting functions.
### Frontend Files
**Rule**: Frontend files use context-appropriate naming.
**Location**: `frontend/`
**Examples**:
```
frontend/
├── admin/
│ ├── vendors.html # PLURAL - lists multiple vendors
│ ├── users.html # PLURAL - lists multiple users
│ └── dashboard.html # SINGULAR - one dashboard
├── vendor/admin/
│ ├── products.html # PLURAL - lists multiple products
│ ├── orders.html # PLURAL - lists multiple orders
│ ├── teams.html # PLURAL - lists team members
│ └── dashboard.html # SINGULAR - one dashboard
└── shop/
├── products.html # PLURAL - product catalog
├── product.html # SINGULAR - single product detail
├── orders.html # PLURAL - order history
└── cart.html # SINGULAR - one shopping cart
```
**Rationale**:
- List views are plural (show collections)
- Detail views are singular (show individual items)
- Functional views use descriptive names
## Terminology Standards
### Core Business Terms
| Use This | Not This | Context |
|----------|----------|---------|
| inventory | stock | All inventory management |
| vendor | shop | Multi-tenant architecture |
| customer | user | End customers (buyers) |
| user | member | Platform/vendor team members |
| team | staff | Vendor team members |
| order | purchase | Customer orders |
| product | item | Catalog products |
### Database Naming
**Table Names**: Use singular, lowercase with underscores
```sql
-- Correct
inventory
inventory_movements
vendor_users
-- Incorrect
inventories
inventory_movement
vendorusers
```
**Column Names**: Use singular, descriptive names
```sql
-- Correct
vendor_id
inventory_level
created_at
-- Incorrect
vendors_id
inventory_levels
creation_time
```
### API Endpoint Patterns
**Resource Collections**: Use plural nouns
```
GET /api/v1/vendor/products # List products
POST /api/v1/vendor/products # Create product
GET /api/v1/vendor/orders # List orders
POST /api/v1/vendor/orders # Create order
```
**Individual Resources**: Use singular in URL structure
```
GET /api/v1/vendor/products/{id} # Get single product
PUT /api/v1/vendor/products/{id} # Update single product
DELETE /api/v1/vendor/products/{id} # Delete single product
```
**Non-Resource Endpoints**: Use descriptive names
```
GET /api/v1/vendor/dashboard/stats # Dashboard statistics
POST /api/v1/vendor/auth/login # Authentication
GET /api/v1/vendor/settings # Vendor settings
```
## Variable and Function Naming
### Function Names
```python
# Correct - verb + singular object
def create_product()
def get_customer()
def update_order()
def delete_inventory_item()
# Correct - verb + plural when operating on collections
def get_products()
def list_customers()
def bulk_update_orders()
# Incorrect
def create_products() # Creates one product
def get_customers() # Gets one customer
```
### Variable Names
```python
# Correct - context-appropriate singular/plural
product = get_product(id)
products = get_products()
customer_list = get_all_customers()
inventory_count = len(inventory_items)
# Incorrect
products = get_product(id) # Single item, should be singular
product = get_products() # Multiple items, should be plural
```
### Class Attributes
```python
# Correct - descriptive and consistent
class Vendor:
id: int
name: str
subdomain: str
owner_user_id: int # Singular reference
created_at: datetime
class Customer:
vendor_id: int # Belongs to one vendor
total_orders: int # Aggregate count
last_order_date: datetime # Most recent
```
## Migration Checklist
When applying these naming conventions to existing code:
### File Renames Required
- [ ] `app/api/v1/stock.py``app/api/v1/inventory.py`
- [ ] `models/database/stock.py``models/database/inventory.py`
- [ ] `models/schema/stock.py``models/schema/inventory.py`
- [ ] `services/stock_service.py``services/inventory_service.py`
- [ ] `app/exceptions/stock.py``app/exceptions/inventory.py`
### Import Statement Updates
- [ ] Update all `from models.database.stock import` statements
- [ ] Update all `from services.stock_service import` statements
- [ ] Update all `stock_` variable prefixes to `inventory_`
### Class Name Updates
- [ ] `Stock``Inventory`
- [ ] `StockMovement``InventoryMovement`
- [ ] `StockService``InventoryService`
### Database Updates
- [ ] Rename `stock` table to `inventory`
- [ ] Rename `stock_movements` table to `inventory_movements`
- [ ] Update all `stock_id` foreign keys to `inventory_id`
### Frontend Updates
- [ ] Update all HTML files with stock terminology
- [ ] Update JavaScript variable names
- [ ] Update CSS class names if applicable
## Benefits of Consistent Naming
1. **Developer Productivity**: Predictable file locations and naming patterns
2. **Code Readability**: Clear understanding of file purposes and contents
3. **Team Communication**: Shared vocabulary and terminology
4. **Maintenance**: Easier to locate and update related functionality
5. **Onboarding**: New developers quickly understand the codebase structure
6. **Documentation**: Consistent terminology across all documentation
7. **API Usability**: Predictable and intuitive API endpoint structures
## Enforcement
### Code Review Checklist
- [ ] File names follow singular/plural conventions
- [ ] Class names use appropriate terminology (inventory vs stock)
- [ ] API endpoints use plural resource names
- [ ] Database models use singular names
- [ ] Variables names match their content (singular vs plural)
### Automated Checks
Consider implementing linting rules or pre-commit hooks to enforce:
- File naming patterns
- Import statement consistency
- Variable naming conventions
- API endpoint patterns
This naming convention guide ensures consistent, maintainable, and intuitive code across the entire multi-tenant ecommerce platform.

View File

@@ -1,649 +0,0 @@
# Admin Models Integration Guide
## What We've Added
You now have:
1. **Database Models** (`models/database/admin.py`):
- `AdminAuditLog` - Track all admin actions
- `AdminNotification` - System alerts for admins
- `AdminSetting` - Platform-wide settings
- `PlatformAlert` - System health alerts
- `AdminSession` - Track admin login sessions
2. **Pydantic Schemas** (`models/schemas/admin.py`):
- Request/response models for all admin operations
- Validation for bulk operations
- System health check schemas
3. **Services**:
- `AdminAuditService` - Audit logging operations
- `AdminSettingsService` - Platform settings management
4. **API Endpoints**:
- `/api/v1/admin/audit` - Audit log endpoints
- `/api/v1/admin/settings` - Settings management
- `/api/v1/admin/notifications` - Notifications & alerts (stubs)
---
## Step-by-Step Integration
### Step 1: Update Database
Add the new models to your database imports:
```python
# models/database/__init__.py
from .admin import (
AdminAuditLog,
AdminNotification,
AdminSetting,
PlatformAlert,
AdminSession
)
```
Run database migration:
```bash
# Create migration
alembic revision --autogenerate -m "Add admin models"
# Apply migration
alembic upgrade head
```
### Step 2: Update Admin API Router
```python
# app/api/v1/admin/__init__.py
from fastapi import APIRouter
from . import auth, vendors, users, dashboard, marketplace, audit, settings, notifications
router = APIRouter(prefix="/admin", tags=["admin"])
# Include all admin routers
router.include_router(auth.router)
router.include_router(vendors.router)
router.include_router(users.router)
router.include_router(dashboard.router)
router.include_router(marketplace.router)
router.include_router(audit.router) # NEW
router.include_router(settings.router) # NEW
router.include_router(notifications.router) # NEW
```
### Step 3: Add Audit Logging to Existing Admin Operations
Update your `admin_service.py` to log actions:
```python
# app/services/admin_service.py
from app.services.admin_audit_service import admin_audit_service
class AdminService:
def create_vendor_with_owner(
self, db: Session, vendor_data: VendorCreate
) -> Tuple[Vendor, User, str]:
"""Create vendor with owner user account."""
# ... existing code ...
vendor, owner_user, temp_password = # ... your creation logic
# LOG THE ACTION
admin_audit_service.log_action(
db=db,
admin_user_id=current_admin_id, # You'll need to pass this
action="create_vendor",
target_type="vendor",
target_id=str(vendor.id),
details={
"vendor_code": vendor.vendor_code,
"subdomain": vendor.subdomain,
"owner_email": owner_user.email
}
)
return vendor, owner_user, temp_password
def toggle_vendor_status(
self, db: Session, vendor_id: int, admin_user_id: int
) -> Tuple[Vendor, str]:
"""Toggle vendor status with audit logging."""
vendor = self._get_vendor_by_id_or_raise(db, vendor_id)
old_status = vendor.is_active
# ... toggle logic ...
# LOG THE ACTION
admin_audit_service.log_action(
db=db,
admin_user_id=admin_user_id,
action="toggle_vendor_status",
target_type="vendor",
target_id=str(vendor_id),
details={
"old_status": "active" if old_status else "inactive",
"new_status": "active" if vendor.is_active else "inactive"
}
)
return vendor, message
```
### Step 4: Update API Endpoints to Pass Admin User ID
Your API endpoints need to pass the current admin's ID to service methods:
```python
# app/api/v1/admin/vendors.py
@router.post("", response_model=VendorResponse)
def create_vendor_with_owner(
vendor_data: VendorCreate,
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user),
):
"""Create vendor with audit logging."""
vendor, owner_user, temp_password = admin_service.create_vendor_with_owner(
db=db,
vendor_data=vendor_data,
admin_user_id=current_admin.id # Pass admin ID for audit logging
)
# Audit log is automatically created inside the service
return {
**VendorResponse.model_validate(vendor).model_dump(),
"owner_email": owner_user.email,
"owner_username": owner_user.username,
"temporary_password": temp_password,
"login_url": f"{vendor.subdomain}.platform.com/vendor/login"
}
@router.put("/{vendor_id}/status")
def toggle_vendor_status(
vendor_id: int,
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user),
):
"""Toggle vendor status with audit logging."""
vendor, message = admin_service.toggle_vendor_status(
db=db,
vendor_id=vendor_id,
admin_user_id=current_admin.id # Pass for audit
)
return {"message": message, "vendor": VendorResponse.model_validate(vendor)}
```
### Step 5: Add Request Context to Audit Logs
To capture IP address and user agent, use FastAPI's Request object:
```python
# app/api/v1/admin/vendors.py
from fastapi import Request
@router.delete("/{vendor_id}")
def delete_vendor(
vendor_id: int,
request: Request, # Add request parameter
confirm: bool = Query(False),
db: Session = Depends(get_db),
current_admin: User = Depends(get_current_admin_user),
):
"""Delete vendor with full audit trail."""
if not confirm:
raise HTTPException(status_code=400, detail="Confirmation required")
# Get request metadata
ip_address = request.client.host if request.client else None
user_agent = request.headers.get("user-agent")
message = admin_service.delete_vendor(db, vendor_id)
# Log with full context
admin_audit_service.log_action(
db=db,
admin_user_id=current_admin.id,
action="delete_vendor",
target_type="vendor",
target_id=str(vendor_id),
ip_address=ip_address,
user_agent=user_agent,
details={"confirm": True}
)
return {"message": message}
```
---
## Example: Platform Settings Usage
### Creating Default Settings
```python
# scripts/init_platform_settings.py
from app.core.database import SessionLocal
from app.services.admin_settings_service import admin_settings_service
from models.schemas.admin import AdminSettingCreate
db = SessionLocal()
# Create default platform settings
settings = [
AdminSettingCreate(
key="max_vendors_allowed",
value="1000",
value_type="integer",
category="system",
description="Maximum number of vendors allowed on the platform",
is_public=False
),
AdminSettingCreate(
key="maintenance_mode",
value="false",
value_type="boolean",
category="system",
description="Enable maintenance mode (blocks all non-admin access)",
is_public=True
),
AdminSettingCreate(
key="vendor_trial_days",
value="30",
value_type="integer",
category="system",
description="Default trial period for new vendors (days)",
is_public=False
),
AdminSettingCreate(
key="stripe_publishable_key",
value="pk_test_...",
value_type="string",
category="payments",
description="Stripe publishable key",
is_public=True
),
AdminSettingCreate(
key="stripe_secret_key",
value="sk_test_...",
value_type="string",
category="payments",
description="Stripe secret key",
is_encrypted=True,
is_public=False
)
]
for setting_data in settings:
try:
admin_settings_service.upsert_setting(db, setting_data, admin_user_id=1)
print(f"✓ Created setting: {setting_data.key}")
except Exception as e:
print(f"✗ Failed to create {setting_data.key}: {e}")
db.close()
```
### Using Settings in Your Code
```python
# app/services/vendor_service.py
from app.services.admin_settings_service import admin_settings_service
def can_create_vendor(db: Session) -> bool:
"""Check if platform allows creating more vendors."""
max_vendors = admin_settings_service.get_setting_value(
db=db,
key="max_vendors_allowed",
default=1000
)
current_count = db.query(Vendor).count()
return current_count < max_vendors
def is_maintenance_mode(db: Session) -> bool:
"""Check if platform is in maintenance mode."""
return admin_settings_service.get_setting_value(
db=db,
key="maintenance_mode",
default=False
)
```
---
## Frontend Integration
### Admin Dashboard with Audit Logs
```html
<!-- templates/admin/audit_logs.html -->
<div x-data="auditLogs()" x-init="loadLogs()">
<h1>Audit Logs</h1>
<!-- Filters -->
<div class="filters">
<select x-model="filters.action" @change="loadLogs()">
<option value="">All Actions</option>
<option value="create_vendor">Create Vendor</option>
<option value="delete_vendor">Delete Vendor</option>
<option value="toggle_vendor_status">Toggle Status</option>
<option value="update_setting">Update Setting</option>
</select>
<select x-model="filters.target_type" @change="loadLogs()">
<option value="">All Targets</option>
<option value="vendor">Vendors</option>
<option value="user">Users</option>
<option value="setting">Settings</option>
</select>
</div>
<!-- Logs Table -->
<table class="data-table">
<thead>
<tr>
<th>Timestamp</th>
<th>Admin</th>
<th>Action</th>
<th>Target</th>
<th>Details</th>
<th>IP Address</th>
</tr>
</thead>
<tbody>
<template x-for="log in logs" :key="log.id">
<tr>
<td x-text="formatDate(log.created_at)"></td>
<td x-text="log.admin_username"></td>
<td>
<span class="badge" x-text="log.action"></span>
</td>
<td x-text="`${log.target_type}:${log.target_id}`"></td>
<td>
<button @click="showDetails(log)">View</button>
</td>
<td x-text="log.ip_address"></td>
</tr>
</template>
</tbody>
</table>
<!-- Pagination -->
<div class="pagination">
<button @click="previousPage()" :disabled="skip === 0">Previous</button>
<span x-text="`Page ${currentPage} of ${totalPages}`"></span>
<button @click="nextPage()" :disabled="!hasMore">Next</button>
</div>
</div>
<script>
function auditLogs() {
return {
logs: [],
filters: {
action: '',
target_type: '',
admin_user_id: null
},
skip: 0,
limit: 50,
total: 0,
async loadLogs() {
const params = new URLSearchParams({
skip: this.skip,
limit: this.limit,
...this.filters
});
const response = await apiClient.get(`/api/v1/admin/audit/logs?${params}`);
this.logs = response.logs;
this.total = response.total;
},
showDetails(log) {
// Show modal with full details
console.log('Details:', log.details);
},
formatDate(date) {
return new Date(date).toLocaleString();
},
get currentPage() {
return Math.floor(this.skip / this.limit) + 1;
},
get totalPages() {
return Math.ceil(this.total / this.limit);
},
get hasMore() {
return this.skip + this.limit < this.total;
},
nextPage() {
this.skip += this.limit;
this.loadLogs();
},
previousPage() {
this.skip = Math.max(0, this.skip - this.limit);
this.loadLogs();
}
}
}
</script>
```
### Platform Settings Management
```html
<!-- templates/admin/settings.html -->
<div x-data="platformSettings()" x-init="loadSettings()">
<h1>Platform Settings</h1>
<!-- Category Tabs -->
<div class="tabs">
<button
@click="selectedCategory = 'system'"
:class="{'active': selectedCategory === 'system'}"
>System</button>
<button
@click="selectedCategory = 'security'"
:class="{'active': selectedCategory === 'security'}"
>Security</button>
<button
@click="selectedCategory = 'payments'"
:class="{'active': selectedCategory === 'payments'}"
>Payments</button>
</div>
<!-- Settings List -->
<div class="settings-list">
<template x-for="setting in filteredSettings" :key="setting.id">
<div class="setting-item">
<div class="setting-header">
<h3 x-text="setting.key"></h3>
<span class="badge" x-text="setting.value_type"></span>
</div>
<p class="setting-description" x-text="setting.description"></p>
<div class="setting-value">
<input
type="text"
:value="setting.value"
@change="updateSetting(setting.key, $event.target.value)"
>
<span class="updated-at" x-text="`Updated: ${formatDate(setting.updated_at)}`"></span>
</div>
</div>
</template>
</div>
<!-- Add New Setting -->
<button @click="showAddModal = true" class="btn-primary">
Add New Setting
</button>
</div>
<script>
function platformSettings() {
return {
settings: [],
selectedCategory: 'system',
showAddModal: false,
async loadSettings() {
const response = await apiClient.get('/api/v1/admin/settings');
this.settings = response.settings;
},
get filteredSettings() {
if (!this.selectedCategory) return this.settings;
return this.settings.filter(s => s.category === this.selectedCategory);
},
async updateSetting(key, newValue) {
try {
await apiClient.put(`/api/v1/admin/settings/${key}`, {
value: newValue
});
showNotification('Setting updated successfully', 'success');
this.loadSettings();
} catch (error) {
showNotification('Failed to update setting', 'error');
}
},
formatDate(date) {
return new Date(date).toLocaleString();
}
}
}
</script>
```
---
## Testing the New Features
### Test Audit Logging
```python
# tests/test_admin_audit.py
import pytest
from app.services.admin_audit_service import admin_audit_service
def test_log_admin_action(db_session, test_admin_user):
"""Test logging admin actions."""
log = admin_audit_service.log_action(
db=db_session,
admin_user_id=test_admin_user.id,
action="create_vendor",
target_type="vendor",
target_id="123",
details={"vendor_code": "TEST"}
)
assert log is not None
assert log.action == "create_vendor"
assert log.target_type == "vendor"
assert log.details["vendor_code"] == "TEST"
def test_query_audit_logs(db_session, test_admin_user):
"""Test querying audit logs with filters."""
# Create test logs
for i in range(5):
admin_audit_service.log_action(
db=db_session,
admin_user_id=test_admin_user.id,
action=f"test_action_{i}",
target_type="test",
target_id=str(i)
)
# Query logs
from models.schemas.admin import AdminAuditLogFilters
filters = AdminAuditLogFilters(limit=10)
logs = admin_audit_service.get_audit_logs(db_session, filters)
assert len(logs) == 5
```
### Test Platform Settings
```python
# tests/test_admin_settings.py
def test_create_setting(db_session, test_admin_user):
"""Test creating platform setting."""
from models.schemas.admin import AdminSettingCreate
setting_data = AdminSettingCreate(
key="test_setting",
value="test_value",
value_type="string",
category="test"
)
result = admin_settings_service.create_setting(
db=db_session,
setting_data=setting_data,
admin_user_id=test_admin_user.id
)
assert result.key == "test_setting"
assert result.value == "test_value"
def test_get_setting_value_with_type_conversion(db_session):
"""Test getting setting values with proper type conversion."""
# Create integer setting
setting_data = AdminSettingCreate(
key="max_vendors",
value="100",
value_type="integer",
category="system"
)
admin_settings_service.create_setting(db_session, setting_data, 1)
# Get value (should be converted to int)
value = admin_settings_service.get_setting_value(db_session, "max_vendors")
assert isinstance(value, int)
assert value == 100
```
---
## Summary
You now have a complete admin infrastructure with:
**Audit Logging**: Track all admin actions for compliance
**Platform Settings**: Manage global configuration
**Notifications**: System alerts for admins (structure ready)
**Platform Alerts**: Health monitoring (structure ready)
**Session Tracking**: Monitor admin logins (structure ready)
### Next Steps
1. **Apply database migrations** to create new tables
2. **Update admin API router** to include new endpoints
3. **Add audit logging** to existing admin operations
4. **Create default platform settings** using the script
5. **Build frontend pages** for audit logs and settings
6. **Implement notification service** (notifications.py stubs)
7. **Add monitoring** for platform alerts
These additions make your platform production-ready with full compliance and monitoring capabilities!

View File

@@ -1,128 +0,0 @@
Frontend Folder Structure
Generated: 25/10/2025 16:45:08.55
==============================================================================
Folder PATH listing for volume Data2
Volume serial number is 0000007B A008:CC27
E:\FASTAPI-MULTITENANT-ECOMMERCE\STATIC
+---admin
| | marketplace.html
| | monitoring.html
| | users.html
| | vendor-edit.html
| | vendors.html
| |
| +---css
| | tailwind.output.css
| |
| +---img
| | create-account-office-dark.jpeg
| | create-account-office.jpeg
| | forgot-password-office-dark.jpeg
| | forgot-password-office.jpeg
| | login-office-dark.jpeg
| | login-office.jpeg
| |
| +---js
| | analytics.js
| | components.js
| | dashboard.js
| | icons-page.js
| | init-alpine.js
| | login.js
| | monitoring.js
| | testing-hub.js
| | users.js
| | vendor-detail.js
| | vendor-edit.js
| | vendors.js
| |
| \---partials
| base-layout.html
|
+---css
| +---admin
| | admin.css
| |
| +---shared
| | auth.css
| | base.css
| | components.css
| | modals.css
| | responsive-utilities.css
| |
| +---shop
| +---themes
| \---vendor
| vendor.css
|
+---js
| +---shared
| | alpine-components.js
| | media-upload.js
| | modal-system.js
| | modal-templates.js
| | notification.js
| | search.js
| | vendor-context.js
| |
| +---shop
| | account.js
| | cart.js
| | catalog.js
| | checkout.js
| | search.js
| | shop-layout-templates.js
| |
| \---vendor
| dashboard.js
| login.js
| marketplace.js
| media.js
| orders.js
| payments.js
| products.js
| vendor-layout-templates.js
|
+---shared
| \---js
| api-client.js
| icons.js
| utils.js
|
+---shop
| | cart.html
| | checkout.html
| | home.html
| | product.html
| | products.html
| | search.html
| |
| \---account
| addresses.html
| login.html
| orders.html
| profile.html
| register.html
|
\---vendor
| dashboard.html
| login.html
|
\---admin
| customers.html
| inventory.html
| media.html
| notifications.html
| orders.html
| payments.html
| products.html
| settings.html
| teams.html
|
\---marketplace
browse.html
config.html
imports.html
selected.html