[INIT-001] Initial project setup with Clean Architecture (feat)
Some checks 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
Some checks 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
- Implemented Clean Architecture with Domain, Application, Infrastructure, Presentation layers - Added comprehensive project structure following SOLID principles - Created Kubernetes deployment with Helm charts (HPA, PDB, NetworkPolicy) - Configured ArgoCD for automated deployment (production + staging) - Implemented CI/CD pipeline with GitHub Actions - Added comprehensive documentation (handbook, architecture, coding standards) - Configured PostgreSQL, Redis, Celery for backend services - Created modern landing page with Persian fonts (Vazirmatn) - Added Docker multi-stage build for production - Configured development tools (pytest, black, flake8, mypy, isort) - Added pre-commit hooks for code quality - Implemented Makefile for common operations
This commit is contained in:
902
docs/handbook.md
Normal file
902
docs/handbook.md
Normal file
@@ -0,0 +1,902 @@
|
||||
# پروژه پیکربند - 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 production
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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 باید همیشه بهروز نگه داشته شود.**
|
||||
|
||||
Reference in New Issue
Block a user