Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/manual/woodpecker Pipeline failed
CD - Build & Deploy / build-and-push (push) Has been cancelled
CD - Build & Deploy / package-helm (push) Has been cancelled
CD - Build & Deploy / deploy-staging (push) Has been cancelled
CD - Build & Deploy / deploy-production (push) Has been cancelled
CD - Build & Deploy / release (push) Has been cancelled
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / security (push) Has been cancelled
Reflex only accepts 'dev' or 'prod' as valid --env values. This was causing: Error: Invalid value for '--env': 'production' is not one of 'dev', 'prod' Changes: - Dockerfile: REFLEX_ENV=production -> prod - Dockerfile CMD: --env production -> prod - docs/handbook.md: updated example command
903 lines
23 KiB
Markdown
903 lines
23 KiB
Markdown
# پروژه پیکربند - Handbook جامع
|
|
|
|
**نسخه**: 1.0.0
|
|
**آخرین بروزرسانی**: 2025-01-24
|
|
**نویسنده**: تیم توسعه پیکربند
|
|
|
|
---
|
|
|
|
## فهرست مطالب
|
|
|
|
1. [معرفی پروژه](#1-معرفی-پروژه)
|
|
2. [معماری کلی](#2-معماری-کلی)
|
|
3. [قوانین و استانداردها](#3-قوانین-و-استانداردها)
|
|
4. [راهاندازی محیط توسعه](#4-راهاندازی-محیط-توسعه)
|
|
5. [ساختار پروژه](#5-ساختار-پروژه)
|
|
6. [Design Patterns](#6-design-patterns)
|
|
7. [Best Practices](#7-best-practices)
|
|
8. [Testing Strategy](#8-testing-strategy)
|
|
9. [Deployment Guide](#9-deployment-guide)
|
|
10. [Troubleshooting](#10-troubleshooting)
|
|
11. [مستندسازی تغییرات](#11-مستندسازی-تغییرات)
|
|
|
|
---
|
|
|
|
## 1. معرفی پروژه
|
|
|
|
### 1.1 هدف
|
|
|
|
پیکربند یک پلتفرم جامع مدیریت هاستینگ و زیرساخت ابری است که شامل:
|
|
|
|
- **هاستینگ وردپرس**: مدیریت حرفهای سایتهای WordPress
|
|
- **فروش دامین**: ثبت و مدیریت دامینها
|
|
- **سرورهای اختصاصی**: VPS و Dedicated Servers
|
|
- **خدمات DevOps**: مشاوره و پیادهسازی
|
|
- **پنل مدیریت**: پنل کنترل سفارشی شبیه cPanel
|
|
|
|
### 1.2 تکنولوژیهای استفاده شده
|
|
|
|
| تکنولوژی | نسخه | کاربرد |
|
|
|----------|------|--------|
|
|
| Python | 3.11+ | زبان اصلی |
|
|
| Reflex | 0.4.0 | Frontend/Backend Framework |
|
|
| PostgreSQL | 14+ | Database اصلی |
|
|
| Redis | 7+ | Cache & Sessions |
|
|
| SQLAlchemy | 2.0+ | ORM |
|
|
| Celery | 5.3+ | Task Queue |
|
|
| pytest | 7.4+ | Testing |
|
|
|
|
### 1.3 اصول طراحی
|
|
|
|
#### Clean Architecture
|
|
پروژه بر اساس معماری تمیز طراحی شده که شامل 4 لایه اصلی است:
|
|
|
|
1. **Domain Layer**: منطق کسبوکار خالص
|
|
2. **Application Layer**: موارد استفاده (Use Cases)
|
|
3. **Infrastructure Layer**: جزئیات فنی
|
|
4. **Presentation Layer**: رابط کاربری
|
|
|
|
#### SOLID Principles
|
|
- **S**ingle Responsibility Principle
|
|
- **O**pen/Closed Principle
|
|
- **L**iskov Substitution Principle
|
|
- **I**nterface Segregation Principle
|
|
- **D**ependency Inversion Principle
|
|
|
|
#### سایر اصول
|
|
- **DRY**: Don't Repeat Yourself
|
|
- **KISS**: Keep It Simple, Stupid
|
|
- **YAGNI**: You Aren't Gonna Need It
|
|
- **Convention over Configuration**
|
|
|
|
---
|
|
|
|
## 2. معماری کلی
|
|
|
|
### 2.1 نمای کلی لایهها
|
|
|
|
```
|
|
┌─────────────────────────────────────────┐
|
|
│ Presentation Layer (Reflex UI) │
|
|
│ ┌────────┐ ┌────────┐ ┌────────┐ │
|
|
│ │Landing │ │Dashboard│ │ Admin │ │
|
|
│ └────────┘ └────────┘ └────────┘ │
|
|
└──────────────────┬──────────────────────┘
|
|
│
|
|
┌──────────────────┴──────────────────────┐
|
|
│ Application Layer (Use Cases) │
|
|
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
|
|
│ │ Auth │ │Billing│ │Server│ │Ticket│ │
|
|
│ └──────┘ └──────┘ └──────┘ └──────┘ │
|
|
└──────────────────┬──────────────────────┘
|
|
│
|
|
┌──────────────────┴──────────────────────┐
|
|
│ Domain Layer (Business Logic) │
|
|
│ ┌────────┐ ┌────────┐ ┌────────┐ │
|
|
│ │Entities│ │ Values │ │Services│ │
|
|
│ └────────┘ └────────┘ └────────┘ │
|
|
└──────────────────┬──────────────────────┘
|
|
│
|
|
┌──────────────────┴──────────────────────┐
|
|
│ Infrastructure Layer (Technical) │
|
|
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
|
|
│ │ DB │ │Cache│ │ API │ │Tasks│ │
|
|
│ └─────┘ └─────┘ └─────┘ └─────┘ │
|
|
└─────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.2 جریان داده
|
|
|
|
```
|
|
User Request → Presentation → Application → Domain
|
|
↓
|
|
Infrastructure ← Application ← Domain Logic
|
|
↓
|
|
External APIs
|
|
```
|
|
|
|
### 2.3 Layer های جزئی
|
|
|
|
#### Domain Layer
|
|
- **Entities**: موجودیتهای اصلی (User, Service, Invoice, etc.)
|
|
- **Value Objects**: اشیاء ارزشی (Email, Money, Phone)
|
|
- **Domain Services**: منطق پیچیده دامین
|
|
- **Enums**: مقادیر ثابت
|
|
- **Exceptions**: خطاهای دامین
|
|
|
|
#### Application Layer
|
|
- **Use Cases**: موارد استفاده سیستم
|
|
- **DTOs**: Data Transfer Objects
|
|
- **Interfaces**: تعریف رابطهای سرویسها
|
|
- **Validators**: اعتبارسنجی ورودیها
|
|
|
|
#### Infrastructure Layer
|
|
- **Database**: Models و Repositories
|
|
- **Cache**: Redis implementation
|
|
- **External**: API های خارجی
|
|
- **Tasks**: Background jobs
|
|
- **Security**: Authentication & Authorization
|
|
- **Logging**: Structured logging
|
|
|
|
#### Presentation Layer
|
|
- **Web**: Reflex components و pages
|
|
- **API**: REST endpoints (optional)
|
|
- **State**: Reflex state management
|
|
|
|
---
|
|
|
|
## 3. قوانین و استانداردها
|
|
|
|
### 3.1 Python Code Style (PEP 8)
|
|
|
|
#### Naming Conventions
|
|
|
|
```python
|
|
# Classes: PascalCase
|
|
class UserService:
|
|
pass
|
|
|
|
class PaymentGateway:
|
|
pass
|
|
|
|
# Functions & Methods: snake_case
|
|
def create_user(email: str) -> User:
|
|
pass
|
|
|
|
def process_payment(amount: Decimal) -> PaymentResult:
|
|
pass
|
|
|
|
# Constants: UPPER_SNAKE_CASE
|
|
MAX_LOGIN_ATTEMPTS = 3
|
|
DEFAULT_TIMEOUT = 30
|
|
API_VERSION = "v1"
|
|
|
|
# Private methods: _leading_underscore
|
|
def _internal_helper():
|
|
pass
|
|
|
|
# Protected: __double_underscore (name mangling)
|
|
class BaseClass:
|
|
def __private_method(self):
|
|
pass
|
|
|
|
# Variables: snake_case
|
|
user_email = "test@example.com"
|
|
total_amount = Decimal("100.00")
|
|
```
|
|
|
|
### 3.2 Type Hints (الزامی)
|
|
|
|
```python
|
|
from typing import Optional, List, Dict, Any, Union
|
|
from decimal import Decimal
|
|
|
|
# Function signatures
|
|
def get_user_by_id(user_id: int) -> Optional[User]:
|
|
pass
|
|
|
|
def create_invoice(
|
|
user_id: int,
|
|
amount: Decimal,
|
|
items: List[InvoiceItem]
|
|
) -> Invoice:
|
|
pass
|
|
|
|
# Return types
|
|
def get_users(limit: int = 10) -> List[User]:
|
|
pass
|
|
|
|
def find_service(service_id: int) -> Optional[Service]:
|
|
pass
|
|
|
|
# Complex types
|
|
def process_config(config: Dict[str, Any]) -> bool:
|
|
pass
|
|
|
|
UserOrNone = Optional[User]
|
|
ServiceList = List[Service]
|
|
```
|
|
|
|
### 3.3 Docstrings (Google Style - الزامی)
|
|
|
|
```python
|
|
def create_user(
|
|
email: str,
|
|
password: str,
|
|
full_name: str,
|
|
phone: Optional[str] = None
|
|
) -> User:
|
|
"""Create a new user account.
|
|
|
|
This function creates a new user in the system with the provided
|
|
information. Password is automatically hashed before storage.
|
|
|
|
Args:
|
|
email: User's email address (must be unique)
|
|
password: Plain text password (will be hashed)
|
|
full_name: User's full name
|
|
phone: Optional phone number
|
|
|
|
Returns:
|
|
User: Created user object
|
|
|
|
Raises:
|
|
EmailAlreadyExistsException: If email is already registered
|
|
InvalidEmailException: If email format is invalid
|
|
WeakPasswordException: If password doesn't meet requirements
|
|
|
|
Example:
|
|
>>> user = create_user(
|
|
... email="test@example.com",
|
|
... password="SecurePass123!",
|
|
... full_name="John Doe",
|
|
... phone="+989123456789"
|
|
... )
|
|
>>> print(user.id)
|
|
1
|
|
"""
|
|
pass
|
|
```
|
|
|
|
### 3.4 Import Order (با isort)
|
|
|
|
```python
|
|
# 1. Standard library imports
|
|
import os
|
|
import sys
|
|
from typing import Optional, List
|
|
from decimal import Decimal
|
|
from datetime import datetime
|
|
|
|
# 2. Third-party imports
|
|
import redis
|
|
from sqlalchemy import Column, Integer, String
|
|
from pydantic import BaseModel
|
|
|
|
# 3. Local application imports
|
|
from src.config.settings import settings
|
|
from src.core.domain.entities.user import User
|
|
from src.infrastructure.database.repositories.user_repository import UserRepository
|
|
```
|
|
|
|
### 3.5 Error Handling
|
|
|
|
```python
|
|
# ✅ GOOD: Specific exceptions
|
|
try:
|
|
user = user_repository.get_by_id(user_id)
|
|
if not user:
|
|
raise UserNotFoundException(f"User {user_id} not found")
|
|
except DatabaseException as e:
|
|
logger.error("database_error", error=str(e), user_id=user_id)
|
|
raise
|
|
except Exception as e:
|
|
logger.critical("unexpected_error", error=str(e))
|
|
raise InfrastructureException("Internal server error") from e
|
|
|
|
# ❌ BAD: Generic exceptions
|
|
try:
|
|
# code
|
|
except: # Never do this!
|
|
pass
|
|
|
|
# ❌ BAD: Too broad
|
|
try:
|
|
# code
|
|
except Exception:
|
|
pass
|
|
```
|
|
|
|
### 3.6 Logging Best Practices
|
|
|
|
```python
|
|
import structlog
|
|
|
|
logger = structlog.get_logger(__name__)
|
|
|
|
# ✅ GOOD: Structured logging with context
|
|
logger.info(
|
|
"user_created",
|
|
user_id=user.id,
|
|
email=user.email,
|
|
registration_source="web",
|
|
ip_address=request.ip
|
|
)
|
|
|
|
logger.error(
|
|
"payment_failed",
|
|
user_id=user.id,
|
|
invoice_id=invoice.id,
|
|
amount=str(invoice.amount),
|
|
gateway="zarinpal",
|
|
error_code=response.code,
|
|
error_message=response.message
|
|
)
|
|
|
|
# ❌ BAD: String concatenation
|
|
logger.info("User " + str(user.id) + " created")
|
|
```
|
|
|
|
---
|
|
|
|
## 4. راهاندازی محیط توسعه
|
|
|
|
### 4.1 پیشنیازها
|
|
|
|
```bash
|
|
# Check Python version (3.11+)
|
|
python --version
|
|
|
|
# Check PostgreSQL (14+)
|
|
psql --version
|
|
|
|
# Check Redis (7+)
|
|
redis-cli --version
|
|
|
|
# Check Node.js (18+)
|
|
node --version
|
|
```
|
|
|
|
### 4.2 نصب وابستگیها
|
|
|
|
```bash
|
|
# Clone repository
|
|
git clone https://github.com/yourusername/peikarband.git
|
|
cd peikarband
|
|
|
|
# Create virtual environment
|
|
python -m venv venv
|
|
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
|
|
# Install dependencies
|
|
pip install -r requirements.txt
|
|
pip install -r requirements-dev.txt
|
|
|
|
# Install pre-commit hooks
|
|
pre-commit install
|
|
```
|
|
|
|
### 4.3 تنظیم Environment Variables
|
|
|
|
```bash
|
|
# Copy example env file
|
|
cp .env.example .env
|
|
|
|
# Edit .env file
|
|
nano .env
|
|
|
|
# Required variables:
|
|
# - DATABASE_URL
|
|
# - REDIS_URL
|
|
# - SECRET_KEY
|
|
# - JWT_SECRET_KEY
|
|
```
|
|
|
|
### 4.4 راهاندازی دیتابیس
|
|
|
|
```bash
|
|
# Create database
|
|
createdb peikarband
|
|
|
|
# Or using psql
|
|
psql -U postgres
|
|
CREATE DATABASE peikarband;
|
|
\q
|
|
|
|
# Run migrations
|
|
alembic upgrade head
|
|
|
|
# (Optional) Seed database
|
|
python scripts/seed_database.py
|
|
```
|
|
|
|
### 4.5 اجرای پروژه
|
|
|
|
```bash
|
|
# Development mode
|
|
python -m reflex run
|
|
|
|
# With auto-reload
|
|
python -m reflex run --reload
|
|
|
|
# Production mode
|
|
python -m reflex run --env prod
|
|
```
|
|
|
|
---
|
|
|
|
## 5. ساختار پروژه
|
|
|
|
### 5.1 نمای کلی
|
|
|
|
```
|
|
peikarband/
|
|
├── docs/ # Documentation
|
|
├── src/ # Source code
|
|
├── tests/ # Tests
|
|
├── scripts/ # Utility scripts
|
|
├── .github/workflows/ # CI/CD
|
|
└── [config files] # Configuration
|
|
```
|
|
|
|
### 5.2 src/ Structure
|
|
|
|
```
|
|
src/
|
|
├── config/ # Configuration
|
|
│ ├── settings.py # Main settings
|
|
│ ├── database.py # DB config
|
|
│ ├── cache.py # Redis config
|
|
│ └── logging.py # Log config
|
|
│
|
|
├── core/ # Core business logic
|
|
│ ├── domain/ # Domain layer
|
|
│ │ ├── entities/ # Business entities
|
|
│ │ ├── value_objects/ # Value objects
|
|
│ │ ├── enums/ # Enumerations
|
|
│ │ └── exceptions/ # Domain exceptions
|
|
│ │
|
|
│ ├── application/ # Application layer
|
|
│ │ ├── use_cases/ # Use cases
|
|
│ │ ├── dto/ # DTOs
|
|
│ │ ├── interfaces/ # Service interfaces
|
|
│ │ └── validators/ # Validators
|
|
│ │
|
|
│ └── utils/ # Core utilities
|
|
│
|
|
├── infrastructure/ # Infrastructure layer
|
|
│ ├── database/ # Database implementation
|
|
│ ├── cache/ # Cache implementation
|
|
│ ├── external/ # External APIs
|
|
│ ├── tasks/ # Background tasks
|
|
│ ├── security/ # Security utilities
|
|
│ └── logging/ # Logging setup
|
|
│
|
|
├── presentation/ # Presentation layer
|
|
│ ├── web/ # Reflex web app
|
|
│ │ ├── pages/ # Pages
|
|
│ │ ├── components/ # Components
|
|
│ │ ├── state/ # State management
|
|
│ │ └── styles/ # Styling
|
|
│ │
|
|
│ └── api/ # REST API (optional)
|
|
│
|
|
└── shared/ # Shared code
|
|
├── events/ # Domain events
|
|
└── messaging/ # Event bus
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Design Patterns
|
|
|
|
### 6.1 Repository Pattern
|
|
|
|
```python
|
|
from abc import ABC, abstractmethod
|
|
from typing import Optional, List
|
|
|
|
# Interface (in core/application/interfaces/repositories/)
|
|
class IUserRepository(ABC):
|
|
@abstractmethod
|
|
def get_by_id(self, user_id: int) -> Optional[User]:
|
|
"""Get user by ID."""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_by_email(self, email: str) -> Optional[User]:
|
|
"""Get user by email."""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def save(self, user: User) -> User:
|
|
"""Save or update user."""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def delete(self, user_id: int) -> bool:
|
|
"""Delete user."""
|
|
pass
|
|
|
|
# Implementation (in infrastructure/database/repositories/)
|
|
class UserRepository(IUserRepository):
|
|
def __init__(self, session: Session):
|
|
self._session = session
|
|
|
|
def get_by_id(self, user_id: int) -> Optional[User]:
|
|
model = self._session.query(UserModel).filter_by(id=user_id).first()
|
|
return self._to_entity(model) if model else None
|
|
|
|
def save(self, user: User) -> User:
|
|
model = self._to_model(user)
|
|
self._session.add(model)
|
|
self._session.commit()
|
|
self._session.refresh(model)
|
|
return self._to_entity(model)
|
|
```
|
|
|
|
### 6.2 Unit of Work Pattern
|
|
|
|
```python
|
|
from contextlib import contextmanager
|
|
|
|
class UnitOfWork:
|
|
"""Manages database transactions."""
|
|
|
|
def __init__(self, session_factory):
|
|
self.session_factory = session_factory
|
|
self._session = None
|
|
|
|
def __enter__(self):
|
|
self._session = self.session_factory()
|
|
self.users = UserRepository(self._session)
|
|
self.services = ServiceRepository(self._session)
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
if exc_type:
|
|
self._session.rollback()
|
|
else:
|
|
self._session.commit()
|
|
self._session.close()
|
|
|
|
# Usage
|
|
with UnitOfWork(SessionLocal) as uow:
|
|
user = uow.users.get_by_id(1)
|
|
user.email = "new@email.com"
|
|
uow.users.save(user)
|
|
# Automatically commits on success
|
|
```
|
|
|
|
### 6.3 Factory Pattern
|
|
|
|
```python
|
|
from abc import ABC, abstractmethod
|
|
|
|
class ICloudProvider(ABC):
|
|
@abstractmethod
|
|
def create_server(self, config: ServerConfig) -> Server:
|
|
pass
|
|
|
|
class DigitalOceanProvider(ICloudProvider):
|
|
def create_server(self, config: ServerConfig) -> Server:
|
|
# Implementation
|
|
pass
|
|
|
|
class HetznerProvider(ICloudProvider):
|
|
def create_server(self, config: ServerConfig) -> Server:
|
|
# Implementation
|
|
pass
|
|
|
|
class CloudProviderFactory:
|
|
@staticmethod
|
|
def create(provider_type: str) -> ICloudProvider:
|
|
providers = {
|
|
"digitalocean": DigitalOceanProvider,
|
|
"hetzner": HetznerProvider,
|
|
"ovh": OVHProvider,
|
|
}
|
|
|
|
provider_class = providers.get(provider_type)
|
|
if not provider_class:
|
|
raise ValueError(f"Unknown provider: {provider_type}")
|
|
|
|
return provider_class()
|
|
|
|
# Usage
|
|
provider = CloudProviderFactory.create("digitalocean")
|
|
server = provider.create_server(config)
|
|
```
|
|
|
|
### 6.4 Strategy Pattern
|
|
|
|
```python
|
|
class PaymentStrategy(ABC):
|
|
@abstractmethod
|
|
def pay(self, amount: Decimal) -> PaymentResult:
|
|
pass
|
|
|
|
class ZarinpalPayment(PaymentStrategy):
|
|
def pay(self, amount: Decimal) -> PaymentResult:
|
|
# Zarinpal implementation
|
|
pass
|
|
|
|
class IdPayPayment(PaymentStrategy):
|
|
def pay(self, amount: Decimal) -> PaymentResult:
|
|
# IdPay implementation
|
|
pass
|
|
|
|
class PaymentProcessor:
|
|
def __init__(self, strategy: PaymentStrategy):
|
|
self._strategy = strategy
|
|
|
|
def process(self, amount: Decimal) -> PaymentResult:
|
|
return self._strategy.pay(amount)
|
|
|
|
# Usage
|
|
processor = PaymentProcessor(ZarinpalPayment())
|
|
result = processor.process(Decimal("100.00"))
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Best Practices
|
|
|
|
### 7.1 کد تمیز
|
|
|
|
```python
|
|
# ✅ GOOD: Clear and simple
|
|
def calculate_total_price(items: List[Item]) -> Decimal:
|
|
"""Calculate total price of items."""
|
|
return sum(item.price * item.quantity for item in items)
|
|
|
|
# ❌ BAD: Too complex
|
|
def calc(i):
|
|
t = 0
|
|
for x in i:
|
|
t += x[0] * x[1]
|
|
return t
|
|
```
|
|
|
|
### 7.2 Don't Repeat Yourself (DRY)
|
|
|
|
```python
|
|
# ❌ BAD: Repetition
|
|
def get_user_name(user_id: int) -> str:
|
|
session = SessionLocal()
|
|
user = session.query(User).filter_by(id=user_id).first()
|
|
session.close()
|
|
return user.name
|
|
|
|
def get_user_email(user_id: int) -> str:
|
|
session = SessionLocal()
|
|
user = session.query(User).filter_by(id=user_id).first()
|
|
session.close()
|
|
return user.email
|
|
|
|
# ✅ GOOD: Reusable
|
|
def get_user(user_id: int) -> User:
|
|
with get_db_context() as session:
|
|
return session.query(User).filter_by(id=user_id).first()
|
|
|
|
def get_user_name(user_id: int) -> str:
|
|
user = get_user(user_id)
|
|
return user.name if user else None
|
|
```
|
|
|
|
### 7.3 Single Responsibility
|
|
|
|
```python
|
|
# ❌ BAD: Multiple responsibilities
|
|
class User:
|
|
def save(self):
|
|
# Saves to database
|
|
pass
|
|
|
|
def send_email(self):
|
|
# Sends email
|
|
pass
|
|
|
|
def calculate_discount(self):
|
|
# Business logic
|
|
pass
|
|
|
|
# ✅ GOOD: Separated
|
|
class User:
|
|
# Just entity
|
|
pass
|
|
|
|
class UserRepository:
|
|
def save(self, user: User):
|
|
pass
|
|
|
|
class EmailService:
|
|
def send_welcome_email(self, user: User):
|
|
pass
|
|
|
|
class DiscountService:
|
|
def calculate_user_discount(self, user: User):
|
|
pass
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Testing Strategy
|
|
|
|
### 8.1 Test Pyramid
|
|
|
|
```
|
|
/\
|
|
/E2E\ 10% - End-to-End Tests
|
|
/------\
|
|
/Integr-\ 20% - Integration Tests
|
|
/----------\
|
|
/ Unit \ 70% - Unit Tests
|
|
```
|
|
|
|
### 8.2 Unit Test Example
|
|
|
|
```python
|
|
import pytest
|
|
from decimal import Decimal
|
|
|
|
class TestInvoiceCalculation:
|
|
def test_calculate_total_with_items(self):
|
|
# Arrange
|
|
items = [
|
|
InvoiceItem(name="Item 1", price=Decimal("10.00"), quantity=2),
|
|
InvoiceItem(name="Item 2", price=Decimal("5.00"), quantity=3),
|
|
]
|
|
invoice = Invoice(items=items)
|
|
|
|
# Act
|
|
total = invoice.calculate_total()
|
|
|
|
# Assert
|
|
assert total == Decimal("35.00")
|
|
|
|
def test_calculate_total_empty(self):
|
|
invoice = Invoice(items=[])
|
|
assert invoice.calculate_total() == Decimal("0.00")
|
|
```
|
|
|
|
### 8.3 Integration Test Example
|
|
|
|
```python
|
|
@pytest.mark.integration
|
|
class TestUserRepository:
|
|
def test_save_and_retrieve_user(self, db_session):
|
|
# Arrange
|
|
repository = UserRepository(db_session)
|
|
user = User(email="test@example.com", name="Test User")
|
|
|
|
# Act
|
|
saved_user = repository.save(user)
|
|
retrieved_user = repository.get_by_id(saved_user.id)
|
|
|
|
# Assert
|
|
assert retrieved_user is not None
|
|
assert retrieved_user.email == "test@example.com"
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Deployment Guide
|
|
|
|
### 9.1 Production Checklist
|
|
|
|
- [ ] همه تستها pass شدند
|
|
- [ ] Code coverage بالای 80%
|
|
- [ ] Security audit انجام شد
|
|
- [ ] Environment variables set شدند
|
|
- [ ] Database migrations اجرا شدند
|
|
- [ ] Monitoring setup شد
|
|
- [ ] Backup strategy تعریف شد
|
|
- [ ] SSL certificates نصب شدند
|
|
- [ ] Firewall rules تنظیم شدند
|
|
|
|
---
|
|
|
|
## 10. Troubleshooting
|
|
|
|
### 10.1 مشکلات رایج
|
|
|
|
#### Database Connection Error
|
|
|
|
**Problem**: `sqlalchemy.exc.OperationalError`
|
|
|
|
**Solution**:
|
|
1. Check DATABASE_URL in .env
|
|
2. Verify PostgreSQL is running
|
|
3. Check firewall rules
|
|
4. Test connection: `psql $DATABASE_URL`
|
|
|
|
#### Redis Connection Error
|
|
|
|
**Problem**: `redis.exceptions.ConnectionError`
|
|
|
|
**Solution**:
|
|
1. Check REDIS_URL in .env
|
|
2. Verify Redis is running: `redis-cli ping`
|
|
3. Check Redis password if set
|
|
|
|
---
|
|
|
|
## 11. مستندسازی تغییرات
|
|
|
|
### 11.1 Commit Message Format
|
|
|
|
```
|
|
<type>(<scope>): <subject>
|
|
|
|
<body>
|
|
|
|
<footer>
|
|
```
|
|
|
|
**Types**:
|
|
- feat: ویژگی جدید
|
|
- fix: رفع باگ
|
|
- docs: تغییرات مستندات
|
|
- style: فرمتبندی
|
|
- refactor: بازنویسی
|
|
- test: اضافه کردن تست
|
|
- chore: کارهای نگهداری
|
|
|
|
**Example**:
|
|
```
|
|
feat(auth): add two-factor authentication
|
|
|
|
- Implement TOTP-based 2FA
|
|
- Add QR code generation for authenticator apps
|
|
- Add backup codes feature
|
|
|
|
Closes #123
|
|
```
|
|
|
|
### 11.2 CHANGELOG.md
|
|
|
|
تمام تغییرات باید در CHANGELOG.md ثبت شود:
|
|
|
|
```markdown
|
|
# Changelog
|
|
|
|
## [Unreleased]
|
|
|
|
## [1.0.0] - 2025-01-24
|
|
|
|
### Added
|
|
- User authentication system
|
|
- Two-factor authentication
|
|
- Password reset functionality
|
|
|
|
### Changed
|
|
- Improved database schema
|
|
- Updated UI components
|
|
|
|
### Fixed
|
|
- Payment gateway timeout issue
|
|
- Email verification bug
|
|
```
|
|
|
|
---
|
|
|
|
## پیوستها
|
|
|
|
### A. فایلهای مهم
|
|
|
|
- `docs/architecture/`: معماری سیستم
|
|
- `docs/development/`: راهنمای توسعه
|
|
- `docs/changelog/`: تاریخچه تغییرات
|
|
- `docs/api/`: مستندات API
|
|
|
|
### B. لینکهای مفید
|
|
|
|
- [Python PEP 8](https://pep8.org/)
|
|
- [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
|
|
- [SOLID Principles](https://en.wikipedia.org/wiki/SOLID)
|
|
|
|
---
|
|
|
|
**این handbook باید همیشه بهروز نگه داشته شود.**
|
|
|