Enhancing documentation

This commit is contained in:
2025-09-20 22:39:12 +02:00
parent 5996cecc42
commit a26f8086f8
22 changed files with 2176 additions and 5221 deletions

132
Makefile
View File

@@ -1,5 +1,5 @@
# Comprehensive Makefile for LetzShop API (Windows Compatible)
.PHONY: install install-test install-dev install-all dev test test-unit test-integration test-coverage test-fast test-slow test-auth test-products test-stock lint format check docker-build docker-up docker-down migrate clean check-tools setup setup-test
.PHONY: install install-test install-dev install-docs install-all dev test test-unit test-integration test-coverage test-fast test-slow test-auth test-products test-stock lint format check docker-build docker-up docker-down migrate clean check-tools setup setup-test docs docs-serve docs-build docs-deploy docs-clean help
# Check if required tools are installed (Windows compatible)
check-tools:
@@ -8,6 +8,9 @@ check-tools:
@where flake8 >nul 2>&1 || (echo flake8 is required but not installed. Run 'make install-dev' first. && exit 1)
@where mypy >nul 2>&1 || (echo mypy is required but not installed. Run 'make install-dev' first. && exit 1)
check-docs-tools:
@where mkdocs >nul 2>&1 || (echo mkdocs is required but not installed. Run 'make install-docs' first. && exit 1)
# Development setup
install:
pip install -r requirements.txt
@@ -19,14 +22,68 @@ install-dev:
pip install -r requirements.txt
pip install -r tests/requirements-test.txt
pip install -r requirements-dev.txt
install-docs:
pip install -r requirements-docs.txt
install-all: install install-test install-dev
install-all: install install-test install-dev install-docs
# Development server
# Development servers
dev:
uvicorn main:app --reload --host 0.0.0.0 --port 8000
dev-with-docs:
@echo Starting API server and documentation server...
@start /B uvicorn main:app --reload --host 0.0.0.0 --port 8000
@timeout /t 3 >nul
@mkdocs serve --dev-addr=0.0.0.0:8001
# Documentation commands
docs: docs-serve
docs-serve:
@echo Starting MkDocs development server...
mkdocs serve --dev-addr=0.0.0.0:8001
docs-build:
@echo Building documentation site...
mkdocs build --clean --strict
docs-build-quiet:
@echo Building documentation (quiet)...
mkdocs build --clean --quiet
docs-deploy:
@echo Deploying documentation to GitHub Pages...
mkdocs gh-deploy --clean
docs-deploy-force:
@echo Force deploying documentation to GitHub Pages...
mkdocs gh-deploy --clean --force
docs-update:
@echo Updating documentation with API information...
python scripts/update_docs.py
docs-clean:
@echo Cleaning documentation build files...
@if exist site rmdir /s /q site
@echo Documentation build files cleaned!
docs-check:
@echo Checking documentation for issues...
mkdocs build --strict --verbose
docs-help:
mkdocs --help
# Combined development environment
dev-full: dev-with-docs
@echo Development environment ready!
@echo API server: http://localhost:8000
@echo API docs: http://localhost:8000/docs
@echo Documentation: http://localhost:8001
# Testing commands
test:
pytest tests/ -v
@@ -117,6 +174,15 @@ deploy-staging:
deploy-prod:
docker-compose -f docker-compose.prod.yml up -d
# Documentation deployment workflow
docs-publish: docs-build docs-deploy
@echo Documentation published successfully!
@echo Visit: https://yourusername.github.io/letzshop-import/
docs-preview: docs-build
@echo Opening documentation preview...
@start site\index.html
# Clean up (Windows compatible)
clean:
@if exist htmlcov rmdir /s /q htmlcov
@@ -126,28 +192,63 @@ clean:
@for /d /r . %%d in (__pycache__) do @if exist "%%d" rmdir /s /q "%%d"
@del /s /q *.pyc 2>nul || echo No .pyc files found
clean-all: clean docs-clean
@echo All build artifacts cleaned!
# Development workflow shortcuts
setup: install-dev migrate-up
setup: install-all migrate-up
@echo Development environment setup complete!
@echo Run 'make dev-full' to start both API and documentation servers
setup-test: install-test
@echo Test environment setup complete!
setup-docs: install-docs
@echo Documentation environment setup complete!
@echo Run 'make docs-serve' to start documentation server
full-test: format lint test-coverage
@echo Full test suite completed!
# Quality assurance workflow
qa: format lint test-coverage docs-check
@echo Quality assurance checks completed!
# Release workflow
release-check: qa docs-build
@echo Release readiness check completed!
# Help command
help:
@echo Available commands:
@echo.
@echo === SETUP ===
@echo install - Install production dependencies
@echo install-test - Install test dependencies only
@echo install-dev - Install all development dependencies
@echo install-docs - Install documentation dependencies
@echo install-all - Install everything
@echo setup - Complete development setup
@echo setup-test - Setup test environment only
@echo dev - Start development server
@echo setup-docs - Setup documentation environment
@echo.
@echo Testing:
@echo === DEVELOPMENT ===
@echo dev - Start development server (API only)
@echo dev-with-docs - Start both API and documentation servers
@echo dev-full - Start full development environment with info
@echo.
@echo === DOCUMENTATION ===
@echo docs - Start documentation development server (alias for docs-serve)
@echo docs-serve - Start MkDocs development server
@echo docs-build - Build documentation site
@echo docs-deploy - Deploy documentation to GitHub Pages
@echo docs-publish - Build and deploy documentation
@echo docs-preview - Build and open documentation locally
@echo docs-update - Update docs with API information
@echo docs-check - Check documentation for issues
@echo docs-clean - Clean documentation build files
@echo.
@echo === TESTING ===
@echo test - Run all tests
@echo test-unit - Run unit tests only
@echo test-integration - Run integration tests only
@@ -156,22 +257,33 @@ help:
@echo test-slow - Run slow tests only
@echo full-test - Format, lint, and test with coverage
@echo.
@echo Code Quality:
@echo === CODE QUALITY ===
@echo format - Format code with black and isort
@echo lint - Run linting with flake8 and mypy
@echo check - Format and lint code
@echo ci - Full CI pipeline (format, lint, test)
@echo qa - Quality assurance (format, lint, test, docs check)
@echo.
@echo Database:
@echo === DATABASE ===
@echo migrate-up - Run database migrations
@echo migrate-down - Rollback last migration
@echo migrate-reset - Reset and rerun all migrations
@echo.
@echo Docker:
@echo === DOCKER ===
@echo docker-build - Build Docker containers
@echo docker-up - Start Docker containers
@echo docker-down - Stop Docker containers
@echo docker-restart - Restart Docker containers
@echo.
@echo Cleanup:
@echo === CLEANUP ===
@echo clean - Remove test artifacts and cache files
@echo clean-all - Remove all build artifacts (including docs)
@echo.
@echo === WORKFLOWS ===
@echo release-check - Complete release readiness check
@echo.
@echo === QUICK START ===
@echo make setup # First time setup
@echo make dev-full # Start development environment
@echo make docs-serve # Start documentation server
@echo make qa # Run quality checks

1063
README.md

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@ from alembic import context
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from app.core.config import settings
from models.database import Base
from models.database.base import Base
# Alembic Config object
config = context.config

View File

@@ -1,137 +0,0 @@
# Authentication Usage Example
# This file demonstrates how to use the authentication endpoints
import requests
# API Base URL
BASE_URL = "http://localhost:8000"
def register_user(email, username, password):
"""Register a new user"""
response = requests.post(
f"{BASE_URL}/register",
json={"email": email, "username": username, "password": password},
)
return response.json()
def login_user(username, password):
"""Login and get JWT token"""
response = requests.post(
f"{BASE_URL}/login", json={"username": username, "password": password}
)
if response.status_code == 200:
data = response.json()
return data["access_token"]
else:
print(f"Login failed: {response.json()}")
return None
def get_user_info(token):
"""Get current user info"""
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(f"{BASE_URL}/me", headers=headers)
return response.json()
def get_products(token, skip=0, limit=10):
"""Get products (requires authentication)"""
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(
f"{BASE_URL}/products?skip={skip}&limit={limit}", headers=headers
)
return response.json()
def create_product(token, product_data):
"""Create a new product (requires authentication)"""
headers = {"Authorization": f"Bearer {token}"}
response = requests.post(f"{BASE_URL}/products", json=product_data, headers=headers)
return response.json()
# Example usage
if __name__ == "__main__":
# 1. Register a new user
print("1. Registering new user...")
try:
user_result = register_user("test@example.com", "testuser", "password123")
print(f"User registered: {user_result}")
except Exception as e:
print(f"Registration failed: {e}")
# 2. Login with default admin user
print("\n2. Logging in as admin...")
admin_token = login_user("admin", "admin123")
if admin_token:
print(f"Admin login successful! Token: {admin_token[:50]}...")
# 3. Get user info
print("\n3. Getting admin user info...")
user_info = get_user_info(admin_token)
print(f"User info: {user_info}")
# 4. Create a sample product
print("\n4. Creating a sample product...")
sample_product = {
"product_id": "TEST001",
"title": "Test Product",
"description": "A test product for demonstration",
"price": "19.99",
"brand": "Test Brand",
"availability": "in stock",
}
product_result = create_product(admin_token, sample_product)
print(f"Product created: {product_result}")
# 5. Get products list
print("\n5. Getting products list...")
products = get_products(admin_token)
print(f"Products: {products}")
# 6. Login with regular user
print("\n6. Logging in as regular user...")
user_token = login_user("testuser", "password123")
if user_token:
print(f"User login successful! Token: {user_token[:50]}...")
# Regular users can also access protected endpoints
user_info = get_user_info(user_token)
print(f"Regular user info: {user_info}")
products = get_products(user_token, limit=5)
print(
f"Products accessible to regular user: {len(products.get('products', []))} products"
)
print("\nAuthentication example completed!")
# Example cURL commands:
"""
# Register a new user
curl -X POST "http://localhost:8000/register" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "username": "newuser", "password": "password123"}'
# Login (get JWT token)
curl -X POST "http://localhost:8000/login" \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "admin123"}'
# Use token to access protected endpoint
curl -X GET "http://localhost:8000/me" \
-H "Authorization: Bearer YOUR_JWT_TOKEN_HERE"
# Get products (protected)
curl -X GET "http://localhost:8000/products" \
-H "Authorization: Bearer YOUR_JWT_TOKEN_HERE"
# Create product (protected)
curl -X POST "http://localhost:8000/products" \
-H "Authorization: Bearer YOUR_JWT_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{"product_id": "TEST001", "title": "Test Product", "price": "19.99"}'
"""

View File

@@ -1,493 +0,0 @@
# Ecommerce Backend API with Marketplace Support
A comprehensive FastAPI-based product management system with JWT authentication, marketplace-aware CSV import/export, multi-shop support, and advanced stock management capabilities.
## Features
- **JWT Authentication** - Secure user registration, login, and role-based access control
- **Marketplace Integration** - Support for multiple marketplaces (Letzshop, Amazon, eBay, Etsy, Shopify, etc.)
- **Multi-Shop Management** - Shop creation, ownership validation, and product catalog management
- **Advanced Product Management** - GTIN validation, price processing, and comprehensive filtering
- **Stock Management** - Multi-location inventory tracking with add/remove/set operations
- **CSV Import/Export** - Background processing of marketplace CSV files with progress tracking
- **Rate Limiting** - Built-in request rate limiting for API protection
- **Admin Panel** - Administrative functions for user and shop management
- **Statistics & Analytics** - Comprehensive reporting on products, marketplaces, and inventory
## Technology Stack
- **FastAPI** - Modern, fast web framework for building APIs
- **SQLAlchemy** - SQL toolkit and Object-Relational Mapping (ORM)
- **PostgreSQL** - Primary database (SQLite supported for development)
- **JWT** - JSON Web Tokens for secure authentication
- **Pydantic** - Data validation using Python type annotations
- **Pandas** - Data processing for CSV operations
- **bcrypt** - Password hashing
- **Pytest** - Comprehensive testing framework
## Directory Structure
```
letzshop_api/
├── main.py # FastAPI application entry point
├── app/
│ ├── core/
│ │ ├── config.py # Configuration settings
│ │ ├── database.py # Database setup
│ │ └── lifespan.py # App lifecycle management
│ ├── api/
│ │ ├── deps.py # Common dependencies
│ │ ├── main.py # API router setup
│ │ └── v1/ # API version 1 routes
│ │ ├── auth.py # Authentication endpoints
│ │ ├── products.py # Product management
│ │ ├── stock.py # Stock operations
│ │ ├── shops.py # Shop management
│ │ ├── marketplace.py # Marketplace imports
│ │ ├── admin.py # Admin functions
│ │ └── stats.py # Statistics
│ ├── services/ # Business logic layer
│ └── tasks/ # Background task processing
├── models/
│ ├── database_models.py # SQLAlchemy ORM models
│ └── api_models.py # Pydantic API models
├── utils/
│ ├── data_processing.py # GTIN and price processing
│ ├── csv_processor.py # CSV import/export
│ └── database.py # Database utilities
├── middleware/
│ ├── auth.py # JWT authentication
│ ├── rate_limiter.py # Rate limiting
│ ├── error_handler.py # Error handling
│ └── logging_middleware.py # Request logging
├── tests/ # Comprehensive test suite
└── requirements.txt # Dependencies
```
## Quick Start
### 1. Installation
```bash
# Clone the repository
git clone <repository-url>
cd letzshop_api
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
```
### 2. Environment Configuration
Create a `.env` file in the project root:
```env
# Database Configuration
DATABASE_URL=postgresql://user:password@localhost/ecommerce
# For development, you can use SQLite:
# DATABASE_URL=sqlite:///./ecommerce.db
# JWT Configuration
SECRET_KEY=your-super-secret-key-change-in-production
ACCESS_TOKEN_EXPIRE_MINUTES=30
# API Configuration
ALLOWED_HOSTS=["*"]
RATE_LIMIT_REQUESTS=100
RATE_LIMIT_WINDOW=3600
# Application Settings
PROJECT_NAME="Ecommerce Backend API"
VERSION="2.2.0"
DEBUG=True
```
### 3. Database Setup
```bash
# The application will automatically create tables on startup
# For production, consider using Alembic for migrations
# Install PostgreSQL (if using PostgreSQL)
# Create database
createdb ecommerce
# Run the application (tables will be created automatically)
python main.py
```
### 4. Running the Application
```bash
# Development server
python main.py
# Or using uvicorn directly
uvicorn main:app --reload --host 0.0.0.0 --port 8000
```
The API will be available at:
- **API Documentation**: http://localhost:8000/docs (Swagger UI)
- **Alternative Docs**: http://localhost:8000/redoc
- **Health Check**: http://localhost:8000/health
## API Usage
### Authentication
#### Register a new user
```bash
curl -X POST "http://localhost:8000/api/v1/auth/register" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"username": "testuser",
"password": "securepassword123"
}'
```
#### Login
```bash
curl -X POST "http://localhost:8000/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"password": "securepassword123"
}'
```
#### Use JWT Token
```bash
# Get token from login response and use in subsequent requests
curl -X GET "http://localhost:8000/api/v1/product" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
```
### Product Management
#### Create a product
```bash
curl -X POST "http://localhost:8000/api/v1/product" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"product_id": "PROD001",
"title": "Amazing Product",
"description": "An amazing product description",
"price": "29.99",
"currency": "EUR",
"brand": "BrandName",
"gtin": "1234567890123",
"availability": "in stock",
"marketplace": "Letzshop",
"shop_name": "MyShop"
}'
```
#### Get products with filtering
```bash
# Get all products
curl -X GET "http://localhost:8000/api/v1/product" \
-H "Authorization: Bearer YOUR_TOKEN"
# Filter by marketplace
curl -X GET "http://localhost:8000/api/v1/product?marketplace=Amazon&limit=50" \
-H "Authorization: Bearer YOUR_TOKEN"
# Search products
curl -X GET "http://localhost:8000/api/v1/product?search=Amazing&brand=BrandName" \
-H "Authorization: Bearer YOUR_TOKEN"
```
### Stock Management
#### Set stock quantity
```bash
curl -X POST "http://localhost:8000/api/v1/stock" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"gtin": "1234567890123",
"location": "WAREHOUSE_A",
"quantity": 100
}'
```
#### Add stock
```bash
curl -X POST "http://localhost:8000/api/v1/stock/add" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"gtin": "1234567890123",
"location": "WAREHOUSE_A",
"quantity": 25
}'
```
#### Check stock levels
```bash
curl -X GET "http://localhost:8000/api/v1/stock/1234567890123" \
-H "Authorization: Bearer YOUR_TOKEN"
```
### Marketplace Import
#### Import products from CSV
```bash
curl -X POST "http://localhost:8000/api/v1/marketplace/import-product" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/products.csv",
"marketplace": "Amazon",
"shop_code": "MYSHOP",
"batch_size": 1000
}'
```
#### Check import status
```bash
curl -X GET "http://localhost:8000/api/v1/marketplace/import-status/1" \
-H "Authorization: Bearer YOUR_TOKEN"
```
### Export Data
#### Export products to CSV
```bash
# Export all products
curl -X GET "http://localhost:8000/api/v1/export-csv" \
-H "Authorization: Bearer YOUR_TOKEN" \
-o products_export.csv
# Export with filters
curl -X GET "http://localhost:8000/api/v1/export-csv?marketplace=Amazon&shop_name=MyShop" \
-H "Authorization: Bearer YOUR_TOKEN" \
-o amazon_products.csv
```
## CSV Import Format
The system supports CSV imports with the following headers:
### Required Fields
- `product_id` - Unique product identifier
- `title` - Product title
### Optional Fields
- `description` - Product description
- `link` - Product URL
- `image_link` - Product image URL
- `availability` - Stock availability (in stock, out of stock, preorder)
- `price` - Product price
- `currency` - Price currency (EUR, USD, etc.)
- `brand` - Product brand
- `gtin` - Global Trade Item Number (EAN/UPC)
- `google_product_category` - Product category
- `marketplace` - Source marketplace
- `shop_name` - Shop/seller name
### Example CSV
```csv
product_id,title,description,price,currency,brand,gtin,marketplace,shop_name
PROD001,"Amazing Widget","The best widget ever",29.99,EUR,WidgetCorp,1234567890123,Letzshop,MyShop
PROD002,"Super Gadget","A fantastic gadget",19.99,EUR,GadgetInc,9876543210987,Amazon,TechStore
```
## Testing
### Run Tests
```bash
# Install test dependencies
pip install -r tests/requirements_test.txt
# Run all tests
pytest tests/ -v
# Run with coverage report
pytest tests/ --cov=app --cov=models --cov=utils --cov-report=html
# Run specific test categories
pytest tests/ -m unit -v # Unit tests only
pytest tests/ -m integration -v # Integration tests only
pytest tests/ -m "not slow" -v # Fast tests only
# Run specific test files
pytest tests/test_authentication_endpoints.py -v # Authentication tests
pytest tests/test_product_endpoints.py -v # Product tests
pytest tests/test_stock_endpoints.py -v # Stock management tests
```
### Test Coverage
The test suite includes:
- **Unit Tests** - Individual component testing
- **Integration Tests** - Full workflow testing
- **Security Tests** - Authentication, authorization, input validation
- **Performance Tests** - Load testing with large datasets
- **Error Handling Tests** - Edge cases and error conditions
## API Reference
### Authentication Endpoints
- `POST /api/v1/auth/register` - Register new user
- `POST /api/v1/auth/login` - Login user
- `GET /api/v1/auth/me` - Get current user info
### Product Endpoints
- `GET /api/v1/product` - List products with filtering
- `POST /api/v1/product` - Create new product
- `GET /api/v1/product/{product_id}` - Get specific product
- `PUT /api/v1/product/{product_id}` - Update product
- `DELETE /api/v1/product/{product_id}` - Delete product
### Stock Endpoints
- `POST /api/v1/stock` - Set stock quantity
- `POST /api/v1/stock/add` - Add to stock
- `POST /api/v1/stock/remove` - Remove from stock
- `GET /api/v1/stock/{gtin}` - Get stock by GTIN
- `GET /api/v1/stock/{gtin}/total` - Get total stock
- `GET /api/v1/stock` - List all stock entries
### Shop Endpoints
- `POST /api/v1/shop` - Create new shop
- `GET /api/v1/shop` - List shops
- `GET /api/v1/shop/{shop_code}` - Get specific shop
### Marketplace Endpoints
- `POST /api/v1/marketplace/import-product` - Start CSV import
- `GET /api/v1/marketplace/import-status/{job_id}` - Check import status
- `GET /api/v1/marketplace/import-jobs` - List import jobs
### Statistics Endpoints
- `GET /api/v1/stats` - Get general statistics
- `GET /api/v1/stats/marketplace-stats` - Get marketplace statistics
### Admin Endpoints (Admin only)
- `GET /api/v1/admin/users` - List all users
- `PUT /api/v1/admin/users/{user_id}/status` - Toggle user status
- `GET /api/v1/admin/shops` - List all shops
- `PUT /api/v1/admin/shops/{shop_id}/verify` - Verify/unverify shop
## Database Schema
### Core Tables
- **users** - User accounts and authentication
- **products** - Product catalog with marketplace info
- **stock** - Inventory tracking by location and GTIN
- **shops** - Shop/seller information
- **shop_products** - Shop-specific product settings
- **marketplace_import_jobs** - Background import job tracking
### Key Relationships
- Users own shops (one-to-many)
- Products belong to marketplaces and shops
- Stock entries are linked to products via GTIN
- Import jobs track user-initiated imports
## Security Features
- **JWT Authentication** - Secure token-based authentication
- **Password Hashing** - bcrypt for secure password storage
- **Role-Based Access** - User and admin role separation
- **Rate Limiting** - Protection against API abuse
- **Input Validation** - Comprehensive data validation
- **SQL Injection Protection** - Parameterized queries
- **CORS Configuration** - Cross-origin request handling
## Performance Optimizations
- **Database Indexing** - Strategic indexes on key columns
- **Pagination** - Efficient data retrieval with skip/limit
- **Streaming Responses** - Memory-efficient CSV exports
- **Background Processing** - Async import job handling
- **Connection Pooling** - Efficient database connections
- **Query Optimization** - Optimized database queries
## Deployment
### Docker Deployment
```dockerfile
FROM python:3.11
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```
### Production Considerations
- Use PostgreSQL for production database
- Set strong SECRET_KEY in environment
- Configure proper CORS settings
- Enable HTTPS
- Set up monitoring and logging
- Use a reverse proxy (nginx)
- Configure database connection pooling
- Set up backup strategies
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Ensure all tests pass
6. Submit a pull request
### Development Setup
```bash
# Install development dependencies
pip install -r requirements_dev.txt
# Run pre-commit hooks
pre-commit install
# Run linting
flake8 app/ models/ utils/
black app/ models/ utils/
# Run type checking
mypy app/
```
## Support & Documentation
- **API Documentation**: http://localhost:8000/docs
- **Health Check**: http://localhost:8000/health
- **Version Info**: http://localhost:8000/
For issues and feature requests, please create an issue in the repository.
## License
[Specify your license here]
## Changelog
### v2.2.0
- Added marketplace-aware product import
- Implemented multi-shop support
- Enhanced stock management with location tracking
- Added comprehensive test suite
- Improved authentication and authorization
### v2.1.0
- Added JWT authentication
- Implemented role-based access control
- Added CSV import/export functionality
### v2.0.0
- Complete rewrite with FastAPI
- Added PostgreSQL support
- Implemented comprehensive API documentation

View File

@@ -0,0 +1,377 @@
# Authentication Usage Examples
This document provides practical examples of how to use the authentication system in the Ecommerce Backend API.
## Overview
The API uses JWT (JSON Web Token) authentication with the following workflow:
1. Register a new user account
2. Login to receive a JWT token
3. Include the token in the `Authorization` header for protected endpoints
4. Token expires after 30 minutes (configurable)
## Python Examples
### Basic Authentication Functions
```python
import requests
# API Base URL
BASE_URL = "http://localhost:8000"
def register_user(email, username, password):
"""Register a new user"""
response = requests.post(
f"{BASE_URL}/register",
json={"email": email, "username": username, "password": password},
)
return response.json()
def login_user(username, password):
"""Login and get JWT token"""
response = requests.post(
f"{BASE_URL}/login", json={"username": username, "password": password}
)
if response.status_code == 200:
data = response.json()
return data["access_token"]
else:
print(f"Login failed: {response.json()}")
return None
def get_user_info(token):
"""Get current user info"""
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(f"{BASE_URL}/me", headers=headers)
return response.json()
```
### Using Protected Endpoints
```python
def get_products(token, skip=0, limit=10):
"""Get products (requires authentication)"""
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(
f"{BASE_URL}/products?skip={skip}&limit={limit}", headers=headers
)
return response.json()
def create_product(token, product_data):
"""Create a new product (requires authentication)"""
headers = {"Authorization": f"Bearer {token}"}
response = requests.post(f"{BASE_URL}/products", json=product_data, headers=headers)
return response.json()
```
### Complete Workflow Example
```python
# Example usage workflow
if __name__ == "__main__":
# 1. Register a new user
print("1. Registering new user...")
try:
user_result = register_user("test@example.com", "testuser", "password123")
print(f"User registered: {user_result}")
except Exception as e:
print(f"Registration failed: {e}")
# 2. Login with default admin user
print("\n2. Logging in as admin...")
admin_token = login_user("admin", "admin123")
if admin_token:
print(f"Admin login successful! Token: {admin_token[:50]}...")
# 3. Get user info
print("\n3. Getting admin user info...")
user_info = get_user_info(admin_token)
print(f"User info: {user_info}")
# 4. Create a sample product
print("\n4. Creating a sample product...")
sample_product = {
"product_id": "TEST001",
"title": "Test Product",
"description": "A test product for demonstration",
"price": "19.99",
"brand": "Test Brand",
"availability": "in stock",
}
product_result = create_product(admin_token, sample_product)
print(f"Product created: {product_result}")
# 5. Get products list
print("\n5. Getting products list...")
products = get_products(admin_token)
print(f"Products: {products}")
# 6. Login with regular user
print("\n6. Logging in as regular user...")
user_token = login_user("testuser", "password123")
if user_token:
print(f"User login successful! Token: {user_token[:50]}...")
# Regular users can also access protected endpoints
user_info = get_user_info(user_token)
print(f"Regular user info: {user_info}")
products = get_products(user_token, limit=5)
print(
f"Products accessible to regular user: {len(products.get('products', []))} products"
)
print("\nAuthentication example completed!")
```
## cURL Examples
### Register a New User
```bash
curl -X POST "http://localhost:8000/register" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"username": "newuser",
"password": "password123"
}'
```
**Response:**
```json
{
"id": 2,
"email": "user@example.com",
"username": "newuser",
"role": "user",
"is_active": true,
"created_at": "2024-01-15T10:30:00Z"
}
```
### Login (Get JWT Token)
```bash
curl -X POST "http://localhost:8000/login" \
-H "Content-Type: application/json" \
-d '{
"username": "admin",
"password": "admin123"
}'
```
**Response:**
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 1800,
"user": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"role": "admin",
"is_active": true
}
}
```
### Use Token for Protected Endpoints
#### Get Current User Info
```bash
curl -X GET "http://localhost:8000/me" \
-H "Authorization: Bearer YOUR_JWT_TOKEN_HERE"
```
#### Get Products List
```bash
curl -X GET "http://localhost:8000/products" \
-H "Authorization: Bearer YOUR_JWT_TOKEN_HERE"
```
#### Create a Product
```bash
curl -X POST "http://localhost:8000/products" \
-H "Authorization: Bearer YOUR_JWT_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"product_id": "TEST001",
"title": "Test Product",
"description": "A test product for demonstration",
"price": "19.99",
"brand": "Test Brand",
"availability": "in stock"
}'
```
## Default Accounts
### Admin Account
- **Username**: `admin`
- **Password**: `admin123`
- **Email**: `admin@example.com`
- **Role**: `admin`
**Security Note**: Change the admin password immediately in production environments!
## Authentication Headers
All protected endpoints require the JWT token in the Authorization header:
```
Authorization: Bearer <your_jwt_token>
```
## Error Handling
### Common Authentication Errors
#### Invalid Credentials (Login)
```json
{
"detail": "Invalid credentials"
}
```
#### Missing or Invalid Token
```json
{
"detail": "Not authenticated"
}
```
#### Expired Token
```json
{
"detail": "Token has expired"
}
```
#### Insufficient Permissions
```json
{
"detail": "Not enough permissions"
}
```
### Error Handling in Python
```python
def safe_api_call(token, endpoint, method="GET", data=None):
"""Make API call with proper error handling"""
headers = {"Authorization": f"Bearer {token}"}
try:
if method == "GET":
response = requests.get(f"{BASE_URL}{endpoint}", headers=headers)
elif method == "POST":
response = requests.post(f"{BASE_URL}{endpoint}", json=data, headers=headers)
if response.status_code == 401:
print("Authentication failed - token may be expired")
return None
elif response.status_code == 403:
print("Access denied - insufficient permissions")
return None
elif response.status_code == 200:
return response.json()
else:
print(f"API call failed: {response.status_code} - {response.text}")
return None
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
```
## Best Practices
### Token Management
1. **Store tokens securely** - Don't expose tokens in logs or client-side code
2. **Handle token expiration** - Implement automatic token refresh or re-login
3. **Use HTTPS in production** - Never send tokens over unencrypted connections
### Password Security
1. **Use strong passwords** - Minimum 6 characters (configurable)
2. **Don't hardcode passwords** - Use environment variables or secure configuration
3. **Regular password updates** - Especially for admin accounts
### API Integration
1. **Include error handling** - Always check response status codes
2. **Implement retry logic** - Handle temporary network issues
3. **Rate limiting awareness** - Respect API rate limits
## Testing Authentication
You can test the authentication system using the provided Python script or with make commands:
```bash
# Run authentication tests
make test-auth
# Run all tests including authentication
make test
```
## Integration with Frontend
### JavaScript/TypeScript Example
```javascript
class APIClient {
constructor(baseURL = 'http://localhost:8000') {
this.baseURL = baseURL;
this.token = localStorage.getItem('jwt_token');
}
async login(username, password) {
const response = await fetch(`${this.baseURL}/login`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({username, password})
});
if (response.ok) {
const data = await response.json();
this.token = data.access_token;
localStorage.setItem('jwt_token', this.token);
return data;
} else {
throw new Error('Login failed');
}
}
async apiCall(endpoint, method = 'GET', data = null) {
const headers = {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json'
};
const config = {method, headers};
if (data) config.body = JSON.stringify(data);
const response = await fetch(`${this.baseURL}${endpoint}`, config);
if (response.status === 401) {
// Token expired, redirect to login
localStorage.removeItem('jwt_token');
window.location.href = '/login';
return;
}
return response.json();
}
}
```
This authentication system provides secure access control for all API endpoints while maintaining ease of use for developers integrating with the system.

View File

@@ -1,299 +0,0 @@
# Testing Overview
Our comprehensive test suite ensures code quality, reliability, and maintainability. This section covers everything you need to know about testing in the Letzshop Import project.
## Test Structure
We use a hierarchical test organization based on test types and scope:
```
tests/
├── conftest.py # Core test configuration and fixtures
├── pytest.ini # Pytest configuration with custom markers
├── fixtures/ # Shared test fixtures by domain
├── unit/ # Fast, isolated component tests
├── integration/ # Multi-component interaction tests
├── performance/ # Performance and load tests
├── system/ # End-to-end system behavior tests
└── test_data/ # Test data files (CSV, JSON, etc.)
```
## Test Types
### 🔧 Unit Tests
**Purpose**: Test individual components in isolation
**Speed**: Very fast (< 1 second each)
**Scope**: Single function, method, or class
```bash
# Run unit tests
pytest -m unit
```
**Examples**:
- Data processing utilities
- Model validation
- Service business logic
- Individual API endpoint handlers
### 🔗 Integration Tests
**Purpose**: Test component interactions
**Speed**: Fast to moderate (1-5 seconds each)
**Scope**: Multiple components working together
```bash
# Run integration tests
pytest -m integration
```
**Examples**:
- API endpoints with database
- Service layer interactions
- Authentication workflows
- File processing pipelines
### 🏗️ System Tests
**Purpose**: Test complete application behavior
**Speed**: Moderate (5-30 seconds each)
**Scope**: End-to-end user scenarios
```bash
# Run system tests
pytest -m system
```
**Examples**:
- Complete user registration flow
- Full CSV import process
- Multi-step workflows
- Error handling across layers
### ⚡ Performance Tests
**Purpose**: Validate performance requirements
**Speed**: Slow (30+ seconds each)
**Scope**: Load, stress, and performance testing
```bash
# Run performance tests
pytest -m performance
```
**Examples**:
- API response times
- Database query performance
- Large file processing
- Concurrent user scenarios
## Running Tests
### Basic Commands
```bash
# Run all tests
pytest
# Run with verbose output
pytest -v
# Run specific test type
pytest -m unit
pytest -m integration
pytest -m "unit or integration"
# Run tests in specific directory
pytest tests/unit/
pytest tests/integration/api/
# Run specific test file
pytest tests/unit/services/test_product_service.py
# Run specific test class
pytest tests/unit/services/test_product_service.py::TestProductService
# Run specific test method
pytest tests/unit/services/test_product_service.py::TestProductService::test_create_product_success
```
### Advanced Options
```bash
# Run with coverage report
pytest --cov=app --cov-report=html
# Run tests matching pattern
pytest -k "product and not slow"
# Stop on first failure
pytest -x
# Run failed tests from last run
pytest --lf
# Run tests in parallel (if pytest-xdist installed)
pytest -n auto
# Show slowest tests
pytest --durations=10
```
## Test Markers
We use pytest markers to categorize and selectively run tests:
| Marker | Purpose |
|--------|---------|
| `@pytest.mark.unit` | Fast, isolated component tests |
| `@pytest.mark.integration` | Multi-component interaction tests |
| `@pytest.mark.system` | End-to-end system tests |
| `@pytest.mark.performance` | Performance and load tests |
| `@pytest.mark.slow` | Long-running tests |
| `@pytest.mark.api` | API endpoint tests |
| `@pytest.mark.database` | Tests requiring database |
| `@pytest.mark.auth` | Authentication/authorization tests |
### Example Usage
```python
@pytest.mark.unit
@pytest.mark.products
class TestProductService:
def test_create_product_success(self):
# Test implementation
pass
@pytest.mark.integration
@pytest.mark.api
@pytest.mark.database
def test_product_creation_endpoint():
# Test implementation
pass
```
## Test Configuration
### pytest.ini
Our pytest configuration includes:
- **Custom markers** for test categorization
- **Coverage settings** with 80% minimum threshold
- **Test discovery** patterns and paths
- **Output formatting** for better readability
### conftest.py
Core test fixtures and configuration:
- **Database fixtures** for test isolation
- **Authentication fixtures** for user/admin testing
- **Client fixtures** for API testing
- **Mock fixtures** for external dependencies
## Test Data Management
### Fixtures
We organize fixtures by domain:
```python
# tests/fixtures/product_fixtures.py
@pytest.fixture
def sample_product():
return {
"name": "Test Product",
"gtin": "1234567890123",
"price": "19.99"
}
@pytest.fixture
def product_factory():
def _create_product(**kwargs):
defaults = {"name": "Test", "gtin": "1234567890123"}
defaults.update(kwargs)
return defaults
return _create_product
```
### Test Data Files
Static test data in `tests/test_data/`:
- CSV files for import testing
- JSON files for API testing
- Sample configuration files
## Coverage Requirements
We maintain high test coverage standards:
- **Minimum coverage**: 80% overall
- **Critical paths**: 95%+ coverage required
- **New code**: Must include tests
- **HTML reports**: Generated in `htmlcov/`
```bash
# Generate coverage report
pytest --cov=app --cov-report=html --cov-report=term-missing
```
## Best Practices
### Test Naming
- Use descriptive test names that explain the scenario
- Follow the pattern: `test_{action}_{scenario}_{expected_outcome}`
- See our [Test Naming Conventions](test-naming-conventions.md) for details
### Test Structure
- **Arrange**: Set up test data and conditions
- **Act**: Execute the code being tested
- **Assert**: Verify the expected outcome
```python
def test_create_product_with_valid_data_returns_product(self):
# Arrange
product_data = {"name": "Test", "gtin": "1234567890123"}
# Act
result = product_service.create_product(product_data)
# Assert
assert result is not None
assert result.name == "Test"
```
### Test Isolation
- Each test should be independent
- Use database transactions that rollback
- Mock external dependencies
- Clean up test data
## Continuous Integration
Our CI pipeline runs:
1. **Linting** with flake8 and black
2. **Type checking** with mypy
3. **Security scanning** with bandit
4. **Unit tests** on every commit
5. **Integration tests** on pull requests
6. **Performance tests** on releases
## Tools and Libraries
- **pytest**: Test framework and runner
- **pytest-cov**: Coverage reporting
- **pytest-asyncio**: Async test support
- **pytest-mock**: Mocking utilities
- **faker**: Test data generation
- **httpx**: HTTP client for API testing
- **factory-boy**: Test object factories
## Getting Started
1. **Read the conventions**: [Test Naming Conventions](test-naming-conventions.md)
2. **Run existing tests**: `pytest -v`
3. **Write your first test**: See examples in existing test files
4. **Check coverage**: `pytest --cov`
## Need Help?
- **Examples**: Look at existing tests in `tests/` directory
- **Documentation**: This testing section has detailed guides
- **Issues**: Create a GitHub issue for testing questions
- **Standards**: Follow our [naming conventions](test-naming-conventions.md)

View File

@@ -1,403 +0,0 @@
# Running Tests
This guide covers everything you need to know about running tests in the Letzshop Import project.
## Prerequisites
Ensure you have the test dependencies installed:
```bash
pip install -r tests/requirements-test.txt
```
Required packages:
- `pytest>=7.4.0` - Test framework
- `pytest-cov>=4.1.0` - Coverage reporting
- `pytest-asyncio>=0.21.0` - Async test support
- `pytest-mock>=3.11.0` - Mocking utilities
- `httpx>=0.24.0` - HTTP client for API tests
- `faker>=19.0.0` - Test data generation
## Basic Test Commands
### Run All Tests
```bash
# Run the entire test suite
pytest
# Run with verbose output
pytest -v
# Run with very verbose output (show individual test results)
pytest -vv
```
### Run by Test Type
```bash
# Run only unit tests (fast)
pytest -m unit
# Run only integration tests
pytest -m integration
# Run unit and integration tests
pytest -m "unit or integration"
# Run everything except slow tests
pytest -m "not slow"
# Run performance tests only
pytest -m performance
```
### Run by Directory
```bash
# Run all unit tests
pytest tests/unit/
# Run all integration tests
pytest tests/integration/
# Run API endpoint tests
pytest tests/integration/api/
# Run service layer tests
pytest tests/unit/services/
```
### Run Specific Files
```bash
# Run specific test file
pytest tests/unit/services/test_product_service.py
# Run multiple specific files
pytest tests/unit/services/test_product_service.py tests/unit/utils/test_data_processing.py
```
### Run Specific Tests
```bash
# Run specific test class
pytest tests/unit/services/test_product_service.py::TestProductService
# Run specific test method
pytest tests/unit/services/test_product_service.py::TestProductService::test_create_product_success
# Run tests matching pattern
pytest -k "product and create"
pytest -k "test_create_product"
```
## Advanced Test Options
### Coverage Reporting
```bash
# Run with coverage report
pytest --cov=app
# Coverage with missing lines
pytest --cov=app --cov-report=term-missing
# Generate HTML coverage report
pytest --cov=app --cov-report=html
# Coverage for specific modules
pytest --cov=app.services --cov=app.api
# Fail if coverage below threshold
pytest --cov=app --cov-fail-under=80
```
### Output and Debugging
```bash
# Show local variables on failure
pytest --tb=short --showlocals
# Stop on first failure
pytest -x
# Stop after N failures
pytest --maxfail=3
# Show print statements
pytest -s
# Show warnings
pytest -W error
# Capture output (default)
pytest --capture=sys
```
### Test Selection and Filtering
```bash
# Run only failed tests from last run
pytest --lf
# Run failed tests first, then continue
pytest --ff
# Run tests that match keyword expression
pytest -k "user and not admin"
# Run tests modified since last commit
pytest --testmon
# Collect tests without running
pytest --collect-only
```
### Performance and Parallel Execution
```bash
# Show 10 slowest tests
pytest --durations=10
# Show all test durations
pytest --durations=0
# Run tests in parallel (requires pytest-xdist)
pytest -n auto
pytest -n 4 # Use 4 workers
```
## Test Environment Setup
### Database Tests
```bash
# Run database tests (uses test database)
pytest -m database
# Run with test database reset
pytest --tb=short tests/integration/database/
```
### API Tests
```bash
# Run API endpoint tests
pytest -m api
# Run with test client
pytest tests/integration/api/ -v
```
### Authentication Tests
```bash
# Run auth-related tests
pytest -m auth
# Run with user fixtures
pytest tests/integration/security/ -v
```
## Configuration Options
### pytest.ini Settings
Our `pytest.ini` is configured with:
```ini
[pytest]
# Test discovery
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
# Default options
addopts =
-v
--tb=short
--strict-markers
--color=yes
--durations=10
--cov=app
--cov-report=term-missing
--cov-report=html:htmlcov
--cov-fail-under=80
# Custom markers
markers =
unit: Unit tests
integration: Integration tests
# ... other markers
```
### Environment Variables
```bash
# Set test environment
export TESTING=true
# Database URL for tests (uses in-memory SQLite by default)
export TEST_DATABASE_URL="sqlite:///:memory:"
# Disable external API calls in tests
export MOCK_EXTERNAL_APIS=true
```
## Common Test Scenarios
### Development Workflow
```bash
# Quick smoke test (unit tests only)
pytest -m unit --maxfail=1
# Full test run before commit
pytest -m "unit or integration"
# Pre-push comprehensive test
pytest --cov=app --cov-fail-under=80
```
### Debugging Failed Tests
```bash
# Run failed test with detailed output
pytest --lf -vv --tb=long --showlocals
# Drop into debugger on failure (requires ipdb)
pytest --pdb
# Run specific failing test in isolation
pytest tests/path/to/test.py::TestClass::test_method -vv -s
```
### Performance Testing
```bash
# Run performance tests only
pytest -m performance --durations=0
# Run with performance profiling
pytest -m performance --profile
# Load testing specific endpoints
pytest tests/performance/test_api_performance.py -v
```
### CI/CD Pipeline Tests
```bash
# Minimal test run (fast feedback)
pytest -m "unit and not slow" --maxfail=5
# Full CI test run
pytest --cov=app --cov-report=xml --junitxml=test-results.xml
# Security and integration tests
pytest -m "security or integration" --tb=short
```
## Test Reports and Output
### Coverage Reports
```bash
# Terminal coverage report
pytest --cov=app --cov-report=term
# HTML coverage report (opens in browser)
pytest --cov=app --cov-report=html
open htmlcov/index.html
# XML coverage for CI
pytest --cov=app --cov-report=xml
```
### JUnit XML Reports
```bash
# Generate JUnit XML (for CI integration)
pytest --junitxml=test-results.xml
# With coverage and JUnit
pytest --cov=app --cov-report=xml --junitxml=test-results.xml
```
## Troubleshooting
### Common Issues
#### Import Errors
```bash
# If getting import errors, ensure PYTHONPATH is set
PYTHONPATH=. pytest
# Or install in development mode
pip install -e .
```
#### Database Connection Issues
```bash
# Check if test database is accessible
python -c "from tests.conftest import engine; engine.connect()"
# Run with in-memory database
pytest --override-db-url="sqlite:///:memory:"
```
#### Fixture Not Found
```bash
# Ensure conftest.py is in the right location
ls tests/conftest.py
# Check fixture imports
pytest --fixtures tests/unit/
```
#### Permission Issues
```bash
# Fix test file permissions
chmod +x tests/**/*.py
# Clear pytest cache
rm -rf .pytest_cache/
```
### Performance Issues
```bash
# Identify slow tests
pytest --durations=10 --durations-min=1.0
# Profile test execution
pytest --profile-svg
# Run subset of tests for faster feedback
pytest -m "unit and not slow"
```
## Integration with IDEs
### VS Code
Add to `.vscode/settings.json`:
```json
{
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": [
"tests",
"-v"
],
"python.testing.cwd": "${workspaceFolder}"
}
```
### PyCharm
1. Go to Settings → Tools → Python Integrated Tools
2. Set Testing → Default test runner to "pytest"
3. Set pytest options: `-v --tb=short`
## Best Practices
### During Development
1. **Run unit tests frequently** - Fast feedback loop
2. **Run integration tests before commits** - Catch interaction issues
3. **Check coverage regularly** - Ensure good test coverage
4. **Use descriptive test names** - Easy to understand failures
### Before Code Review
1. **Run full test suite** - `pytest`
2. **Check coverage meets threshold** - `pytest --cov-fail-under=80`
3. **Ensure no warnings** - `pytest -W error`
4. **Test with fresh environment** - New terminal/clean cache
### In CI/CD
1. **Fail fast on unit tests** - `pytest -m unit --maxfail=1`
2. **Generate reports** - Coverage and JUnit XML
3. **Run performance tests on schedule** - Not every commit
4. **Archive test results** - For debugging and trends
---
Need help with a specific testing scenario? Check our [Testing FAQ](testing-faq.md) or open a GitHub issue!

View File

@@ -0,0 +1,551 @@
# Test Maintenance Guide
This guide covers how to maintain, update, and contribute to our test suite as the application evolves. It's designed for developers who need to modify existing tests or add new test coverage.
## Test Maintenance Philosophy
Our test suite follows these core principles:
- **Tests should be reliable** - They pass consistently and fail only when there are real issues
- **Tests should be fast** - Unit tests complete in milliseconds, integration tests in seconds
- **Tests should be maintainable** - Easy to update when code changes
- **Tests should provide clear feedback** - Failures should clearly indicate what went wrong
## When to Update Tests
### Code Changes That Require Test Updates
**API Changes**:
```bash
# When you modify API endpoints, update integration tests
pytest tests/integration/api/v1/test_*_endpoints.py -v
```
**Business Logic Changes**:
```bash
# When you modify service logic, update unit tests
pytest tests/unit/services/test_*_service.py -v
```
**Database Model Changes**:
```bash
# When you modify models, update model tests
pytest tests/unit/models/test_database_models.py -v
```
**New Features**:
- Add new test files following our naming conventions
- Ensure both unit and integration test coverage
- Add appropriate pytest markers
## Common Maintenance Tasks
### Adding Tests for New Features
**Step 1: Determine Test Type and Location**
```python
# New business logic → Unit test
tests/unit/services/test_new_feature_service.py
# New API endpoint → Integration test
tests/integration/api/v1/test_new_feature_endpoints.py
# New workflow → Integration test
tests/integration/workflows/test_new_feature_workflow.py
```
**Step 2: Create Test File with Proper Structure**
```python
import pytest
from app.services.new_feature_service import NewFeatureService
@pytest.mark.unit
@pytest.mark.new_feature # Add domain marker
class TestNewFeatureService:
"""Unit tests for NewFeatureService"""
def setup_method(self):
"""Setup run before each test"""
self.service = NewFeatureService()
def test_new_feature_with_valid_input_succeeds(self):
"""Test the happy path"""
# Test implementation
pass
def test_new_feature_with_invalid_input_raises_error(self):
"""Test error handling"""
# Test implementation
pass
```
**Step 3: Add Domain Marker to pytest.ini**
```ini
# Add to markers section in pytest.ini
new_feature: marks tests related to new feature functionality
```
### Updating Tests for API Changes
**Example: Adding a new field to product creation**
```python
# Before: tests/integration/api/v1/test_product_endpoints.py
def test_create_product_success(self, client, auth_headers):
product_data = {
"product_id": "TEST001",
"title": "Test Product",
"price": "19.99"
}
response = client.post("/api/v1/product", json=product_data, headers=auth_headers)
assert response.status_code == 200
# After: Adding 'category' field
def test_create_product_success(self, client, auth_headers):
product_data = {
"product_id": "TEST001",
"title": "Test Product",
"price": "19.99",
"category": "Electronics" # New field
}
response = client.post("/api/v1/product", json=product_data, headers=auth_headers)
assert response.status_code == 200
assert response.json()["category"] == "Electronics" # Verify new field
# Add test for validation
def test_create_product_with_invalid_category_fails(self, client, auth_headers):
product_data = {
"product_id": "TEST002",
"title": "Test Product",
"price": "19.99",
"category": "" # Invalid empty category
}
response = client.post("/api/v1/product", json=product_data, headers=auth_headers)
assert response.status_code == 422
```
### Updating Fixtures for Model Changes
**When you add fields to database models, update fixtures**:
```python
# tests/fixtures/product_fixtures.py - Before
@pytest.fixture
def test_product(db):
product = Product(
product_id="TEST001",
title="Test Product",
price="10.99"
)
# ... rest of fixture
# After: Adding new category field
@pytest.fixture
def test_product(db):
product = Product(
product_id="TEST001",
title="Test Product",
price="10.99",
category="Electronics" # Add new field with sensible default
)
# ... rest of fixture
```
### Handling Breaking Changes
**When making breaking changes that affect many tests**:
1. **Update fixtures first** to include new required fields
2. **Run tests to identify failures**: `pytest -x` (stop on first failure)
3. **Update tests systematically** by domain
4. **Verify coverage hasn't decreased**: `make test-coverage`
## Test Data Management
### Creating New Fixtures
**Add domain-specific fixtures to appropriate files**:
```python
# tests/fixtures/new_domain_fixtures.py
import pytest
from models.database import NewModel
@pytest.fixture
def test_new_model(db):
"""Create a test instance of NewModel"""
model = NewModel(
name="Test Model",
value="test_value"
)
db.add(model)
db.commit()
db.refresh(model)
return model
@pytest.fixture
def new_model_factory():
"""Factory for creating custom NewModel instances"""
def _create_new_model(db, **kwargs):
defaults = {"name": "Default Name", "value": "default"}
defaults.update(kwargs)
model = NewModel(**defaults)
db.add(model)
db.commit()
db.refresh(model)
return model
return _create_new_model
```
**Register new fixture module in conftest.py**:
```python
# tests/conftest.py
pytest_plugins = [
"tests.fixtures.auth_fixtures",
"tests.fixtures.product_fixtures",
"tests.fixtures.shop_fixtures",
"tests.fixtures.marketplace_fixtures",
"tests.fixtures.new_domain_fixtures", # Add new fixture module
]
```
### Managing Test Data Files
**Static test data in tests/test_data/**:
```
tests/test_data/
├── csv/
│ ├── valid_products.csv # Standard valid product data
│ ├── invalid_products.csv # Data with validation errors
│ ├── large_product_set.csv # Performance testing data
│ └── new_feature_data.csv # Data for new feature testing
├── json/
│ ├── api_responses.json # Mock API responses
│ └── configuration_samples.json # Configuration test data
└── fixtures/
└── database_seeds.json # Database seed data
```
**Update test data when adding new fields**:
```csv
# Before: tests/test_data/csv/valid_products.csv
product_id,title,price
TEST001,Product 1,19.99
TEST002,Product 2,29.99
# After: Adding category field
product_id,title,price,category
TEST001,Product 1,19.99,Electronics
TEST002,Product 2,29.99,Books
```
## Performance Test Maintenance
### Updating Performance Baselines
**When application performance improves or requirements change**:
```python
# tests/performance/test_api_performance.py
def test_product_list_performance(self, client, auth_headers, db):
# Create test data
products = [Product(product_id=f"PERF{i:03d}") for i in range(100)]
db.add_all(products)
db.commit()
# Time the request
start_time = time.time()
response = client.get("/api/v1/product?limit=100", headers=auth_headers)
end_time = time.time()
assert response.status_code == 200
assert len(response.json()["products"]) == 100
# Update baseline if performance has improved
assert end_time - start_time < 1.5 # Previously was 2.0 seconds
```
### Adding Performance Tests for New Features
```python
@pytest.mark.performance
@pytest.mark.slow
@pytest.mark.new_feature
def test_new_feature_performance_with_large_dataset(self, client, auth_headers, db):
"""Test new feature performance with realistic data volume"""
# Create large dataset
large_dataset = [NewModel(data=f"item_{i}") for i in range(1000)]
db.add_all(large_dataset)
db.commit()
# Test performance
start_time = time.time()
response = client.post("/api/v1/new-feature/process",
json={"process_all": True},
headers=auth_headers)
end_time = time.time()
assert response.status_code == 200
assert end_time - start_time < 10.0 # Should complete within 10 seconds
```
## Debugging and Troubleshooting
### Identifying Flaky Tests
**Tests that pass/fail inconsistently need attention**:
```bash
# Run the same test multiple times to identify flaky behavior
pytest tests/path/to/flaky_test.py -v --count=10
# Run with more verbose output to see what's changing
pytest tests/path/to/flaky_test.py -vv --tb=long --showlocals
```
**Common causes of flaky tests**:
- Database state not properly cleaned between tests
- Timing issues in async operations
- External service dependencies
- Shared mutable state between tests
### Fixing Common Test Issues
**Database State Issues**:
```python
# Ensure proper cleanup in fixtures
@pytest.fixture
def clean_database(db):
"""Ensure clean database state"""
yield db
# Explicit cleanup if needed
db.query(SomeModel).delete()
db.commit()
```
**Async Test Issues**:
```python
# Ensure proper async test setup
@pytest.mark.asyncio
async def test_async_operation():
# Use await for all async operations
result = await async_service.process_data()
assert result is not None
```
**Mock-Related Issues**:
```python
# Ensure mocks are properly reset between tests
def setup_method(self):
"""Reset mocks before each test"""
self.mock_service.reset_mock()
```
### Test Coverage Issues
**Identifying gaps in coverage**:
```bash
# Generate coverage report with missing lines
pytest --cov=app --cov-report=term-missing
# View HTML report for detailed analysis
pytest --cov=app --cov-report=html
open htmlcov/index.html
```
**Adding tests for uncovered code**:
```python
# Example: Adding test for error handling branch
def test_service_method_handles_database_error(self, mock_db):
"""Test error handling path that wasn't covered"""
# Setup mock to raise exception
mock_db.commit.side_effect = DatabaseError("Connection failed")
# Test that error is handled appropriately
with pytest.raises(ServiceError):
self.service.save_data(test_data)
```
## Code Quality Standards
### Test Code Review Checklist
**Before submitting test changes**:
- [ ] Tests have descriptive names explaining the scenario
- [ ] Appropriate pytest markers are used
- [ ] Test coverage hasn't decreased
- [ ] Tests are in the correct category (unit/integration/system)
- [ ] No hardcoded values that could break in different environments
- [ ] Error cases are tested, not just happy paths
- [ ] New fixtures are properly documented
- [ ] Performance tests have reasonable baselines
### Refactoring Tests
**When refactoring test code**:
```python
# Before: Repetitive test setup
class TestProductService:
def test_create_product_success(self):
service = ProductService()
data = {"name": "Test", "price": "10.99"}
result = service.create_product(data)
assert result is not None
def test_create_product_validation_error(self):
service = ProductService() # Duplicate setup
data = {"name": "", "price": "invalid"}
with pytest.raises(ValidationError):
service.create_product(data)
# After: Using setup_method and constants
class TestProductService:
def setup_method(self):
self.service = ProductService()
self.valid_data = {"name": "Test", "price": "10.99"}
def test_create_product_success(self):
result = self.service.create_product(self.valid_data)
assert result is not None
def test_create_product_validation_error(self):
invalid_data = {"name": "", "price": "invalid"}
with pytest.raises(ValidationError):
self.service.create_product(invalid_data)
```
## Working with CI/CD
### Test Categories in CI Pipeline
Our CI pipeline runs tests in stages:
**Stage 1: Fast Feedback**
```bash
make test-fast # Unit tests + fast integration tests
```
**Stage 2: Comprehensive Testing**
```bash
make test-coverage # Full suite with coverage
```
**Stage 3: Performance Validation** (on release branches)
```bash
pytest -m performance
```
### Making Tests CI-Friendly
**Ensure tests are deterministic**:
```python
# Bad: Tests that depend on current time
def test_user_creation():
user = create_user()
assert user.created_at.day == datetime.now().day # Flaky at midnight
# Good: Tests with controlled time
def test_user_creation(freezer):
freezer.freeze("2024-01-15 10:00:00")
user = create_user()
assert user.created_at == datetime(2024, 1, 15, 10, 0, 0)
```
**Make tests environment-independent**:
```python
# Use relative paths and environment variables
TEST_DATA_DIR = Path(__file__).parent / "test_data"
CSV_FILE = TEST_DATA_DIR / "sample_products.csv"
```
## Migration and Upgrade Strategies
### When Upgrading Dependencies
**Test dependency upgrades**:
```bash
# Test with new versions before upgrading
pip install pytest==8.0.0 pytest-cov==5.0.0
make test
# If tests fail, identify compatibility issues
pytest --tb=short -x
```
**Update test configuration for new pytest versions**:
```ini
# pytest.ini - may need updates for new versions
minversion = 8.0
# Check if any deprecated features are used
```
### Database Schema Changes
**When modifying database models**:
1. Update model test fixtures first
2. Run migration on test database
3. Update affected test data files
4. Run integration tests to catch relationship issues
```python
# Update fixtures for new required fields
@pytest.fixture
def test_product(db):
product = Product(
# ... existing fields
new_required_field="default_value" # Add with sensible default
)
return product
```
## Documentation and Knowledge Sharing
### Documenting Complex Test Scenarios
**For complex business logic tests**:
```python
def test_complex_pricing_calculation_scenario(self):
"""
Test pricing calculation with multiple discounts and tax rules.
Scenario:
- Product price: $100
- Member discount: 10%
- Seasonal discount: 5% (applied after member discount)
- Tax rate: 8.5%
Expected calculation:
Base: $100 → Member discount: $90 → Seasonal: $85.50 → Tax: $92.77
"""
# Test implementation with clear steps
```
### Team Knowledge Sharing
**Maintain test documentation**:
- Update this guide when adding new test patterns
- Document complex fixture relationships
- Share test debugging techniques in team meetings
- Create examples for new team members
## Summary: Test Maintenance Best Practices
**Daily Practices**:
- Run relevant tests before committing code
- Add tests for new functionality immediately
- Keep test names descriptive and current
- Update fixtures when models change
**Regular Maintenance**:
- Review and update performance baselines
- Refactor repetitive test code
- Clean up unused fixtures and test data
- Monitor test execution times
**Long-term Strategy**:
- Plan test architecture for new features
- Evaluate test coverage trends
- Update testing tools and practices
- Share knowledge across the team
**Remember**: Good tests are living documentation of your system's behavior. Keep them current, clear, and comprehensive to maintain a healthy codebase.
Use this guide alongside the [Testing Guide](testing-guide.md) for complete test management knowledge.

View File

@@ -1,383 +0,0 @@
# Test Naming Conventions
This document outlines the naming conventions used in our test suite to ensure consistency, clarity, and maintainability across the project.
## Overview
Our test suite follows a hierarchical structure organized by test type and component, with clear naming patterns that make it easy to locate and understand test purposes.
## Directory Structure
```
tests/
├── conftest.py # Core test configuration and fixtures
├── pytest.ini # Pytest configuration
├── fixtures/ # Shared test fixtures organized by domain
├── unit/ # Fast, isolated component tests
├── integration/ # Multi-component interaction tests
├── performance/ # Performance and load tests
├── system/ # End-to-end system behavior tests
└── test_data/ # Test data files (CSV, JSON, etc.)
```
## File Naming Conventions
### General Rule
All test files must start with `test_` prefix for pytest auto-discovery.
**Pattern:** `test_{component/feature}.py`
### Unit Tests (`tests/unit/`)
Focus on testing individual components in isolation.
```
tests/unit/
├── models/
│ ├── test_database_models.py # Database model tests
│ ├── test_api_models.py # API model validation
│ └── test_model_relationships.py # Model relationship tests
├── utils/
│ ├── test_data_processing.py # Data processing utilities
│ ├── test_csv_processor.py # CSV processing utilities
│ ├── test_validators.py # Validation utilities
│ └── test_formatters.py # Data formatting utilities
├── services/
│ ├── test_admin_service.py # Admin service business logic
│ ├── test_auth_service.py # Authentication service
│ ├── test_product_service.py # Product management service
│ ├── test_shop_service.py # Shop management service
│ ├── test_stock_service.py # Stock management service
│ ├── test_marketplace_service.py # Marketplace import service
│ └── test_stats_service.py # Statistics service
└── core/
├── test_config.py # Configuration management
├── test_database.py # Database utilities
└── test_logging.py # Logging functionality
```
### Integration Tests (`tests/integration/`)
Focus on testing interactions between multiple components.
```
tests/integration/
├── api/v1/
│ ├── test_auth_endpoints.py # Authentication API endpoints
│ ├── test_admin_endpoints.py # Admin API endpoints
│ ├── test_product_endpoints.py # Product CRUD endpoints
│ ├── test_shop_endpoints.py # Shop management endpoints
│ ├── test_stock_endpoints.py # Stock management endpoints
│ ├── test_marketplace_endpoints.py # Import endpoints
│ ├── test_stats_endpoints.py # Statistics endpoints
│ └── test_pagination.py # Pagination functionality
├── database/
│ ├── test_migrations.py # Database migration tests
│ ├── test_transactions.py # Transaction handling
│ └── test_constraints.py # Database constraints
├── security/
│ ├── test_authentication.py # Authentication mechanisms
│ ├── test_authorization.py # Permission and role tests
│ ├── test_input_validation.py # Input security validation
│ ├── test_rate_limiting.py # Rate limiting middleware
│ └── test_cors.py # CORS configuration
└── workflows/
├── test_product_import_workflow.py # Complete import process
├── test_user_registration_flow.py # User registration process
└── test_shop_setup_flow.py # Shop creation workflow
```
### System Tests (`tests/system/`)
Focus on end-to-end application behavior.
```
tests/system/
├── test_application_startup.py # Application initialization
├── test_error_handling.py # Global error handling
├── test_health_checks.py # Health endpoint tests
├── test_database_connectivity.py # Database connection tests
└── test_external_dependencies.py # Third-party service tests
```
### Performance Tests (`tests/performance/`)
Focus on performance benchmarks and load testing.
```
tests/performance/
├── test_api_performance.py # API endpoint performance
├── test_database_performance.py # Database query performance
├── test_import_performance.py # Large file import tests
└── test_concurrent_users.py # Multi-user scenarios
```
## Class Naming Conventions
Use descriptive class names that clearly indicate what is being tested:
### Pattern: `Test{ComponentName}{TestType}`
```python
# Good examples
class TestProductService: # Testing ProductService class
class TestProductModel: # Testing Product model
class TestProductEndpoints: # Testing product API endpoints
class TestProductValidation: # Testing product validation logic
class TestProductPermissions: # Testing product access control
# Avoid generic names
class TestProduct: # Too vague - what aspect of Product?
class Tests: # Too generic
```
### Specialized Class Naming
```python
class TestProductCRUD: # CRUD operations
class TestProductSecurity: # Security-related tests
class TestProductErrorHandling: # Error scenario tests
class TestProductEdgeCases: # Boundary condition tests
```
## Method Naming Conventions
Test method names should be descriptive and follow a clear pattern that explains:
1. What is being tested
2. The scenario/condition
3. Expected outcome
### Pattern: `test_{action}_{scenario}_{expected_outcome}`
```python
# Good examples - Clear and descriptive
def test_create_product_with_valid_data_returns_product():
def test_create_product_with_invalid_gtin_raises_validation_error():
def test_get_product_by_id_when_not_found_returns_404():
def test_update_product_without_permission_raises_forbidden():
def test_delete_product_with_existing_stock_prevents_deletion():
# Acceptable shorter versions
def test_create_product_success():
def test_create_product_invalid_data():
def test_create_product_unauthorized():
def test_get_product_not_found():
```
### Method Naming Patterns by Scenario
**Happy Path Tests:**
```python
def test_create_user_success():
def test_login_valid_credentials():
def test_import_csv_valid_format():
```
**Error/Edge Case Tests:**
```python
def test_create_user_duplicate_email_fails():
def test_login_invalid_credentials_rejected():
def test_import_csv_malformed_data_raises_error():
```
**Permission/Security Tests:**
```python
def test_admin_endpoint_requires_admin_role():
def test_user_cannot_access_other_user_data():
def test_api_key_required_for_marketplace_import():
```
**Boundary/Edge Cases:**
```python
def test_pagination_with_zero_items():
def test_price_with_maximum_decimal_places():
def test_gtin_with_minimum_valid_length():
```
## Marker Usage
Use pytest markers to categorize and run specific test types:
```python
@pytest.mark.unit
class TestProductService:
"""Unit tests for ProductService business logic"""
@pytest.mark.integration
@pytest.mark.api
class TestProductEndpoints:
"""Integration tests for Product API endpoints"""
@pytest.mark.slow
@pytest.mark.performance
class TestImportPerformance:
"""Performance tests for large CSV imports"""
```
### Available Markers
| Marker | Purpose |
|--------|---------|
| `@pytest.mark.unit` | Fast, isolated component tests |
| `@pytest.mark.integration` | Multi-component interaction tests |
| `@pytest.mark.system` | End-to-end system tests |
| `@pytest.mark.performance` | Performance and load tests |
| `@pytest.mark.slow` | Long-running tests |
| `@pytest.mark.api` | API endpoint tests |
| `@pytest.mark.database` | Tests requiring database |
| `@pytest.mark.auth` | Authentication/authorization tests |
| `@pytest.mark.admin` | Admin functionality tests |
## File Organization Best Practices
### Mirror Source Structure
Test files should mirror the source code structure:
```
app/services/product_service.py → tests/unit/services/test_product_service.py
app/api/v1/admin.py → tests/integration/api/v1/test_admin_endpoints.py
```
### Group Related Tests
Keep related tests in the same file:
```python
# test_product_service.py
class TestProductCreation: # All product creation scenarios
class TestProductValidation: # All validation scenarios
class TestProductQueries: # All query scenarios
```
### Separate Complex Workflows
Break complex workflows into separate files:
```
test_user_registration_flow.py # Complete registration process
test_shop_setup_flow.py # Shop creation workflow
test_product_import_workflow.py # CSV import end-to-end
```
## Running Tests by Name Pattern
Use pytest's flexible test discovery:
```bash
# Run all unit tests
pytest tests/unit/ -v
# Run specific component tests
pytest tests/ -k "product" -v
# Run by marker
pytest -m "unit and not slow" -v
# Run specific test class
pytest tests/unit/services/test_product_service.py::TestProductService -v
# Run specific test method
pytest tests/unit/services/test_product_service.py::TestProductService::test_create_product_success -v
```
## Examples
### Complete Test File Example
```python
# tests/unit/services/test_product_service.py
import pytest
from unittest.mock import Mock, patch
from app.services.product_service import ProductService
from app.models.database_models import Product
@pytest.mark.unit
class TestProductService:
"""Unit tests for ProductService business logic"""
def setup_method(self):
"""Setup run before each test method"""
self.service = ProductService()
self.mock_db = Mock()
def test_create_product_with_valid_data_returns_product(self):
"""Test successful product creation with valid input data"""
# Arrange
product_data = {
"name": "Test Product",
"gtin": "1234567890123",
"price": "19.99"
}
# Act
result = self.service.create_product(product_data)
# Assert
assert result is not None
assert result.name == "Test Product"
def test_create_product_with_invalid_gtin_raises_validation_error(self):
"""Test product creation fails with invalid GTIN format"""
# Arrange
product_data = {
"name": "Test Product",
"gtin": "invalid_gtin",
"price": "19.99"
}
# Act & Assert
with pytest.raises(ValidationError, match="Invalid GTIN format"):
self.service.create_product(product_data)
@pytest.mark.unit
class TestProductValidation:
"""Unit tests for product validation logic"""
def test_validate_gtin_with_valid_format_returns_true(self):
"""Test GTIN validation accepts valid 13-digit GTIN"""
assert ProductService.validate_gtin("1234567890123") is True
def test_validate_gtin_with_invalid_format_returns_false(self):
"""Test GTIN validation rejects invalid format"""
assert ProductService.validate_gtin("invalid") is False
```
## Naming Anti-Patterns to Avoid
**Avoid these patterns:**
```python
# Too generic
def test_product():
def test_user():
def test_api():
# Unclear purpose
def test_function():
def test_method():
def test_endpoint():
# Non-descriptive
def test_1():
def test_a():
def test_scenario():
# Inconsistent naming
def testProductCreation(): # Wrong case
def test_product_creation(): # Good
def TestProductCreation(): # Wrong - this is for classes
```
**Use these patterns instead:**
```python
# Clear, descriptive, consistent
def test_create_product_with_valid_data_succeeds():
def test_authenticate_user_with_invalid_token_fails():
def test_get_products_endpoint_returns_paginated_results():
```
---
Following these naming conventions will help maintain a clean, understandable, and maintainable test suite that scales with your project.

View File

@@ -0,0 +1,470 @@
# Testing Guide for Developers
This guide provides everything your development team needs to know about our comprehensive test suite structure, how to run tests effectively, and how to maintain test quality.
## Quick Start
```bash
# Install test dependencies
make install-test
# Run all tests
make test
# Run fast tests only (development workflow)
make test-fast
# Run with coverage
make test-coverage
```
## Test Structure Overview
Our test suite is organized hierarchically by test type and execution speed to optimize development workflows:
```
tests/
├── conftest.py # Core test configuration and database fixtures
├── pytest.ini # Test configuration with markers and coverage
├── fixtures/ # Domain-organized test fixtures
│ ├── auth_fixtures.py # Users, tokens, authentication headers
│ ├── product_fixtures.py # Products, factories, bulk test data
│ ├── shop_fixtures.py # Shops, stock, shop-product relationships
│ └── marketplace_fixtures.py # Import jobs and marketplace data
├── unit/ # Fast, isolated component tests (< 1 second)
│ ├── models/ # Database and API model tests
│ ├── utils/ # Utility function tests
│ ├── services/ # Business logic tests
│ └── middleware/ # Middleware component tests
├── integration/ # Multi-component tests (1-10 seconds)
│ ├── api/v1/ # API endpoint tests with database
│ ├── security/ # Authentication, authorization tests
│ ├── tasks/ # Background task integration tests
│ └── workflows/ # Multi-step process tests
├── performance/ # Performance benchmarks (10+ seconds)
│ └── test_api_performance.py # Load testing and benchmarks
├── system/ # End-to-end system tests (30+ seconds)
│ └── test_error_handling.py # Application-wide error handling
└── test_data/ # Static test data files
└── csv/sample_products.csv # Sample CSV for import testing
```
## Test Categories and When to Use Each
### Unit Tests (`tests/unit/`)
**Purpose**: Test individual components in isolation
**Speed**: Very fast (< 1 second each)
**Use when**: Testing business logic, data processing, model validation
```bash
# Run during active development
pytest -m unit
# Example locations:
tests/unit/services/test_product_service.py # Business logic
tests/unit/utils/test_data_processing.py # Utility functions
tests/unit/models/test_database_models.py # Model validation
```
### Integration Tests (`tests/integration/`)
**Purpose**: Test component interactions
**Speed**: Moderate (1-10 seconds each)
**Use when**: Testing API endpoints, service interactions, workflows
```bash
# Run before commits
pytest -m integration
# Example locations:
tests/integration/api/v1/test_admin_endpoints.py # API endpoints
tests/integration/security/test_authentication.py # Auth workflows
tests/integration/workflows/test_product_import.py # Multi-step processes
```
### Performance Tests (`tests/performance/`)
**Purpose**: Validate performance requirements
**Speed**: Slow (10+ seconds each)
**Use when**: Testing response times, load capacity, large data processing
```bash
# Run periodically or in CI
pytest -m performance
```
### System Tests (`tests/system/`)
**Purpose**: End-to-end application behavior
**Speed**: Slowest (30+ seconds each)
**Use when**: Testing complete user scenarios, error handling across layers
```bash
# Run before releases
pytest -m system
```
## Daily Development Workflow
### During Active Development
```bash
# Quick feedback loop - run relevant unit tests
pytest tests/unit/services/test_product_service.py -v
# Test specific functionality you're working on
pytest -k "product and create" -m unit
# Fast comprehensive check
make test-fast # Equivalent to: pytest -m "not slow"
```
### Before Committing Code
```bash
# Run unit and integration tests
make test-unit
make test-integration
# Or run both with coverage
make test-coverage
```
### Before Creating Pull Request
```bash
# Full test suite with linting
make ci # Runs format, lint, and test-coverage
# Check if all tests pass
make test
```
## Running Specific Tests
### By Test Type
```bash
# Fast unit tests only
pytest -m unit
# Integration tests only
pytest -m integration
# Everything except slow tests
pytest -m "not slow"
# Database-dependent tests
pytest -m database
# Authentication-related tests
pytest -m auth
```
### By Component/Domain
```bash
# All product-related tests
pytest -k "product"
# Admin functionality tests
pytest -m admin
# API endpoint tests
pytest -m api
# All tests in a directory
pytest tests/unit/services/ -v
```
### By Specific Files or Methods
```bash
# Specific test file
pytest tests/unit/services/test_product_service.py -v
# Specific test class
pytest tests/unit/services/test_product_service.py::TestProductService -v
# Specific test method
pytest tests/unit/services/test_product_service.py::TestProductService::test_create_product_success -v
```
## Test Fixtures and Data
### Using Existing Fixtures
Our fixtures are organized by domain in the `fixtures/` directory:
```python
# In your test file
def test_product_creation(test_user, test_shop, auth_headers):
"""Uses auth_fixtures.py fixtures"""
# test_user: Creates a test user
# test_shop: Creates a test shop owned by test_user
# auth_headers: Provides authentication headers for API calls
def test_multiple_products(multiple_products):
"""Uses product_fixtures.py fixtures"""
# multiple_products: Creates 5 test products with different attributes
assert len(multiple_products) == 5
def test_with_factory(product_factory, db):
"""Uses factory fixtures for custom test data"""
# Create custom product with specific attributes
product = product_factory(db, title="Custom Product", price="99.99")
assert product.title == "Custom Product"
```
### Available Fixtures by Domain
**Authentication (`auth_fixtures.py`)**:
- `test_user`, `test_admin`, `other_user`
- `auth_headers`, `admin_headers`
- `auth_manager`
**Products (`product_fixtures.py`)**:
- `test_product`, `unique_product`, `multiple_products`
- `product_factory` (for custom products)
**Shops (`shop_fixtures.py`)**:
- `test_shop`, `unique_shop`, `inactive_shop`, `verified_shop`
- `shop_product`, `test_stock`, `multiple_stocks`
- `shop_factory` (for custom shops)
**Marketplace (`marketplace_fixtures.py`)**:
- `test_marketplace_job`
## Writing New Tests
### Test File Location
Choose location based on what you're testing:
```python
# Business logic → unit tests
tests/unit/services/test_my_new_service.py
# API endpoints → integration tests
tests/integration/api/v1/test_my_new_endpoints.py
# Multi-component workflows → integration tests
tests/integration/workflows/test_my_new_workflow.py
# Performance concerns → performance tests
tests/performance/test_my_performance.py
```
### Test Class Structure
```python
import pytest
from app.services.my_service import MyService
@pytest.mark.unit # Always add appropriate markers
@pytest.mark.products # Domain-specific marker
class TestMyService:
"""Test suite for MyService business logic"""
def setup_method(self):
"""Run before each test method"""
self.service = MyService()
def test_create_item_with_valid_data_succeeds(self):
"""Test successful item creation - descriptive name explaining scenario"""
# Arrange
item_data = {"name": "Test Item", "price": "10.99"}
# Act
result = self.service.create_item(item_data)
# Assert
assert result is not None
assert result.name == "Test Item"
def test_create_item_with_invalid_data_raises_validation_error(self):
"""Test validation error handling"""
# Arrange
invalid_data = {"name": "", "price": "invalid"}
# Act & Assert
with pytest.raises(ValidationError):
self.service.create_item(invalid_data)
```
### API Integration Test Example
```python
import pytest
@pytest.mark.integration
@pytest.mark.api
@pytest.mark.products
class TestProductEndpoints:
"""Integration tests for product API endpoints"""
def test_create_product_endpoint_success(self, client, auth_headers):
"""Test successful product creation via API"""
# Arrange
product_data = {
"product_id": "TEST001",
"title": "Test Product",
"price": "19.99"
}
# Act
response = client.post("/api/v1/product",
json=product_data,
headers=auth_headers)
# Assert
assert response.status_code == 200
assert response.json()["product_id"] == "TEST001"
```
## Test Naming Conventions
### Files
- `test_{component_name}.py` for the file name
- Mirror your source structure: `app/services/product.py``tests/unit/services/test_product_service.py`
### Classes
- `TestComponentName` for the main component
- `TestComponentValidation` for validation-specific tests
- `TestComponentErrorHandling` for error scenarios
### Methods
Use descriptive names that explain the scenario:
```python
# Good - explains what, when, and expected outcome
def test_create_product_with_valid_data_returns_product(self):
def test_create_product_with_duplicate_id_raises_error(self):
def test_get_product_when_not_found_returns_404(self):
# Acceptable shorter versions
def test_create_product_success(self):
def test_create_product_validation_error(self):
def test_get_product_not_found(self):
```
## Coverage Requirements
We maintain high coverage standards:
- **Minimum overall coverage**: 80%
- **New code coverage**: 90%+
- **Critical paths**: 95%+
```bash
# Check coverage
make test-coverage
# View detailed HTML report
open htmlcov/index.html
# Fail build if coverage too low
pytest --cov=app --cov-fail-under=80
```
## Debugging Failed Tests
### Get Detailed Information
```bash
# Verbose output with local variables
pytest tests/path/to/test.py -vv --tb=long --showlocals
# Stop on first failure
pytest -x
# Re-run only failed tests
pytest --lf
```
### Common Issues and Solutions
**Import Errors**:
```bash
# Ensure you're in project root and have installed in dev mode
pip install -e .
PYTHONPATH=. pytest
```
**Database Issues**:
```bash
# Tests use in-memory SQLite by default
# Check if fixtures are properly imported
pytest --fixtures tests/
```
**Fixture Not Found**:
```bash
# Ensure fixture modules are listed in conftest.py pytest_plugins
# Check fixture dependencies (test_shop needs test_user)
```
## Performance and Optimization
### Speed Up Test Runs
```bash
# Run in parallel (install pytest-xdist first)
pytest -n auto
# Skip slow tests during development
pytest -m "not slow"
# Run only changed tests (install pytest-testmon)
pytest --testmon
```
### Find Slow Tests
```bash
# Show 10 slowest tests
pytest --durations=10
# Show all test durations
pytest --durations=0
```
## Continuous Integration Integration
Our tests integrate with CI/CD pipelines through make targets:
```bash
# Commands used in CI
make ci # Format, lint, test with coverage
make test-fast # Quick feedback in early CI stages
make test-coverage # Full test run with coverage reporting
```
The CI pipeline:
1. Runs `make test-fast` for quick feedback
2. Runs `make ci` for comprehensive checks
3. Generates coverage reports in XML format
4. Uploads coverage to reporting tools
## Best Practices Summary
### DO:
- Write tests for new code before committing
- Use descriptive test names explaining the scenario
- Keep unit tests fast (< 1 second each)
- Use appropriate fixtures for test data
- Add proper pytest markers to categorize tests
- Test both happy path and error scenarios
- Maintain good test coverage (80%+)
### DON'T:
- Write tests that depend on external services (use mocks)
- Create tests that depend on execution order
- Use hardcoded values that might change
- Write overly complex test setups
- Ignore failing tests
- Skip adding tests for bug fixes
## Getting Help
- **Examples**: Look at existing tests in similar components
- **Fixtures**: Check `tests/fixtures/` for available test data
- **Configuration**: See `pytest.ini` for available markers
- **Make targets**: Run `make help` to see all available commands
- **Team support**: Ask in team channels or create GitHub issues
## Make Commands Reference
```bash
make install-test # Install test dependencies
make test # Run all tests
make test-unit # Run unit tests only
make test-integration # Run integration tests only
make test-fast # Run all except slow tests
make test-coverage # Run with coverage report
make ci # Full CI pipeline (format, lint, test)
```
Use this guide as your daily reference for testing. The structure is designed to give you fast feedback during development while maintaining comprehensive test coverage.

View File

@@ -26,10 +26,8 @@ nav:
- CSV Import: guides/csv-import.md
- Marketplace Integration: guides/marketplace-integration.md
- Testing:
- Overview: testing/index.md
- Naming Conventions: testing/test-naming-conventions.md
- Running Tests: testing/running-tests.md
- Test Data: testing/test-data.md
- Testing Guide: testing/testing-guide.md
- Test Maintenance: testing/test-maintenance.md
- Development:
- Architecture: development/architecture.md
- Database Schema: development/database-schema.md

View File

@@ -1,171 +0,0 @@
# Models Restructure Plan
## New Structure
```
models/
├── database/
│ ├── __init__.py # Import all models for easy access
│ ├── base.py # Base model class and mixins
│ ├── user.py # User model
│ ├── shop.py # Shop, ShopProduct models
│ ├── product.py # Product model
│ ├── stock.py # Stock model
│ └── marketplace.py # MarketplaceImportJob model
└── api/
├── __init__.py # Common imports
├── base.py # Base response models
├── auth.py # User auth models (register, login, response)
├── shop.py # Shop management models
├── product.py # Product CRUD models
├── stock.py # Stock operation models
├── marketplace.py # Marketplace import models
└── stats.py # Statistics response models
```
## File Contents Breakdown
### Database Models
**models/database/base.py:**
```python
from datetime import datetime
from sqlalchemy import Column, DateTime
from app.core.database import Base
class TimestampMixin:
"""Mixin to add created_at and updated_at timestamps to models"""
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
updated_at = Column(
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False
)
```
**models/database/user.py:**
- `User` model (lines 12-37 from your current file)
**models/database/shop.py:**
- `Shop` model (lines 40-75)
- `ShopProduct` model (lines 155-199)
**models/database/product.py:**
- `Product` model (lines 78-152)
**models/database/stock.py:**
- `Stock` model (lines 202-232)
**models/database/marketplace.py:**
- `MarketplaceImportJob` model (lines 235-284)
### API Models
**models/api/base.py:**
```python
from typing import List, TypeVar, Generic
from pydantic import BaseModel
T = TypeVar('T')
class ListResponse(BaseModel, Generic[T]):
"""Generic list response model"""
items: List[T]
total: int
skip: int
limit: int
class StatusResponse(BaseModel):
"""Generic status response"""
success: bool
message: str
```
**models/api/auth.py:**
- `UserRegister` (lines 12-34)
- `UserLogin` (lines 37-46)
- `UserResponse` (lines 49-61)
- `LoginResponse` (lines 64-69)
**models/api/shop.py:**
- `ShopCreate` (lines 72-103)
- `ShopUpdate` (lines 106-122)
- `ShopResponse` (lines 125-145)
- `ShopListResponse` (lines 148-153)
- `ShopProductCreate` (lines 247-270)
- `ShopProductResponse` (lines 273-293)
**models/api/product.py:**
- `ProductBase` (lines 156-193)
- `ProductCreate` (lines 196-206)
- `ProductUpdate` (lines 209-211)
- `ProductResponse` (lines 214-221)
- `ProductListResponse` (lines 408-413)
- `ProductDetailResponse` (lines 416-420)
**models/api/stock.py:**
- `StockBase` (lines 296-300)
- `StockCreate` (lines 303-305)
- `StockAdd` (lines 308-310)
- `StockUpdate` (lines 313-315)
- `StockResponse` (lines 318-327)
- `StockLocationResponse` (lines 330-333)
- `StockSummaryResponse` (lines 336-342)
**models/api/marketplace.py:**
- `MarketplaceImportRequest` (lines 345-381)
- `MarketplaceImportJobResponse` (lines 384-399)
**models/api/stats.py:**
- `StatsResponse` (lines 423-431)
- `MarketplaceStatsResponse` (lines 434-439)
## Migration Steps
### Step 1: Create the new structure
1. Create the new directories
2. Create `__init__.py` files
3. Move the base classes first
### Step 2: Database models migration
1. Extract models one by one, starting with `User`
2. Update imports in each file
3. Test database connections after each model
### Step 3: API models migration
1. Extract API models by domain
2. Update imports in route files
3. Test API endpoints after each model group
### Step 4: Update imports across the application
- Update all route files to use new import paths
- Update service files
- Update test files
## Benefits of This Structure
1. **Domain separation**: Related models are grouped together
2. **Easier maintenance**: Smaller files are easier to navigate and modify
3. **Reduced conflicts**: Multiple developers can work on different domains
4. **Better testability**: Can test model groups independently
5. **Clear dependencies**: Import relationships become more explicit
## Import Examples After Restructure
```python
# In route files
from models.database.user import User, Product, Stock
from models.api.auth import UserLogin, UserResponse
from models.api.product import ProductCreate, ProductListResponse
# Or specific imports
from models.database.product import Product
from models.api.product import ProductCreate, ProductResponse
```
## Consideration for Relationships
When splitting database models, be careful with SQLAlchemy relationships:
- Keep related models in the same file if they have tight coupling
- Use string references for relationships across files: `relationship("User")` instead of `relationship(User)`
- Consider lazy imports in `__init__.py` files to avoid circular imports
This restructure will make your codebase much more maintainable as it grows!

View File

@@ -1,161 +0,0 @@
# restructure_models.ps1 - Final working script using temp files
Write-Host "📄 Starting models restructure..." -ForegroundColor Cyan
# Create new directory structure for models
Write-Host "📁 Creating models directory structure..." -ForegroundColor Yellow
$modelDirectories = @(
"models\database",
"models\api"
)
foreach ($dir in $modelDirectories) {
if (!(Test-Path $dir)) {
New-Item -Path $dir -ItemType Directory -Force | Out-Null
Write-Host " Created: $dir" -ForegroundColor Green
} else {
Write-Host " Exists: $dir" -ForegroundColor Gray
}
}
# Backup original model files
Write-Host "💾 Backing up original model files..." -ForegroundColor Yellow
if (!(Test-Path "models\backup")) {
New-Item -Path "models\backup" -ItemType Directory -Force | Out-Null
}
$originalFiles = @("models\database_models.py", "models\api_models.py")
foreach ($file in $originalFiles) {
if (Test-Path $file) {
Copy-Item $file "models\backup\" -Force
Write-Host " Backed up: $(Split-Path $file -Leaf)" -ForegroundColor Gray
}
}
Write-Host "📄 Creating database model files..." -ForegroundColor Yellow
# Function to create files using temp file approach
function New-PythonFile {
param(
[string]$Path,
[string]$TempContent
)
$tempFile = [System.IO.Path]::GetTempFileName()
$TempContent | Out-File $tempFile -Encoding UTF8
Move-Item $tempFile $Path -Force
}
# Create models/database/__init__.py
Write-Host " Creating models\database\__init__.py..." -ForegroundColor Gray
$initContent = @"
# models/database/__init__.py
from .user import User
from .product import Product
from .shop import Shop, ShopProduct
from .stock import Stock
from .marketplace import MarketplaceImportJob
__all__ = [
"User",
"Product",
"Shop", "ShopProduct",
"Stock",
"MarketplaceImportJob",
]
"@
New-PythonFile -Path "models\database\__init__.py" -TempContent $initContent
# Create models/database/base.py
Write-Host " Creating models\database\base.py..." -ForegroundColor Gray
$baseContent = 'LS0gLS0tQkVHSU4gUFlUSE9OIENPREUtLS0tLQojIG1vZGVscy9kYXRhYmFzZS9iYXNlLnB5CmZyb20gZGF0ZXRpbWUgaW1wb3J0IGRhdGV0aW1lCmZyb20gc3FsYWxjaGVteSBpbXBvcnQgQ29sdW1uLCBEYXRlVGltZQpmcm9tIGFwcC5jb3JlLmRhdGFiYXNlIGltcG9ydCBCYXNlCgoKY2xhc3MgVGltZXN0YW1wTWl4aW46CiAgICAiIiJNaXhpbiB0byBhZGQgY3JlYXRlZF9hdCBhbmQgdXBkYXRlZF9hdCB0aW1lc3RhbXBzIHRvIG1vZGVscyIiIgogICAgY3JlYXRlZF9hdCA9IENvbHVtbihEYXRlVGltZSwgZGVmYXVsdD1kYXRldGltZS51dGNub3csIG51bGxhYmxlPUZhbHNlKQogICAgdXBkYXRlZF9hdCA9IENvbHVtbigKICAgICAgICBEYXRlVGltZSwgZGVmYXVsdD1kYXRldGltZS51dGNub3csIG9udXBkYXRlPWRhdGV0aW1lLnV0Y25vdywgbnVsbGFibGU9RmFsc2UKICAgICkKLS0tLS1FTkQgUFlUSE9OIENPREUtLS0tLQo='
$decodedBase = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($baseContent))
$decodedBase = $decodedBase.Replace('-----BEGIN PYTHON CODE-----', '').Replace('-----END PYTHON CODE-----', '').Trim()
$decodedBase | Out-File "models\database\base.py" -Encoding UTF8
# Create models/database/user.py
Write-Host " Creating models\database\user.py..." -ForegroundColor Gray
$userContent = 'LS0tLS1CRUdJTiBQWVRIT04gQ09ERS0tLS0tCiMgbW9kZWxzL2RhdGFiYXNlL3VzZXIucHkKZnJvbSBkYXRldGltZSBpbXBvcnQgZGF0ZXRpbWUKZnJvbSBzcWxhbGNoZW15IGltcG9ydCBCb29sZWFuLCBDb2x1bW4sIERhdGVUaW1lLCBJbnRlZ2VyLCBTdHJpbmcKZnJvbSBzcWxhbGNoZW15Lm9ybSBpbXBvcnQgcmVsYXRpb25zaGlwCmZyb20gYXBwLmNvcmUuZGF0YWJhc2UgaW1wb3J0IEJhc2UKCgpjbGFzcyBVc2VyKEJhc2UpOgogICAgX190YWJsZW5hbWVfXyA9ICJ1c2VycyIKCiAgICBpZCA9IENvbHVtbihJbnRlZ2VyLCBwcmltYXJ5X2tleT1UcnVlLCBpbmRleD1UcnVlKQogICAgZW1haWwgPSBDb2x1bW4oU3RyaW5nLCB1bmlxdWU9VHJ1ZSwgaW5kZXg9VHJ1ZSwgbnVsbGFibGU9RmFsc2UpCiAgICB1c2VybmFtZSA9IENvbHVtbihTdHJpbmcsIHVuaXF1ZT1UcnVlLCBpbmRleD1UcnVlLCBudWxsYWJsZT1GYWxzZSkKICAgIGhhc2hlZF9wYXNzd29yZCA9IENvbHVtbihTdHJpbmcsIG51bGxhYmxlPUZhbHNlKQogICAgcm9sZSA9IENvbHVtbihTdHJpbmcsIG51bGxhYmxlPUZhbHNlLCBkZWZhdWx0PSJ1c2VyIikgICMgdXNlciwgYWRtaW4sIHNob3Bfb3duZXIKICAgIGlzX2FjdGl2ZSA9IENvbHVtbihCb29sZWFuLCBkZWZhdWx0PVRydWUsIG51bGxhYmxlPUZhbHNlKQogICAgbGFzdF9sb2dpbiA9IENvbHVtbihEYXRlVGltZSwgbnVsbGFibGU9VHJ1ZSkKICAgIGNyZWF0ZWRfYXQgPSBDb2x1bW4oRGF0ZVRpbWUsIGRlZmF1bHQ9ZGF0ZXRpbWUudXRjbm93LCBudWxsYWJsZT1GYWxzZSkKICAgIHVwZGF0ZWRfYXQgPSBDb2x1bW4oCiAgICAgICAgRGF0ZVRpbWUsIGRlZmF1bHQ9ZGF0ZXRpbWUudXRjbm93LCBvbnVwZGF0ZT1kYXRldGltZS51dGNub3csIG51bGxhYmxlPUZhbHNlCiAgICApCgogICAgIyBSZWxhdGlvbnNoaXBzCiAgICBtYXJrZXRwbGFjZV9pbXBvcnRfam9icyA9IHJlbGF0aW9uc2hpcCgKICAgICAgICAiTWFya2V0cGxhY2VJbXBvcnRKb2IiLCBiYWNrX3BvcHVsYXRlcz0idXNlciIKICAgICkKICAgIG93bmVkX3Nob3BzID0gcmVsYXRpb25zaGlwKCJTaG9wIiwgYmFja19wb3B1bGF0ZXM9Im93bmVyIikKCiAgICBkZWYgX19yZXByX18oc2VsZik6CiAgICAgICAgcmV0dXJuIGYiPFVzZXIodXNlcm5hbWU9J3tzZWxmLnVzZXJuYW1lfScsIGVtYWlsPSd7c2VsZi5lbWFpbH0nLCByb2xlPSd7c2VsZi5yb2xlfScpPiIKLS0tLS1FTkQgUFlUSE9OIENPREUtLS0tLQo='
$decodedUser = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($userContent))
$decodedUser = $decodedUser.Replace('-----BEGIN PYTHON CODE-----', '').Replace('-----END PYTHON CODE-----', '').Trim()
$decodedUser | Out-File "models\database\user.py" -Encoding UTF8
# Create models/api/__init__.py
Write-Host " Creating models\api\__init__.py..." -ForegroundColor Gray
$apiInitContent = @"
# models/api/__init__.py
# Import statements will be added as you create the individual API model files
# Example:
# from .auth import UserRegister, UserLogin, UserResponse, LoginResponse
__all__ = [
# Add your API model imports here as you create them
]
"@
New-PythonFile -Path "models\api\__init__.py" -TempContent $apiInitContent
# Create models/api/base.py
Write-Host " Creating models\api\base.py..." -ForegroundColor Gray
$apiBaseContent = 'LS0tLS1CRUdJTiBQWVRIT04gQ09ERS0tLS0tCiMgbW9kZWxzL2FwaS9iYXNlLnB5CmZyb20gdHlwaW5nIGltcG9ydCBMaXN0LCBUeXBlVmFyLCBHZW5lcmljCmZyb20gcHlkYW50aWMgaW1wb3J0IEJhc2VNb2RlbAoKVCA9IFR5cGVWYXIoJ1QnKQoKY2xhc3MgTGlzdFJlc3BvbnNlKEJhc2VNb2RlbCwgR2VuZXJpY1tUXSk6CiAgICAiIiJHZW5lcmljIGxpc3QgcmVzcG9uc2UgbW9kZWwiIiIKICAgIGl0ZW1zOiBMaXN0W1RdCiAgICB0b3RhbDogaW50CiAgICBza2lwOiBpbnQKICAgIGxpbWl0OiBpbnQKCmNsYXNzIFN0YXR1c1Jlc3BvbnNlKEJhc2VNb2RlbCk6CiAgICAiIiJHZW5lcmljIHN0YXR1cyByZXNwb25zZSIiIgogICAgc3VjY2VzczogYm9vbAogICAgbWVzc2FnZTogc3RyCi0tLS0tRU5EIFBZVEhPTiBDT0RFLS0tLS0K'
$decodedApi = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($apiBaseContent))
$decodedApi = $decodedApi.Replace('-----BEGIN PYTHON CODE-----', '').Replace('-----END PYTHON CODE-----', '').Trim()
$decodedApi | Out-File "models\api\base.py" -Encoding UTF8
Write-Host "✅ Basic model structure created!" -ForegroundColor Green
Write-Host ""
Write-Host "🔍 Testing file creation..." -ForegroundColor Yellow
# Check if files were created
$createdFiles = @(
"models\database\__init__.py",
"models\database\base.py",
"models\database\user.py",
"models\api\__init__.py",
"models\api\base.py"
)
foreach ($file in $createdFiles) {
if (Test-Path $file) {
$size = (Get-Item $file).Length
Write-Host "$file ($size bytes)" -ForegroundColor Green
} else {
Write-Host "$file (missing)" -ForegroundColor Red
}
}
Write-Host ""
Write-Host "🧪 Testing Python imports..." -ForegroundColor Yellow
try {
$pythonTest = 'import sys; sys.path.append("."); from models.database.user import User; print("SUCCESS: Database models import working")'
$testResult = python -c $pythonTest 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host "✅ Python import test passed!" -ForegroundColor Green
} else {
Write-Host "⚠️ Python import test failed (may need dependencies)" -ForegroundColor Yellow
}
} catch {
Write-Host "⚠️ Python not available for testing" -ForegroundColor Yellow
}
Write-Host ""
Write-Host "📋 Next steps:" -ForegroundColor Cyan
Write-Host "1. Complete the remaining database models by copying from your original files:" -ForegroundColor White
Write-Host " - models\database\product.py" -ForegroundColor Gray
Write-Host " - models\database\shop.py" -ForegroundColor Gray
Write-Host " - models\database\stock.py" -ForegroundColor Gray
Write-Host " - models\database\marketplace.py" -ForegroundColor Gray
Write-Host ""
Write-Host "2. Extract API model classes from your api_models.py to separate files:" -ForegroundColor White
Write-Host " - models\api\auth.py" -ForegroundColor Gray
Write-Host " - models\api\product.py" -ForegroundColor Gray
Write-Host " - models\api\shop.py" -ForegroundColor Gray
Write-Host " - models\api\stock.py" -ForegroundColor Gray
Write-Host " - models\api\marketplace.py" -ForegroundColor Gray
Write-Host " - models\api\stats.py" -ForegroundColor Gray
Write-Host ""
Write-Host "3. Update imports throughout your application:" -ForegroundColor White
Write-Host " Old: from models.database.user import User" -ForegroundColor Gray
Write-Host " New: from models.database.user import User" -ForegroundColor Gray
Write-Host ""
Write-Host "✨ Foundation completed successfully!" -ForegroundColor Green
Write-Host "📚 Original files backed up in models\backup\" -ForegroundColor Green

View File

@@ -1,159 +0,0 @@
Yes, absolutely! As your application grows, splitting the models into separate files by domain/entity is a common and recommended practice. Here's how you could restructure your models:
## Recommended Structure:
```
models/
├── database/
│ ├── __init__.py # Import all models for easy access
│ ├── base.py # Base model class and common mixins
│ ├── user.py # User, UserProfile models
│ ├── auth.py # Authentication-related models
│ ├── product.py # Product, ProductVariant models
│ ├── stock.py # Stock, StockMovement models
│ ├── shop.py # Shop, ShopLocation models
│ ├── marketplace.py # Marketplace integration models
│ └── admin.py # Admin-specific models
└── api/
├── __init__.py # Common imports
├── base.py # Base Pydantic models
├── auth.py # Login, Token, User response models
├── product.py # Product request/response models
├── stock.py # Stock operation models
├── shop.py # Shop management models
├── marketplace.py # Marketplace import models
├── admin.py # Admin operation models
└── stats.py # Statistics response models
```
## Benefits of this approach:
1. **Maintainability**: Easier to find and modify specific model types
2. **Team collaboration**: Reduces merge conflicts when multiple developers work on different features
3. **Import clarity**: Clear imports like `from models.database.product import Product`
4. **Logical grouping**: Related models stay together
5. **Reduced file size**: Each file focuses on a specific domain
## Example implementation:
**models/database/__init__.py:**
```python
from .user import User, UserProfile
from .product import Product, ProductVariant
from .stock import Stock, StockMovement
from .shop import Shop, ShopLocation
# ... other imports
__all__ = [
"User", "UserProfile",
"Product", "ProductVariant",
"Stock", "StockMovement",
"Shop", "ShopLocation",
# ... other exports
]
```
**models/api/__init__.py:**
```python
from .auth import LoginRequest, TokenResponse, UserResponse
from .product import ProductCreate, ProductResponse, ProductUpdate
# ... other imports
__all__ = [
"LoginRequest", "TokenResponse", "UserResponse",
"ProductCreate", "ProductResponse", "ProductUpdate",
# ... other exports
]
```
This way, you can still import everything easily in your route files:
```python
from models.database import Product, Stock
from models.api import ProductCreate, ProductResponse
```
The split makes most sense when you have 5+ models per domain or when individual model files exceed ~200-300 lines.
Looking at your current `api_models.py` and `database_models.py`, they're definitely getting quite large and would benefit from being split up! Here's how I'd recommend restructuring them:Based on your current models, here are the key considerations for splitting them:
## Immediate Benefits You'll See:
1. **File Size**: Your current `api_models.py` is 439 lines and `database_models.py` is 284 lines - splitting will make them much more manageable
2. **Domain Clarity**: You have clear domains (auth, shop, product, stock, marketplace) that naturally separate
3. **Import Organization**: Instead of importing everything from two massive files, you'll have clear, purposeful imports
## Potential Challenges to Watch For:
1. **Circular Imports**: With SQLAlchemy relationships, you might need to use string references like `relationship("User")` instead of the class directly
2. **Shared Validators**: You have some common validation logic that might need to be moved to a base/utils module
3. **Import Updates**: You'll need to update all your route files, but this is a one-time cost
## Recommended Migration Order:
1. **Start with API models** - they're easier since they don't have complex relationships
2. **Begin with auth models** - they're the most independent
3. **Then do database models** - be careful with relationships
4. **Update imports gradually** - do it route by route to avoid breaking everything at once
Would you like me to create the actual split files for any specific domain (like auth or products) to get you started?
I've created a comprehensive PowerShell script that automatically generates the models restructure outlined in our discussion. This script:
## What the Script Creates:
**Database Models Structure:**
- `models/database/` with separate files for each domain
- `base.py` with TimestampMixin for common functionality
- `user.py`, `product.py`, `shop.py`, `stock.py`, `marketplace.py`
- Proper `__init__.py` with all imports configured
**API Models Structure:**
- `models/api/` directory structure
- `base.py` with generic response models
- `__init__.py` with comprehensive imports ready
**Key Features:**
- **Automatic backup** of your original files
- **Complete database models** extracted and properly organized
- **Import structure** ready with `__init__.py` files
- **Clear next steps** printed after completion
## Usage:
```powershell
# Navigate to your project root
cd your-project-directory
# Run the script
.\restructure_models.ps1
```
## What You'll Still Need to Do Manually:
The script creates the database models completely, but you'll need to extract the API model classes from your existing `api_models.py` into the new structure:
1. **Auth models**`models/api/auth.py`
2. **Product models**`models/api/product.py`
3. **Shop models**`models/api/shop.py`
4. **Stock models**`models/api/stock.py`
5. **Marketplace models**`models/api/marketplace.py`
6. **Stats models**`models/api/stats.py`
## Import Updates Needed:
After running the script, update imports throughout your codebase:
```python
# Old imports
from models.database.user import User, Product, Shop
from models.api import UserRegister, ProductResponse
# New imports
from models.database.user import User, Product, Shop
from models.api import UserRegister, ProductResponse
```
The script will complete the database models restructure automatically and provide you with a clear roadmap for finishing the API models migration.

View File

@@ -1,523 +0,0 @@
# FastAPI Service Layer Architecture
This document describes the service layer architecture implemented in our FastAPI application, providing clear separation of concerns between HTTP handling (routers) and business logic (services).
## Table of Contents
- [Overview](#overview)
- [Architecture Pattern](#architecture-pattern)
- [Service Layer Components](#service-layer-components)
- [Benefits](#benefits)
- [Implementation Guide](#implementation-guide)
- [Testing Strategy](#testing-strategy)
- [Usage Examples](#usage-examples)
- [Best Practices](#best-practices)
- [Migration Guide](#migration-guide)
## Overview
Our FastAPI application follows a **Service Layer Architecture** pattern that separates HTTP concerns from business logic. This architecture provides better maintainability, testability, and code reusability.
### Before vs After
**Before (Router handling everything):**
```python
@router.post("/products")
def create_product(product: ProductCreate, db: Session = Depends(get_db)):
# Validation logic
if product.gtin:
normalized_gtin = normalize_gtin(product.gtin)
if not normalized_gtin:
raise HTTPException(status_code=400, detail="Invalid GTIN")
# Business logic
db_product = Product(**product.model_dump())
db.add(db_product)
db.commit()
# Return response
return db_product
```
**After (Service layer separation):**
```python
# Router (HTTP concerns only)
@router.post("/products")
def create_product(product: ProductCreate, db: Session = Depends(get_db)):
try:
return product_service.create_product(db, product)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
# Service (Business logic)
class ProductService:
def create_product(self, db: Session, product_data: ProductCreate) -> Product:
# All validation and business logic here
# Returns domain objects, raises domain exceptions
```
## Architecture Pattern
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ HTTP Client │ │ FastAPI App │ │ Database │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
│ HTTP Request │ │
├──────────────────────▶ │ │
│ │ │
│ ┌─────────────────┐ │
│ │ Router │ │
│ │ (HTTP Layer) │ │
│ └─────────────────┘ │
│ │ │
│ │ Delegates to │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Service │ │
│ │ (Business Layer)│ │
│ └─────────────────┘ │
│ │ │
│ │ Database Operations │
│ ├──────────────────────▶│
│ │ │
│ HTTP Response │ │
◀──────────────────────── │ │
```
## Service Layer Components
### 1. ProductService
**File:** `product_service.py`
**Responsibilities:**
- Product CRUD operations
- GTIN validation and normalization
- Price processing
- Stock information retrieval
- CSV export generation
**Key Methods:**
```python
class ProductService:
def create_product(self, db: Session, product_data: ProductCreate) -> Product
def get_product_by_id(self, db: Session, product_id: str) -> Optional[Product]
def get_products_with_filters(self, db: Session, **filters) -> tuple[List[Product], int]
def update_product(self, db: Session, product_id: str, product_update: ProductUpdate) -> Product
def delete_product(self, db: Session, product_id: str) -> bool
def get_stock_info(self, db: Session, gtin: str) -> Optional[StockSummaryResponse]
def generate_csv_export(self, db: Session, **filters) -> Generator[str, None, None]
```
### 2. StockService
**File:** `stock_service.py`
**Responsibilities:**
- Stock quantity management
- GTIN normalization
- Stock location tracking
- Stock operations (set, add, remove)
**Key Methods:**
```python
class StockService:
def set_stock(self, db: Session, stock_data: StockCreate) -> Stock
def add_stock(self, db: Session, stock_data: StockAdd) -> Stock
def remove_stock(self, db: Session, stock_data: StockAdd) -> Stock
def get_stock_by_gtin(self, db: Session, gtin: str) -> StockSummaryResponse
def get_total_stock(self, db: Session, gtin: str) -> dict
def get_all_stock(self, db: Session, **filters) -> List[Stock]
def normalize_gtin(self, gtin_value) -> Optional[str]
```
### 3. MarketplaceService
**File:** `marketplace_service.py`
**Responsibilities:**
- Marketplace import job management
- Shop access validation
- User permission checking
- Job lifecycle management
- Import statistics
**Key Methods:**
```python
class MarketplaceService:
def validate_shop_access(self, db: Session, shop_code: str, user: User) -> Shop
def create_import_job(self, db: Session, request: MarketplaceImportRequest, user: User) -> MarketplaceImportJob
def get_import_job_by_id(self, db: Session, job_id: int, user: User) -> MarketplaceImportJob
def get_import_jobs(self, db: Session, user: User, **filters) -> List[MarketplaceImportJob]
def update_job_status(self, db: Session, job_id: int, status: str, **kwargs) -> MarketplaceImportJob
def cancel_import_job(self, db: Session, job_id: int, user: User) -> MarketplaceImportJob
def delete_import_job(self, db: Session, job_id: int, user: User) -> bool
```
## Benefits
### 1. **Separation of Concerns**
- **Routers**: Handle HTTP requests/responses, authentication, validation of HTTP-specific concerns
- **Services**: Handle business logic, data validation, domain rules
- **Models**: Define data structures and database relationships
### 2. **Better Testability**
- **Unit Testing**: Test business logic independently of HTTP layer
- **Integration Testing**: Test HTTP endpoints separately from business logic
- **Mocking**: Easy to mock services for router testing
### 3. **Code Reusability**
- Services can be used from multiple routers
- Background tasks can use services directly
- CLI commands can leverage the same business logic
### 4. **Maintainability**
- Business logic changes only need to be made in one place
- Clear boundaries between different layers
- Easier to understand and modify code
### 5. **Error Handling**
- Domain-specific exceptions in services
- Consistent HTTP error mapping in routers
- Better error messages and logging
## Implementation Guide
### Step 1: Create Service Class
```python
# product_service.py
class ProductService:
def __init__(self):
self.gtin_processor = GTINProcessor()
self.price_processor = PriceProcessor()
def create_product(self, db: Session, product_data: ProductCreate) -> Product:
# Business logic here
# Raise ValueError for business logic errors
# Return domain objects
pass
# Create singleton instance
product_service = ProductService()
```
### Step 2: Refactor Router
```python
# product.py
from product_service import product_service
@router.post("/products", response_model=ProductResponse)
def create_product(
product: ProductCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
try:
result = product_service.create_product(db, product)
return result
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
logger.error(f"Error creating product: {str(e)}")
raise HTTPException(status_code=500, detail="Internal server error")
```
### Step 3: Error Handling Pattern
**Service Layer Exceptions:**
- `ValueError`: Business logic validation errors → HTTP 400
- `PermissionError`: Access control errors → HTTP 403
- Custom exceptions for specific domain errors
**Router Error Translation:**
```python
try:
result = service.method(db, data)
return result
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except PermissionError as e:
raise HTTPException(status_code=403, detail=str(e))
except Exception as e:
logger.error(f"Unexpected error: {str(e)}")
raise HTTPException(status_code=500, detail="Internal server error")
```
## Testing Strategy
### Service Layer Tests
```python
# test_product_service.py
class TestProductService:
def setup_method(self):
self.service = ProductService()
def test_create_product_success(self, db):
product_data = ProductCreate(product_id="TEST001", title="Test Product")
result = self.service.create_product(db, product_data)
assert result.product_id == "TEST001"
assert result.title == "Test Product"
def test_create_product_invalid_gtin(self, db):
product_data = ProductCreate(product_id="TEST001", gtin="invalid")
with pytest.raises(ValueError, match="Invalid GTIN format"):
self.service.create_product(db, product_data)
```
### Router Tests
```python
# test_products_api.py
def test_create_product_endpoint(self, client, auth_headers):
product_data = {"product_id": "TEST001", "title": "Test Product"}
response = client.post("/api/v1/product", headers=auth_headers, json=product_data)
assert response.status_code == 200
assert response.json()["product_id"] == "TEST001"
def test_create_product_validation_error(self, client, auth_headers):
product_data = {"product_id": "TEST001", "gtin": "invalid"}
response = client.post("/api/v1/product", headers=auth_headers, json=product_data)
assert response.status_code == 400
assert "Invalid GTIN format" in response.json()["detail"]
```
### Test Organization
```
tests/
├── test_services.py # Service layer unit tests
├── test_product_service.py # ProductService specific tests
├── test_stock_service.py # StockService specific tests
├── test_marketplace_service.py # MarketplaceService specific tests
├── test_products.py # Product API integration tests
├── test_stock.py # Stock API integration tests
└── test_marketplace.py # Marketplace API integration tests
```
## Usage Examples
### Using Services in Background Tasks
```python
# background_tasks.py
from product_service import product_service
from stock_service import stock_service
async def process_marketplace_import(job_id: int, csv_data: str):
try:
for row in csv_data:
# Create product using service
product = product_service.create_product(db, product_data)
# Update stock using service
if product.gtin:
stock_service.set_stock(db, stock_data)
except Exception as e:
marketplace_service.update_job_status(db, job_id, "failed", error_message=str(e))
```
### Using Services in CLI Commands
```python
# cli_commands.py
from product_service import product_service
def bulk_update_prices(csv_file: str):
"""CLI command to bulk update product prices"""
for product_id, new_price in read_csv(csv_file):
try:
product_service.update_product(
db, product_id,
ProductUpdate(price=new_price)
)
print(f"Updated {product_id}")
except ValueError as e:
print(f"Error updating {product_id}: {e}")
```
### Service Composition
```python
# order_service.py (hypothetical)
from product_service import product_service
from stock_service import stock_service
class OrderService:
def create_order(self, db: Session, order_data: OrderCreate) -> Order:
for item in order_data.items:
# Check product exists
product = product_service.get_product_by_id(db, item.product_id)
if not product:
raise ValueError(f"Product {item.product_id} not found")
# Check stock availability
stock = stock_service.get_total_stock(db, product.gtin)
if stock["total_quantity"] < item.quantity:
raise ValueError(f"Insufficient stock for {item.product_id}")
# Reserve stock
stock_service.remove_stock(db, StockAdd(
gtin=product.gtin,
location="RESERVED",
quantity=item.quantity
))
```
## Best Practices
### 1. Service Design Principles
- **Single Responsibility**: Each service handles one domain
- **Dependency Injection**: Services should not create their own dependencies
- **Pure Functions**: Methods should be predictable and side-effect free when possible
- **Domain Exceptions**: Use meaningful exception types
### 2. Error Handling
```python
# Good: Specific domain exceptions
class ProductService:
def create_product(self, db: Session, product_data: ProductCreate) -> Product:
if self.product_exists(db, product_data.product_id):
raise ValueError(f"Product {product_data.product_id} already exists")
if product_data.gtin and not self.is_valid_gtin(product_data.gtin):
raise ValueError("Invalid GTIN format")
# Business logic...
# Bad: Generic exceptions
def create_product(product_data):
if product_exists(product_data.product_id):
raise Exception("Error occurred") # Too generic
```
### 3. Testing Guidelines
- **Test business logic in service tests**
- **Test HTTP behavior in router tests**
- **Use fixtures for common test data**
- **Mock external dependencies**
### 4. Documentation
- Document service methods with docstrings
- Include parameter types and return types
- Document exceptions that can be raised
- Provide usage examples
```python
def create_product(self, db: Session, product_data: ProductCreate) -> Product:
"""Create a new product with validation.
Args:
db: Database session
product_data: Product creation data
Returns:
Created Product instance
Raises:
ValueError: If product_id already exists or GTIN is invalid
Example:
>>> service = ProductService()
>>> product = service.create_product(db, ProductCreate(
... product_id="ABC123",
... title="Test Product",
... gtin="1234567890123"
... ))
"""
```
## Migration Guide
### Migrating Existing Routers
1. **Identify Business Logic**: Look for code that validates data, processes business rules, or manipulates domain objects
2. **Create Service Class**: Extract business logic into service methods
3. **Update Router**: Replace business logic with service calls and add error handling
4. **Add Tests**: Create comprehensive tests for the service layer
5. **Verify Compatibility**: Ensure API behavior remains the same
### Example Migration
**Before:**
```python
@router.post("/products")
def create_product(product: ProductCreate, db: Session = Depends(get_db)):
# Check if product exists
existing = db.query(Product).filter(Product.product_id == product.product_id).first()
if existing:
raise HTTPException(status_code=400, detail="Product already exists")
# Validate GTIN
if product.gtin:
normalized_gtin = normalize_gtin(product.gtin)
if not normalized_gtin:
raise HTTPException(status_code=400, detail="Invalid GTIN")
product.gtin = normalized_gtin
# Create product
db_product = Product(**product.model_dump())
db.add(db_product)
db.commit()
db.refresh(db_product)
return db_product
```
**After:**
```python
# Service
class ProductService:
def create_product(self, db: Session, product_data: ProductCreate) -> Product:
# Check if product exists
if self.product_exists(db, product_data.product_id):
raise ValueError("Product already exists")
# Validate GTIN
if product_data.gtin:
normalized_gtin = self.gtin_processor.normalize(product_data.gtin)
if not normalized_gtin:
raise ValueError("Invalid GTIN")
product_data.gtin = normalized_gtin
# Create product
db_product = Product(**product_data.model_dump())
db.add(db_product)
db.commit()
db.refresh(db_product)
return db_product
# Router
@router.post("/products")
def create_product(product: ProductCreate, db: Session = Depends(get_db)):
try:
return product_service.create_product(db, product)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
logger.error(f"Error creating product: {str(e)}")
raise HTTPException(status_code=500, detail="Internal server error")
```
## Conclusion
The service layer architecture provides a robust foundation for scalable FastAPI applications. By separating HTTP concerns from business logic, we achieve better maintainability, testability, and code reuse. This pattern scales well as applications grow and makes it easier to add new features while maintaining existing functionality.
For questions or contributions to this architecture, please refer to the team documentation or create an issue in the project repository.

View File

@@ -1,218 +0,0 @@
# Your Specific Test Migration Plan
## New Directory Structure
```
tests/
├── conftest.py # Your current global fixtures (keep most of it)
├── pytest.ini # New - test configuration
├── fixtures/ # Extract fixtures from conftest.py
│ ├── __init__.py
│ ├── auth_fixtures.py # User, admin fixtures
│ ├── product_fixtures.py # Product-related fixtures
│ ├── shop_fixtures.py # Shop-related fixtures
│ └── database_fixtures.py # DB setup fixtures
├── unit/ # Fast, isolated tests
│ ├── __init__.py
│ ├── conftest.py # Unit-specific fixtures
│ ├── models/
│ │ ├── __init__.py
│ │ └── test_database_models.py # From test_database.py
│ ├── utils/
│ │ ├── __init__.py
│ │ └── test_data_processing.py # From test_utils.py
│ └── services/
│ ├── __init__.py
│ └── test_admin_service.py # Keep as-is, move here
├── integration/ # Multi-component tests
│ ├── __init__.py
│ ├── conftest.py
│ ├── api/
│ │ ├── __init__.py
│ │ ├── conftest.py # API client fixtures
│ │ └── v1/
│ │ ├── __init__.py
│ │ └── test_admin_endpoints.py # From test_admin.py
│ └── security/
│ ├── __init__.py
│ ├── test_authentication.py # Split from test_security.py
│ ├── test_authorization.py # Split from test_security.py
│ └── test_input_validation.py # Split from test_security.py
├── system/ # Full system tests
│ ├── __init__.py
│ ├── conftest.py
│ └── test_error_handling.py # From test_error_handling.py
└── test_data/ # Test data files
└── csv/
└── sample_products.csv
```
## Specific File Mappings
### 1. Global Fixtures (Keep in main conftest.py)
**tests/conftest.py** - Keep these fixtures:
- `engine`, `testing_session_local`, `db`
- `client`
- `cleanup`
### 2. Extract to Fixture Files
**tests/fixtures/auth_fixtures.py:**
```python
# Move these from conftest.py:
- auth_manager
- test_user
- test_admin
- auth_headers
- admin_headers
- other_user
```
**tests/fixtures/product_fixtures.py:**
```python
# Move these from conftest.py:
- test_product
- unique_product
- multiple_products
- product_factory
```
**tests/fixtures/shop_fixtures.py:**
```python
# Move these from conftest.py:
- test_shop
- unique_shop
- inactive_shop
- verified_shop
- shop_product
- shop_factory
```
### 3. Unit Tests
**tests/unit/models/test_database_models.py:**
Move content from `test_database.py`:
- `TestDatabaseModels.test_user_model`
- `TestDatabaseModels.test_product_model`
- `TestDatabaseModels.test_stock_model`
- `TestDatabaseModels.test_shop_model_with_owner`
- `TestDatabaseModels.test_database_constraints`
**tests/unit/utils/test_data_processing.py:**
Move content from `test_utils.py`:
- `TestGTINProcessor` (entire class)
- `TestPriceProcessor` (entire class)
**tests/unit/services/test_admin_service.py:**
Keep `test_admin_service.py` exactly as-is, just move to this location.
### 4. Integration Tests
**tests/integration/api/v1/test_admin_endpoints.py:**
Move content from `test_admin.py`:
- `TestAdminAPI` (entire class) - all your admin endpoint tests
**tests/integration/security/test_authentication.py:**
Move from `test_security.py`:
```python
class TestAuthentication:
def test_protected_endpoint_without_auth(self, client):
# From test_security.py
def test_protected_endpoint_with_invalid_token(self, client):
# From test_security.py
```
**tests/integration/security/test_authorization.py:**
Move from `test_security.py`:
```python
class TestAuthorization:
def test_admin_endpoint_requires_admin_role(self, client, auth_headers):
# From test_security.py
```
**tests/integration/security/test_input_validation.py:**
Move from `test_security.py`:
```python
class TestInputValidation:
def test_sql_injection_prevention(self, client, auth_headers):
# From test_security.py
# def test_input_validation(self, client, auth_headers):
# # Your commented XSS test
```
### 5. System Tests
**tests/system/test_error_handling.py:**
Move `test_error_handling.py` as-is to this location.
## Migration Steps
### Step 1: Create Structure
```bash
mkdir -p tests/{fixtures,unit/{models,utils,services},integration/{api/v1,security},system,test_data}
touch tests/{fixtures,unit,integration,system}/__init__.py
touch tests/unit/{models,utils,services}/__init__.py
touch tests/integration/{api,security}/__init__.py
touch tests/integration/api/v1/__init__.py
```
### Step 2: Create pytest.ini
```ini
[tool:pytest]
testpaths = tests
python_files = test_*.py
addopts = -v --tb=short
markers =
unit: Unit tests - fast, isolated
integration: Integration tests - multiple components
system: System tests - full application
slow: Slow running tests
```
### Step 3: Extract Fixtures
Create fixture files and move relevant fixtures from your current `conftest.py`.
### Step 4: Move Test Files
Move each test file to its new location and update imports.
### Step 5: Update Imports
After moving files, update imports like:
```python
# Old import in test files
# No explicit imports needed since fixtures were in conftest.py
# New imports in test files
from tests.fixtures.auth_fixtures import test_user, auth_headers
from tests.fixtures.product_fixtures import test_product
```
## Running Tests by Category
```bash
# Fast unit tests during development
pytest tests/unit -m unit
# Integration tests before commit
pytest tests/integration -m integration
# Full test suite
pytest
# Specific domain tests
pytest tests/unit/services/ tests/integration/api/v1/test_admin_endpoints.py
# Your current debug tests (move to integration/security)
pytest tests/integration/security/ -v -s
```
## Benefits for Your Specific Tests
1. **Your admin tests** get separated into service logic (unit) vs API endpoints (integration)
2. **Your security tests** get properly categorized by concern
3. **Your database tests** become proper model unit tests
4. **Your utility tests** become isolated unit tests
5. **Your error handling** becomes system-level testing
This structure will make your test suite much more maintainable and allow for faster development cycles!

View File

@@ -1,262 +0,0 @@
# Test Structure Migration Guide
This document outlines the complete restructuring of the FastAPI application test suite from a single-folder approach to a comprehensive, scalable test organization.
## Overview
The test suite has been reorganized from:
```
tests/
├── conftest.py
├── test_admin.py
├── test_admin_service.py
├── test_database.py
├── test_error_handling.py
├── test_pagination.py
├── test_performance.py
├── test_security.py
├── test_utils.py
└── pytest.ini
```
To a structured, domain-organized approach that scales with application growth and provides better development workflow support.
## New Structure
```
tests/
├── conftest.py # Core test configuration and database fixtures
├── pytest.ini # Enhanced pytest configuration
├── fixtures/ # Shared test fixtures organized by domain
│ ├── __init__.py
│ ├── auth_fixtures.py # Authentication: users, tokens, headers
│ ├── product_fixtures.py # Products: test products, factories
│ ├── shop_fixtures.py # Shops: shops, stock, shop-products
│ └── marketplace_fixtures.py # Marketplace: import jobs
├── unit/ # Fast, isolated component tests
│ ├── __init__.py
│ ├── conftest.py # Unit test specific fixtures
│ ├── models/
│ │ ├── __init__.py
│ │ └── test_database_models.py # Database model tests
│ ├── utils/
│ │ ├── __init__.py
│ │ └── test_data_processing.py # Utility function tests
│ └── services/
│ ├── __init__.py
│ └── test_admin_service.py # Business logic tests
├── integration/ # Multi-component interaction tests
│ ├── __init__.py
│ ├── conftest.py # Integration test fixtures
│ ├── api/
│ │ ├── __init__.py
│ │ ├── conftest.py # API client fixtures
│ │ └── v1/
│ │ ├── __init__.py
│ │ ├── test_admin_endpoints.py # Admin API endpoint tests
│ │ └── test_pagination.py # Pagination functionality tests
│ └── security/
│ ├── __init__.py
│ ├── test_authentication.py # Authentication mechanism tests
│ ├── test_authorization.py # Permission and role tests
│ └── test_input_validation.py # Input security and validation tests
├── performance/ # Performance and load tests
│ ├── __init__.py
│ ├── conftest.py # Performance test fixtures
│ └── test_api_performance.py # API performance benchmarks
├── system/ # End-to-end system behavior tests
│ ├── __init__.py
│ ├── conftest.py # System test fixtures
│ └── test_error_handling.py # Application error handling tests
└── test_data/ # Test data files
└── csv/
└── sample_products.csv # Sample CSV data for testing
```
## Migration Changes Made
### 1. Fixture Organization
**Problem Solved:** The original `conftest.py` contained 370+ lines mixing different concerns.
**Solution:** Extracted domain-specific fixtures into separate modules:
- **auth_fixtures.py**: User authentication, tokens, and headers
- **product_fixtures.py**: Product creation, factories, and bulk data
- **shop_fixtures.py**: Shop management, stock, and shop-product relationships
- **marketplace_fixtures.py**: Import job fixtures and helpers
### 2. Test Categorization
**Problem Solved:** All tests ran together, making development cycles slow.
**Solution:** Organized tests by execution speed and scope:
- **Unit Tests**: Fast (< 100ms), isolated, no external dependencies
- **Integration Tests**: Medium speed, multiple components, database required
- **Performance Tests**: Slow, large datasets, timing-sensitive
- **System Tests**: Full application behavior, error scenarios
### 3. Enhanced pytest Configuration
**Previous:** Basic configuration with limited markers.
**Current:** Comprehensive configuration including:
```ini
[tool:pytest]
addopts =
-v --tb=short --strict-markers --strict-config
--color=yes --durations=10 --showlocals -ra
--cov=app --cov=models --cov=utils --cov=middleware
--cov-report=term-missing --cov-report=html:htmlcov
--cov-fail-under=80
markers =
unit: Unit tests - fast, isolated components
integration: Integration tests - multiple components
system: System tests - full application behavior
performance: Performance and load tests
slow: Slow running tests
# Domain-specific markers
auth: Authentication and authorization tests
products: Product management functionality
admin: Admin functionality and permissions
# ... additional markers
```
## Usage Examples
### Development Workflow
```bash
# Fast feedback during development (unit tests only)
pytest -m unit
# Before committing (unit + integration)
pytest -m "unit or integration"
# Full test suite (CI/CD)
pytest
# Skip slow tests during development
pytest -m "not slow"
```
### Domain-Specific Testing
```bash
# Test specific functionality
pytest -m auth # Authentication tests
pytest -m products # Product-related tests
pytest -m admin # Admin functionality
# Test specific layers
pytest tests/unit/ # All unit tests
pytest tests/integration/api/ # API integration tests
pytest tests/performance/ # Performance tests only
```
### Coverage and Reporting
```bash
# Generate coverage report
pytest --cov-report=html
# Find slowest tests
pytest --durations=0
# Detailed failure information
pytest -vvv --tb=long
```
## Key Improvements
### 1. Scalability
- **Modular fixture organization** allows teams to work on different domains without conflicts
- **Clear separation of concerns** makes it easy to add new test categories
- **Factory patterns** provide flexible test data generation
### 2. Development Speed
- **Fast unit tests** provide immediate feedback (typically runs in < 10 seconds)
- **Selective test execution** allows developers to run only relevant tests
- **Parallel execution support** ready (uncomment `addopts = -n auto` in pytest.ini)
### 3. Maintainability
- **Domain organization** makes it easy to locate and update tests
- **Consistent fixture patterns** reduce duplication
- **Clear naming conventions** improve code readability
### 4. CI/CD Pipeline Optimization
- **Staged test execution**: Run fast tests first, fail fast on basic issues
- **Performance monitoring**: Track test execution times and performance regressions
- **Coverage tracking**: Maintain code coverage standards
## Migration Process
### Automated Setup
1. Run the migration script:
```bash
bash migrate_tests.sh
```
### Manual Steps
1. **Copy fixture files** to `tests/fixtures/`
2. **Update main conftest.py** with the new version
3. **Move test files** to their new locations:
- `test_database.py``tests/unit/models/test_database_models.py`
- `test_utils.py``tests/unit/utils/test_data_processing.py`
- `test_admin_service.py``tests/unit/services/`
- `test_admin.py``tests/integration/api/v1/test_admin_endpoints.py`
- Split `test_security.py` into `tests/integration/security/` files
- `test_pagination.py``tests/integration/api/v1/`
- `test_performance.py``tests/performance/test_api_performance.py`
- `test_error_handling.py``tests/system/`
4. **Update imports** in moved files
5. **Add pytest markers** to test classes
6. **Test incrementally**:
```bash
pytest tests/unit -v
pytest tests/integration -v
pytest -m unit
```
## Benefits Realized
### For Developers
- **Faster feedback loops**: Unit tests complete in seconds
- **Focused testing**: Run only tests relevant to current work
- **Better debugging**: Clear test categorization helps identify issues quickly
### For Teams
- **Reduced merge conflicts**: Domain separation allows parallel development
- **Clear ownership**: Teams can own test domains matching their code ownership
- **Consistent patterns**: Standardized fixture and test organization
### For CI/CD
- **Optimized pipeline**: Fast tests run first, expensive tests only when needed
- **Performance monitoring**: Track performance regressions over time
- **Coverage enforcement**: Maintain quality standards automatically
## Troubleshooting
### Import Issues
If you encounter import errors after migration:
1. Ensure all `__init__.py` files are created
2. Check that `pytest_plugins` in main `conftest.py` points to correct fixture modules
3. Verify fixture dependencies (e.g., `test_shop` depends on `test_user`)
### Fixture Not Found
If pytest can't find fixtures:
1. Check that fixture modules are listed in `pytest_plugins`
2. Ensure fixture dependencies are imported properly
3. Verify fixture scope (session vs function) matches usage
### Performance Issues
If tests are running slowly:
1. Check that unit tests don't have database dependencies
2. Consider using `pytest-xdist` for parallel execution
3. Review slow tests with `pytest --durations=10`
## Future Enhancements
This structure supports future additions:
- **E2E tests**: Add `tests/e2e/` for complete user journey testing
- **Contract tests**: Add API contract testing with tools like Pact
- **Load tests**: Expand performance testing with tools like Locust
- **Visual tests**: Add screenshot testing for frontend components
- **Mutation tests**: Add mutation testing to verify test quality
The restructured test suite provides a solid foundation for maintaining high code quality as the application scales.

View File

@@ -46,7 +46,8 @@ clean:
# Install test dependencies
install-test-deps:
pip install -r tests/requirements_test.txtvalidate_csv_headers(valid_df) == True
pip install -r tests/requirements_test.txt
validate_csv_headers(valid_df) == True
# Invalid headers (missing required fields)
invalid_df = pd.DataFrame({

View File

@@ -1,352 +0,0 @@
# Tests Folder Restructure Plan
## Current vs Recommended Structure
### Before (Single Folder)
```
tests/
├── test_auth.py
├── test_products.py
├── test_stock.py
├── test_shops.py
├── test_marketplace.py
├── test_admin.py
├── test_stats.py
├── test_database.py
├── test_utils.py
├── conftest.py
└── ...more files
```
### After (Organized Structure)
```
tests/
├── conftest.py # Global test configuration and fixtures
├── pytest.ini # Pytest configuration
├── __init__.py
├── fixtures/ # Shared test fixtures
│ ├── __init__.py
│ ├── auth_fixtures.py # Auth-related fixtures
│ ├── product_fixtures.py # Product fixtures
│ ├── shop_fixtures.py # Shop fixtures
│ └── database_fixtures.py # Database setup fixtures
├── unit/ # Unit tests (isolated, fast)
│ ├── __init__.py
│ ├── conftest.py # Unit test specific fixtures
│ ├── models/ # Test database and API models
│ │ ├── __init__.py
│ │ ├── test_user_model.py
│ │ ├── test_product_model.py
│ │ ├── test_shop_model.py
│ │ └── test_stock_model.py
│ ├── utils/ # Test utility functions
│ │ ├── __init__.py
│ │ ├── test_data_processing.py
│ │ ├── test_csv_processor.py
│ │ └── test_database_utils.py
│ ├── services/ # Test business logic
│ │ ├── __init__.py
│ │ ├── test_auth_service.py
│ │ ├── test_product_service.py
│ │ └── test_marketplace_service.py
│ └── middleware/ # Test middleware components
│ ├── __init__.py
│ ├── test_auth_middleware.py
│ ├── test_rate_limiter.py
│ └── test_error_handler.py
├── integration/ # Integration tests (multiple components)
│ ├── __init__.py
│ ├── conftest.py # Integration test fixtures
│ ├── api/ # API endpoint tests
│ │ ├── __init__.py
│ │ ├── conftest.py # API test fixtures (test client, etc.)
│ │ ├── v1/
│ │ │ ├── __init__.py
│ │ │ ├── test_auth_endpoints.py
│ │ │ ├── test_product_endpoints.py
│ │ │ ├── test_shop_endpoints.py
│ │ │ ├── test_stock_endpoints.py
│ │ │ ├── test_marketplace_endpoints.py
│ │ │ ├── test_admin_endpoints.py
│ │ │ └── test_stats_endpoints.py
│ │ └── test_api_main.py # Test API router setup
│ ├── database/ # Database integration tests
│ │ ├── __init__.py
│ │ ├── test_crud_operations.py
│ │ ├── test_relationships.py
│ │ └── test_migrations.py
│ └── workflows/ # End-to-end workflow tests
│ ├── __init__.py
│ ├── test_product_import_workflow.py
│ ├── test_shop_setup_workflow.py
│ └── test_stock_management_workflow.py
├── e2e/ # End-to-end tests (full application)
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_user_registration_flow.py
│ ├── test_marketplace_import_flow.py
│ └── test_complete_shop_setup.py
├── performance/ # Performance and load tests
│ ├── __init__.py
│ ├── test_api_performance.py
│ ├── test_database_performance.py
│ └── test_import_performance.py
└── test_data/ # Test data files
├── csv/
│ ├── valid_products.csv
│ ├── invalid_products.csv
│ └── large_dataset.csv
├── json/
│ ├── sample_product.json
│ └── marketplace_response.json
└── fixtures/
├── test_users.json
└── test_products.json
```
## File Organization Principles
### 1. Test Types Separation
- **Unit Tests**: Fast, isolated tests for individual functions/classes
- **Integration Tests**: Tests that involve multiple components working together
- **E2E Tests**: Full application flow tests
- **Performance Tests**: Load and performance testing
### 2. Fixture Organization
```python
# tests/fixtures/auth_fixtures.py
import pytest
from models.database.user import User
from utils.auth import create_access_token
@pytest.fixture
def test_user_data():
return {
"email": "test@example.com",
"username": "testuser",
"password": "testpass123"
}
@pytest.fixture
def authenticated_user(db_session, test_user_data):
user = User(**test_user_data)
db_session.add(user)
db_session.commit()
return user
@pytest.fixture
def auth_headers(authenticated_user):
token = create_access_token(data={"sub": authenticated_user.username})
return {"Authorization": f"Bearer {token}"}
```
### 3. Conftest.py Structure
```python
# tests/conftest.py (Global fixtures)
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from main import app
from app.core.database import get_db, Base
# Database fixtures
@pytest.fixture(scope="session")
def test_engine():
engine = create_engine("sqlite:///test.db")
Base.metadata.create_all(bind=engine)
yield engine
Base.metadata.drop_all(bind=engine)
@pytest.fixture
def db_session(test_engine):
TestingSessionLocal = sessionmaker(bind=test_engine)
session = TestingSessionLocal()
yield session
session.close()
@pytest.fixture
def client(db_session):
def override_get_db():
yield db_session
app.dependency_overrides[get_db] = override_get_db
yield TestClient(app)
app.dependency_overrides.clear()
```
```python
# tests/integration/api/conftest.py (API-specific fixtures)
import pytest
@pytest.fixture
def api_client(client):
"""Pre-configured API client for integration tests"""
return client
@pytest.fixture
def admin_client(client, admin_auth_headers):
"""API client with admin authentication"""
client.headers.update(admin_auth_headers)
return client
```
## Test Naming Conventions
### File Naming
- `test_*.py` for all test files
- Mirror your app structure: `test_product_endpoints.py` for `api/v1/products.py`
- Use descriptive names: `test_marketplace_import_workflow.py`
### Test Function Naming
```python
# Good test naming patterns
def test_create_product_with_valid_data_returns_201():
pass
def test_create_product_without_title_returns_422():
pass
def test_get_product_by_id_returns_product_data():
pass
def test_get_nonexistent_product_returns_404():
pass
def test_update_product_stock_updates_quantity():
pass
def test_marketplace_import_with_invalid_csv_fails_gracefully():
pass
```
## Running Tests by Category
### Pytest Configuration (pytest.ini)
```ini
[tool:pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
-v
--tb=short
--strict-markers
markers =
unit: Unit tests
integration: Integration tests
e2e: End-to-end tests
performance: Performance tests
slow: Slow running tests
database: Tests that require database
external: Tests that require external services
```
### Running Specific Test Categories
```bash
# Run only unit tests (fast)
pytest tests/unit -m unit
# Run only integration tests
pytest tests/integration -m integration
# Run all tests except slow ones
pytest -m "not slow"
# Run only database tests
pytest -m database
# Run tests for specific domain
pytest tests/unit/models/ tests/integration/api/v1/test_product_endpoints.py
# Run with coverage
pytest --cov=app --cov-report=html
```
## Benefits of This Structure
1. **Faster Development**: Developers can run relevant test subsets
2. **Clear Separation**: Easy to understand what each test covers
3. **Parallel Execution**: Can run different test types in parallel
4. **Maintenance**: Easier to maintain and update tests
5. **CI/CD Pipeline**: Can have different pipeline stages for different test types
## Migration Strategy
### Phase 1: Create Structure
1. Create new directory structure
2. Move global fixtures to `fixtures/` directory
3. Update `conftest.py` files
### Phase 2: Move Unit Tests
1. Start with utility and model tests
2. Move to `tests/unit/` with appropriate subdirectories
3. Update imports and fixtures
### Phase 3: Move Integration Tests
1. Move API endpoint tests to `tests/integration/api/`
2. Create database integration tests
3. Add workflow tests
### Phase 4: Add Missing Coverage
1. Add performance tests if needed
2. Create E2E tests for critical flows
3. Add proper test markers
## Example Test File Structure
### Unit Test Example
```python
# tests/unit/models/test_product_model.py
import pytest
from models.database import Product
class TestProductModel:
def test_product_creation_with_valid_data(self, db_session):
product = Product(
product_id="TEST123",
title="Test Product",
price="99.99"
)
db_session.add(product)
db_session.commit()
assert product.id is not None
assert product.product_id == "TEST123"
assert product.title == "Test Product"
def test_product_gtin_relationship_with_stock(self, db_session, test_product, test_stock):
# Test the GTIN-based relationship
assert test_product.gtin in [stock.gtin for stock in test_product.stock_entries]
```
### Integration Test Example
```python
# tests/integration/api/v1/test_product_endpoints.py
import pytest
class TestProductEndpoints:
def test_create_product_endpoint(self, client, auth_headers, valid_product_data):
response = client.post(
"/api/v1/products/",
json=valid_product_data,
headers=auth_headers
)
assert response.status_code == 201
assert response.json()["product_id"] == valid_product_data["product_id"]
def test_get_products_with_pagination(self, client, auth_headers, multiple_products):
response = client.get(
"/api/v1/products/?skip=0&limit=10",
headers=auth_headers
)
assert response.status_code == 200
data = response.json()
assert "products" in data
assert "total" in data
assert len(data["products"]) <= 10
```
This structure will scale beautifully as your application grows and makes it much easier for your team to maintain and extend the test suite!

View File

@@ -1,569 +0,0 @@
# Ecommerce Backend API v2.1
A robust, production-ready FastAPI backend for ecommerce product catalog and inventory management with JWT authentication and advanced CSV import capabilities.
## Key Features
### Security & Authentication
- **JWT Authentication**: Secure token-based authentication with configurable expiration (30 minutes default)
- **User Management**: Registration, login, role-based access control (Admin/User roles)
- **Password Security**: Bcrypt hashing for secure password storage
- **Protected Endpoints**: All product management operations require authentication
- **Default Admin Account**: Auto-created admin user for immediate system access
### Architecture Improvements
- **Modular Design**: Separated concerns into utility modules, middleware, and models
- **Database Optimization**: Added proper indexing strategy and foreign key relationships
- **Connection Pooling**: PostgreSQL support with connection pooling for production scalability
- **Background Processing**: Asynchronous CSV import with job tracking
### Performance Optimizations
- **Batch Processing**: CSV imports processed in configurable batches
- **Database Indexes**: Strategic indexing for common query patterns
- **Streaming Export**: Memory-efficient CSV export for large datasets
- **Rate Limiting**: Sliding window rate limiter to prevent API abuse
### Data Processing
- **Robust GTIN Handling**: Centralized GTIN normalization and validation
- **Multi-currency Support**: Advanced price parsing with currency extraction
- **International Content**: Multi-encoding CSV support for global data
## Project Structure
```
ecommerce_api/
├── main.py # FastAPI application entry point with auth
├── models/
│ ├── database_models.py # SQLAlchemy ORM models (User, Product, Stock, ImportJob)
│ └── api_models.py # Pydantic API models with auth models
├── utils/
│ ├── data_processing.py # GTIN and price processing utilities
│ ├── csv_processor.py # CSV import/export handling
│ └── database.py # Database configuration
├── middleware/
│ ├── auth.py # JWT authentication with bcrypt
│ ├── rate_limiter.py # Rate limiting implementation
│ ├── error_handler.py # Centralized error handling
│ └── logging_middleware.py # Request/response logging
├── tests/
│ └── test_auth.py # Authentication tests
├── requirements.txt # Python dependencies with auth packages
└── README.md # This file
```
## Quick Start
### 1. Installation
```bash
# Clone the repository
git clone <repository-url>
cd ecommerce-api
# Set up virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
```
### 2. Environment Configuration
Create a `.env` file in the project root:
```env
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/ecommerce_db
# For SQLite (development): DATABASE_URL=sqlite:///./ecommerce.db
# JWT Configuration
JWT_SECRET_KEY=your-super-secret-key-change-in-production-immediately
JWT_EXPIRE_MINUTES=30
# Server Configuration
API_HOST=0.0.0.0
API_PORT=8000
DEBUG=False
```
**Important Security Note**: Always change the `JWT_SECRET_KEY` in production!
### 3. Database Setup
**For SQLite (Development):**
```bash
# Run the application - it will create tables automatically
python main.py
```
**For PostgreSQL (Production):**
```bash
# Create PostgreSQL database
createdb ecommerce_db
# Run the application - it will create tables and indexes automatically
python main.py
```
### 4. Start the Server
```bash
# Development server
uvicorn main:app --reload --host 0.0.0.0 --port 8000
# Production server
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
```
The API will be available at `http://localhost:8000`
### 5. Default Admin Access
The system automatically creates a default admin user:
- **Username**: `admin`
- **Password**: `admin123`
- **Email**: `admin@example.com`
**Security Warning**: Change the admin password immediately in production!
## Authentication Flow
### 1. Register a New User
```bash
curl -X POST "http://localhost:8000/register" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"username": "newuser",
"password": "securepassword123"
}'
```
### 2. Login and Get JWT Token
```bash
curl -X POST "http://localhost:8000/login" \
-H "Content-Type: application/json" \
-d '{
"username": "admin",
"password": "admin123"
}'
```
Response:
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 1800,
"user": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"role": "admin",
"is_active": true
}
}
```
### 3. Use Token for Protected Endpoints
```bash
curl -X GET "http://localhost:8000/products" \
-H "Authorization: Bearer YOUR_JWT_TOKEN_HERE"
```
## API Endpoints
### Public Endpoints
- `GET /` - API information
- `GET /health` - Health check
- `POST /register` - Register new user
- `POST /login` - Login and get JWT token
### Protected Endpoints (Require Authentication)
#### User Management
- `GET /me` - Get current user information
#### Products (All users)
- `GET /products` - List products with filtering and search
- `POST /products` - Create new product
- `GET /products/{product_id}` - Get product with stock info
- `PUT /products/{product_id}` - Update product
- `DELETE /products/{product_id}` - Delete product and associated stock
#### Stock Management (All users)
- `POST /stock` - Set exact stock quantity
- `GET /stock/{gtin}` - Get stock summary by GTIN
#### CSV Operations (All users)
- `POST /import-csv` - Start background CSV import
- `GET /import-status/{job_id}` - Check import job status (own jobs only)
- `GET /export-csv` - Export products as CSV (streaming)
#### Statistics (All users)
- `GET /stats` - System statistics
#### Admin-Only Endpoints
- `GET /admin/users` - List all users
- `PUT /admin/users/{user_id}/status` - Activate/deactivate users
## User Roles and Permissions
### Regular Users
- Can register and login
- Access all product and stock management features
- Can import/export CSV files
- Can only view their own import jobs
- Cannot manage other users
### Admin Users
- All regular user permissions
- Can view and manage all users
- Can view all import jobs from any user
- Can activate/deactivate user accounts
## Security Features
### Password Security
- Passwords hashed using bcrypt with salt
- Minimum password length: 6 characters
- No password storage in plaintext anywhere
### JWT Token Security
- Tokens include expiration timestamp
- Tokens include user role and permissions
- Configurable expiration time (default: 30 minutes)
- Secure token validation on each request
### Rate Limiting
- CSV imports: 10 requests per hour
- General API: 100 requests per hour per client
- Customizable per endpoint
### Input Validation
- All inputs validated using Pydantic models
- Email format validation for registration
- Username alphanumeric validation
- GTIN format validation and normalization
## Advanced Features
### Background CSV Import
Import large CSV files asynchronously:
```python
import requests
# Start import
response = requests.post(
'http://localhost:8000/import-csv',
headers={'Authorization': 'Bearer YOUR_TOKEN'},
json={
'url': 'https://example.com/products.csv',
'batch_size': 1000
}
)
job_id = response.json()['job_id']
# Check status
status_response = requests.get(
f'http://localhost:8000/import-status/{job_id}',
headers={'Authorization': 'Bearer YOUR_TOKEN'}
)
print(status_response.json())
```
### Product Search and Filtering
```bash
# Search in title and description
GET /products?search=laptop
# Filter by brand and category
GET /products?brand=Apple&category=Electronics
# Combine filters with pagination
GET /products?brand=Samsung&availability=in%20stock&search=phone&skip=0&limit=50
```
### Stock Management
```bash
# Set stock for a specific location
curl -X POST "http://localhost:8000/stock" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"gtin": "1234567890123",
"location": "WAREHOUSE_A",
"quantity": 100
}'
# Get stock summary
curl -X GET "http://localhost:8000/stock/1234567890123" \
-H "Authorization: Bearer YOUR_TOKEN"
```
## Database Schema
### Users Table
```sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR UNIQUE NOT NULL,
username VARCHAR UNIQUE NOT NULL,
hashed_password VARCHAR NOT NULL,
role VARCHAR DEFAULT 'user',
is_active BOOLEAN DEFAULT true,
last_login TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
```
### Products Table
- Full product catalog with Google Shopping compatibility
- Indexed fields: `gtin`, `brand`, `google_product_category`, `availability`
- Supports all Google Shopping feed attributes
### Stock Table
- Location-based inventory tracking
- GTIN-based product linking
- Unique constraint on GTIN+location combinations
### Import Jobs Table
- Track background import operations
- User ownership and access control
- Status monitoring and error handling
## Development
### Running Tests
```bash
# Install test dependencies
pip install pytest pytest-asyncio httpx
# Run all tests
pytest
# Run with coverage
pytest --cov=. tests/
```
### Development Server with Auto-reload
```bash
uvicorn main:app --reload --host 0.0.0.0 --port 8000
```
## Production Deployment
### Security Checklist
- [ ] Change default admin password immediately
- [ ] Set strong JWT_SECRET_KEY (32+ random characters)
- [ ] Configure JWT_EXPIRE_MINUTES appropriately
- [ ] Set up HTTPS/TLS termination
- [ ] Configure CORS for your frontend domains only
- [ ] Set up database connection limits and pooling
- [ ] Enable request logging and monitoring
- [ ] Configure rate limiting per your needs
- [ ] Set up user account monitoring and alerting
- [ ] Regular security audits of user accounts
### Environment Variables for Production
```env
# Security
JWT_SECRET_KEY=your-very-long-random-secret-key-at-least-32-characters
JWT_EXPIRE_MINUTES=30
# Database (use PostgreSQL in production)
DATABASE_URL=postgresql://user:password@db-host:5432/ecommerce_prod
# Server
DEBUG=False
API_HOST=0.0.0.0
API_PORT=8000
# Optional: External services
REDIS_URL=redis://redis-host:6379/0
```
### Docker Deployment
```yaml
# docker-compose.yml
version: '3.8'
services:
db:
image: postgres:15
environment:
POSTGRES_DB: ecommerce
POSTGRES_USER: ecommerce_user
POSTGRES_PASSWORD: secure_password
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
api:
build: .
environment:
DATABASE_URL: postgresql://ecommerce_user:secure_password@db:5432/ecommerce
JWT_SECRET_KEY: your-production-secret-key
JWT_EXPIRE_MINUTES: 30
ports:
- "8000:8000"
depends_on:
- db
restart: unless-stopped
volumes:
postgres_data:
```
### Nginx Configuration
```nginx
server {
listen 80;
server_name your-api-domain.com;
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
## Troubleshooting
### Authentication Issues
**Invalid Token Errors:**
- Check token expiration (default 30 minutes)
- Verify JWT_SECRET_KEY is consistent
- Ensure Bearer token format: `Authorization: Bearer <token>`
**Login Failures:**
- Verify username/email and password
- Check if user account is active (`is_active: true`)
- Review user registration process
**Permission Denied:**
- Confirm user role permissions
- Check endpoint access requirements
- Verify token contains correct role information
### Database Issues
**Connection Errors:**
- Verify DATABASE_URL format and credentials
- Check database server accessibility
- Monitor connection pool limits
**Migration Issues:**
- Tables are created automatically on startup
- For schema changes, implement proper migrations
- Backup data before major updates
### Common API Issues
**CSV Import Failures:**
- Check file URL accessibility
- Verify CSV format and encoding
- Monitor import job status for detailed errors
- Ensure proper authentication token
**Rate Limiting:**
- Default limits: 100 requests/hour, 10 CSV imports/hour
- Check rate limit headers in responses
- Implement proper retry logic with backoff
### Logging and Monitoring
Application logs include:
- Authentication events (login, failed attempts)
- API request/response times
- Import job progress and errors
- Rate limiting events
- Database query performance
```bash
# View logs in development
python main.py # Logs to console
# Docker logs
docker-compose logs -f api
```
## Migration from v2.0
If upgrading from v2.0 to v2.1:
1. **Install new dependencies:**
```bash
pip install -r requirements.txt
```
2. **Update environment variables:**
```bash
echo "JWT_SECRET_KEY=your-secret-key" >> .env
echo "JWT_EXPIRE_MINUTES=30" >> .env
```
3. **Database migration:**
The application will automatically create the new `users` table and update the `import_jobs` table on startup.
4. **Update client code:**
- Add authentication to all product management API calls
- Implement login flow in your frontend
- Handle JWT token refresh
## Contributing
1. Fork the repository
2. Create a feature branch: `git checkout -b feature-name`
3. Make changes with proper tests
4. Run security and quality checks
5. Update documentation if needed
6. Submit a pull request
### Code Quality Standards
- All endpoints must have proper authentication
- Password handling must use bcrypt
- JWT tokens must have expiration
- Input validation using Pydantic models
- Comprehensive error handling
- Unit tests for authentication logic
## License
This project is licensed under the MIT License - see the LICENSE file for details.
## Security
For security issues, please email the maintainers directly instead of creating a public issue.
## Support
For issues and questions:
1. Check the troubleshooting section above
2. Review existing GitHub issues
3. Create a new issue with detailed information including:
- Authentication steps you've tried
- Error messages and logs
- API endpoint and request details
- Environment configuration (without secrets)

View File

@@ -1,663 +0,0 @@
# Letzshop Marketplace API v2.1
A robust, production-ready FastAPI backend for Luxembourg's premier e-commerce marketplace with multi-vendor support, JWT authentication, and advanced CSV import capabilities.
## Key Features
### Marketplace Architecture
- **Multi-Vendor Support**: Shops can import and manage their product catalogs independently
- **Centralized Product Catalog**: Products exist in main marketplace with shop-specific overrides
- **Shop Management**: Complete vendor onboarding, verification, and management system
- **Shop-Specific Pricing**: Vendors can set their own prices, availability, and conditions
- **Marketplace Controls**: Admin verification and quality control for vendor shops
### Security & Authentication
- **JWT Authentication**: Secure token-based authentication with configurable expiration (30 minutes default)
- **User Management**: Registration, login, role-based access control (Admin/User/Shop Owner roles)
- **Password Security**: Bcrypt hashing for secure password storage
- **Protected Endpoints**: All operations require authentication with proper authorization
- **Default Admin Account**: Auto-created admin user for immediate system access
### Architecture Improvements
- **Modular Design**: Separated concerns into utility modules, middleware, and models
- **Database Optimization**: Added proper indexing strategy and foreign key relationships
- **Connection Pooling**: PostgreSQL support with connection pooling for production scalability
- **Background Processing**: Asynchronous CSV import with job tracking per shop
### Performance Optimizations
- **Batch Processing**: CSV imports processed in configurable batches
- **Database Indexes**: Strategic indexing for common query patterns including shop relationships
- **Streaming Export**: Memory-efficient CSV export for large datasets with shop filtering
- **Rate Limiting**: Sliding window rate limiter to prevent API abuse
### Data Processing
- **Robust GTIN Handling**: Centralized GTIN normalization and validation
- **Multi-currency Support**: Advanced price parsing with currency extraction
- **International Content**: Multi-encoding CSV support for global data
- **Shop Association**: Automatic product-shop linking during CSV imports
## Project Structure
```
letzshop_api/
├── main.py # FastAPI application entry point with marketplace support
├── models/
│ ├── database_models.py # SQLAlchemy ORM models (User, Shop, Product, ShopProduct, Stock, ImportJob)
│ └── api_models.py # Pydantic API models with shop and auth models
├── utils/
│ ├── data_processing.py # GTIN and price processing utilities
│ ├── csv_processor.py # CSV import/export handling with shop support
│ └── database.py # Database configuration
├── middleware/
│ ├── auth.py # JWT authentication with bcrypt
│ ├── rate_limiter.py # Rate limiting implementation
│ ├── error_handler.py # Centralized error handling
│ └── logging_middleware.py # Request/response logging
├── tests/
│ └── test_auth.py # Authentication tests
├── requirements.txt # Python dependencies with auth packages
└── README.md # This file
```
## Quick Start
### 1. Installation
```bash
# Clone the repository
git clone <repository-url>
cd letzshop-api
# Set up virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
```
### 2. Environment Configuration
Create a `.env` file in the project root:
```env
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/letzshop_db
# For SQLite (development): DATABASE_URL=sqlite:///./letzshop.db
# JWT Configuration
JWT_SECRET_KEY=your-super-secret-key-change-in-production-immediately
JWT_EXPIRE_MINUTES=30
# Server Configuration
API_HOST=0.0.0.0
API_PORT=8000
DEBUG=False
```
**Important Security Note**: Always change the `JWT_SECRET_KEY` in production!
### 3. Database Setup
**For SQLite (Development):**
```bash
# Run the application - it will create tables automatically
python main.py
```
**For PostgreSQL (Production):**
```bash
# Create PostgreSQL database
createdb letzshop_db
# Run the application - it will create tables and indexes automatically
python main.py
```
### 4. Start the Server
```bash
# Development server
uvicorn main:app --reload --host 0.0.0.0 --port 8000
# Production server
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
```
The API will be available at `http://localhost:8000`
### 5. Default Access
The system automatically creates:
- **Admin User**: `admin` / `admin123` / `admin@example.com`
- **Demo Shop**: `DEMOSHOP` owned by admin for testing
**Security Warning**: Change the admin password immediately in production!
## Authentication Flow
### 1. Register a New User
```bash
curl -X POST "http://localhost:8000/register" \
-H "Content-Type: application/json" \
-d '{
"email": "vendor@example.com",
"username": "newvendor",
"password": "securepassword123"
}'
```
### 2. Login and Get JWT Token
```bash
curl -X POST "http://localhost:8000/login" \
-H "Content-Type: application/json" \
-d '{
"username": "admin",
"password": "admin123"
}'
```
Response:
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 1800,
"user": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"role": "admin",
"is_active": true
}
}
```
### 3. Use Token for Protected Endpoints
```bash
curl -X GET "http://localhost:8000/shops" \
-H "Authorization: Bearer YOUR_JWT_TOKEN_HERE"
```
## Marketplace Workflow
### 1. Create a Shop
```bash
curl -X POST "http://localhost:8000/shops" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"shop_code": "TECHSTORE",
"shop_name": "Tech Store Luxembourg",
"description": "Electronics and gadgets for Luxembourg",
"contact_email": "info@techstore.lu",
"contact_phone": "+352 123 456 789",
"website": "https://techstore.lu"
}'
```
### 2. Import Products for Your Shop
```bash
curl -X POST "http://localhost:8000/import-csv" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://techstore.com/products.csv",
"shop_code": "TECHSTORE",
"batch_size": 1000
}'
```
### 3. Monitor Import Progress
```bash
curl -X GET "http://localhost:8000/import-status/1" \
-H "Authorization: Bearer YOUR_TOKEN"
```
### 4. View Shop Products
```bash
curl -X GET "http://localhost:8000/products?shop_code=TECHSTORE" \
-H "Authorization: Bearer YOUR_TOKEN"
```
## API Endpoints
### Public Endpoints
- `GET /` - API information
- `GET /health` - Health check
- `POST /register` - Register new user
- `POST /login` - Login and get JWT token
### Protected Endpoints (Require Authentication)
#### User Management
- `GET /me` - Get current user information
#### Shop Management
- `POST /shops` - Create new shop
- `GET /shops` - List shops with filtering
- `GET /shops/{shop_code}` - Get shop details
- `PUT /shops/{shop_code}` - Update shop (owners only)
- `POST /shops/{shop_code}/products` - Add product to shop catalog
- `GET /shops/{shop_code}/products` - Get shop products
#### Products (Marketplace Catalog)
- `GET /products` - List products with filtering (optionally by shop)
- `POST /products` - Create new product in marketplace catalog
- `GET /products/{product_id}` - Get product with stock info and shop listings
- `PUT /products/{product_id}` - Update product
- `DELETE /products/{product_id}` - Delete product and associated shop listings
#### Stock Management
- `POST /stock` - Set stock quantity (with optional shop association)
- `GET /stock/{gtin}` - Get stock summary by GTIN
#### CSV Operations
- `POST /import-csv` - Start background CSV import for specific shop
- `GET /import-status/{job_id}` - Check import job status
- `GET /export-csv` - Export products as CSV (optionally filtered by shop)
#### Statistics
- `GET /stats` - Marketplace statistics
#### Admin-Only Endpoints
- `GET /admin/users` - List all users
- `PUT /admin/users/{user_id}/status` - Activate/deactivate users
- `GET /admin/shops` - List all shops
- `PUT /admin/shops/{shop_id}/verify` - Verify/unverify shop
- `PUT /admin/shops/{shop_id}/status` - Activate/deactivate shop
- `GET /admin/import-jobs` - View all import jobs
## User Roles and Permissions
### Regular Users
- Can register and login
- Can create and manage their own shops
- Can import products for their shops
- Can manage stock for their products
- Can view marketplace products and shops
### Shop Owners (Regular Users with Shops)
- All regular user permissions
- Can manage their shop information
- Can import/export products for their shops
- Can set shop-specific pricing and availability
- Can view their import job history
### Admin Users
- All user permissions
- Can view and manage all users and shops
- Can verify/unverify shops
- Can view all import jobs from any shop
- Can activate/deactivate user accounts and shops
## Marketplace Features
### Shop Verification System
- New shops start as unverified
- Admin approval required for public visibility
- Verified shops appear in public marketplace listings
- Quality control through admin verification
### Multi-Vendor Product Catalog
- Products exist in central marketplace catalog
- Multiple shops can sell the same product
- Shop-specific pricing, availability, and conditions
- Automatic product matching during CSV imports
### Shop-Specific Overrides
```json
{
"product_id": "LAPTOP123",
"shop_price": 999.99,
"shop_currency": "EUR",
"shop_availability": "in stock",
"shop_condition": "new",
"is_featured": true,
"min_quantity": 1,
"max_quantity": 5
}
```
### Advanced Product Search
```bash
# Search products in specific shop
GET /products?shop_code=TECHSTORE&search=laptop
# Search across all verified shops
GET /products?search=laptop&availability=in%20stock
# Filter by brand and category
GET /products?brand=Apple&category=Electronics
```
## Database Schema
### Core Tables
#### Users Table
```sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR UNIQUE NOT NULL,
username VARCHAR UNIQUE NOT NULL,
hashed_password VARCHAR NOT NULL,
role VARCHAR DEFAULT 'user',
is_active BOOLEAN DEFAULT true,
last_login TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
```
#### Shops Table
```sql
CREATE TABLE shops (
id SERIAL PRIMARY KEY,
shop_code VARCHAR UNIQUE NOT NULL,
shop_name VARCHAR NOT NULL,
description TEXT,
owner_id INTEGER REFERENCES users(id),
contact_email VARCHAR,
contact_phone VARCHAR,
website VARCHAR,
business_address TEXT,
tax_number VARCHAR,
is_active BOOLEAN DEFAULT true,
is_verified BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
```
#### Products Table
- Main marketplace catalog with Google Shopping compatibility
- Indexed fields: `gtin`, `brand`, `google_product_category`, `availability`
- Supports all Google Shopping feed attributes
#### ShopProducts Table
```sql
CREATE TABLE shop_products (
id SERIAL PRIMARY KEY,
shop_id INTEGER REFERENCES shops(id),
product_id INTEGER REFERENCES products(id),
shop_product_id VARCHAR,
shop_price DECIMAL,
shop_sale_price DECIMAL,
shop_currency VARCHAR,
shop_availability VARCHAR,
shop_condition VARCHAR,
is_featured BOOLEAN DEFAULT false,
is_active BOOLEAN DEFAULT true,
min_quantity INTEGER DEFAULT 1,
max_quantity INTEGER,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
UNIQUE(shop_id, product_id)
);
```
#### Stock Table
- Location-based inventory tracking with optional shop association
- GTIN-based product linking
- Support for reserved quantities (for order processing)
#### Import Jobs Table
- Track background import operations per shop
- User and shop ownership tracking
- Status monitoring and error handling
## Advanced Features
### Shop-Specific CSV Import
Import products with automatic shop association:
```python
import requests
# Start import for specific shop
response = requests.post(
'http://localhost:8000/import-csv',
headers={'Authorization': 'Bearer YOUR_TOKEN'},
json={
'url': 'https://myshop.com/products.csv',
'shop_code': 'MYSHOP',
'batch_size': 1000
}
)
job_id = response.json()['job_id']
# Monitor progress
status_response = requests.get(
f'http://localhost:8000/import-status/{job_id}',
headers={'Authorization': 'Bearer YOUR_TOKEN'}
)
print(status_response.json())
```
### Multi-Shop Product Management
```bash
# Add existing marketplace product to your shop
curl -X POST "http://localhost:8000/shops/MYSHOP/products" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"product_id": "EXISTING_PRODUCT_123",
"shop_price": 89.99,
"shop_availability": "in stock",
"is_featured": true
}'
# Get products from specific shop
curl -X GET "http://localhost:8000/shops/MYSHOP/products" \
-H "Authorization: Bearer YOUR_TOKEN"
```
### Stock Management with Shop Context
```bash
# Set shop-specific stock
curl -X POST "http://localhost:8000/stock" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"gtin": "1234567890123",
"location": "MYSHOP_WAREHOUSE",
"quantity": 50,
"shop_code": "MYSHOP"
}'
```
## Production Deployment
### Security Checklist for Marketplace
- [ ] Change default admin password immediately
- [ ] Set strong JWT_SECRET_KEY (32+ random characters)
- [ ] Configure JWT_EXPIRE_MINUTES appropriately
- [ ] Set up HTTPS/TLS termination
- [ ] Configure CORS for your frontend domains only
- [ ] Set up database connection limits and pooling
- [ ] Enable request logging and monitoring
- [ ] Configure rate limiting per your needs
- [ ] Set up shop verification workflow
- [ ] Implement shop quality monitoring
- [ ] Set up automated backup for shop data
- [ ] Configure email notifications for shop owners
- [ ] Regular security audits of user accounts and shops
### Environment Variables for Production
```env
# Security
JWT_SECRET_KEY=your-very-long-random-secret-key-at-least-32-characters
JWT_EXPIRE_MINUTES=30
# Database (use PostgreSQL in production)
DATABASE_URL=postgresql://user:password@db-host:5432/letzshop_prod
# Server
DEBUG=False
API_HOST=0.0.0.0
API_PORT=8000
# Marketplace Configuration
MARKETPLACE_NAME=Letzshop
DEFAULT_CURRENCY=EUR
ADMIN_EMAIL=admin@letzshop.lu
# Optional: External services
REDIS_URL=redis://redis-host:6379/0
EMAIL_API_KEY=your-email-service-key
```
### Docker Deployment
```yaml
# docker-compose.yml
version: '3.8'
services:
db:
image: postgres:15
environment:
POSTGRES_DB: letzshop
POSTGRES_USER: letzshop_user
POSTGRES_PASSWORD: secure_password
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
api:
build: .
environment:
DATABASE_URL: postgresql://letzshop_user:secure_password@db:5432/letzshop
JWT_SECRET_KEY: your-production-secret-key
JWT_EXPIRE_MINUTES: 30
MARKETPLACE_NAME: Letzshop
ports:
- "8000:8000"
depends_on:
- db
restart: unless-stopped
volumes:
postgres_data:
```
## Troubleshooting
### Marketplace-Specific Issues
**Shop Import Failures:**
- Verify shop exists and is active
- Check user permissions for the shop
- Ensure CSV format is compatible
- Monitor import job status for detailed errors
**Shop Product Association:**
- Products are added to main catalog first
- Shop-product relationships created automatically during import
- Check shop_products table for associations
**Permission Issues:**
- Shop owners can only manage their own shops
- Admin can manage all shops and users
- Verify user role and shop ownership
### Common API Issues
**Shop Not Found Errors:**
- Check shop_code spelling and case (stored uppercase)
- Verify shop is active and verified (for public access)
- Check user permissions for shop access
**CSV Import with Shop Code:**
- Shop code is required for all imports
- Shop must exist before importing
- User must have permission to import for that shop
## Migration Guide
### From v2.0 to v2.1 (Marketplace Update)
1. **Backup existing data**
2. **Update dependencies:** `pip install -r requirements.txt`
3. **Update environment variables** (add shop-related configs)
4. **Run application** - new tables will be created automatically
5. **Existing products remain in main catalog**
6. **Create shops for existing users**
7. **Update client applications** to use shop-specific endpoints
### Data Migration Script Example
```python
# Migrate existing products to demo shop
from models.database import Product, Shop, ShopProduct
from sqlalchemy.orm import Session
def migrate_to_shops(db: Session):
demo_shop = db.query(Shop).filter(Shop.shop_code == "DEMOSHOP").first()
products = db.query(Product).all()
for product in products:
shop_product = ShopProduct(
shop_id=demo_shop.id,
product_id=product.id,
shop_price=product.price,
shop_availability=product.availability,
is_active=True
)
db.add(shop_product)
db.commit()
```
## Contributing
1. Fork the repository
2. Create a feature branch: `git checkout -b feature-name`
3. Make changes with proper tests
4. Run security and quality checks
5. Update documentation if needed
6. Submit a pull request
### Code Quality Standards
- All endpoints must have proper authentication and authorization
- Shop ownership verification for protected operations
- Input validation using Pydantic models
- Comprehensive error handling with meaningful messages
- Unit tests for marketplace functionality
## License
This project is licensed under the MIT License - see the LICENSE file for details.
## About Letzshop
Letzshop is Luxembourg's premier e-commerce marketplace, connecting local and international vendors with Luxembourg customers. Our platform supports multi-vendor operations with advanced inventory management and seamless CSV import capabilities.
## Support
For marketplace-specific issues and vendor onboarding:
1. Check the troubleshooting section above
2. Review existing GitHub issues
3. Create a new issue with detailed information including:
- Shop code and user information
- CSV format and import details
- Error messages and logs
- Environment configuration (without secrets)
For vendor support: vendor-support@letzshop.lu
For technical issues: tech-support@letzshop.lu