[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:
453
docs/architecture/database-strategy.md
Normal file
453
docs/architecture/database-strategy.md
Normal file
@@ -0,0 +1,453 @@
|
||||
# استراتژی دیتابیس - انعطاف و مقیاسپذیری
|
||||
|
||||
## مشکل: انعطاف vs ثبات
|
||||
|
||||
با توجه به اینکه پروژه قرار است:
|
||||
- کلی feature جدید بگیره
|
||||
- Options و configurations متنوع داشته باشه
|
||||
- قابل توسعه سریع باشه
|
||||
|
||||
آیا PostgreSQL محدودیت ایجاد میکنه؟
|
||||
|
||||
## ✅ راه حل: Hybrid Database Architecture
|
||||
|
||||
### لایهبندی داده بر اساس نوع:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────┐
|
||||
│ Application Layer │
|
||||
└────┬─────────────┬──────────────┬────────────┘
|
||||
│ │ │
|
||||
┌────▼─────┐ ┌───▼────┐ ┌───▼────┐
|
||||
│PostgreSQL│ │MongoDB │ │ Redis │
|
||||
│ │ │ │ │ │
|
||||
│Critical │ │Flexible│ │ Cache │
|
||||
│Structured│ │Dynamic │ │Session │
|
||||
└──────────┘ └────────┘ └────────┘
|
||||
```
|
||||
|
||||
### Tier 1: PostgreSQL - Critical Business Data
|
||||
|
||||
**چی بریزیم توی PostgreSQL:**
|
||||
- User accounts
|
||||
- Financial data (invoices, transactions, wallet)
|
||||
- Service subscriptions
|
||||
- Audit logs
|
||||
- Anything که نیاز به ACID داره
|
||||
|
||||
```python
|
||||
# ❌ اینها رو NEVER توی MongoDB نذاریم
|
||||
class Invoice(BaseModel):
|
||||
id: int
|
||||
user_id: int
|
||||
amount: Decimal # MUST be ACID
|
||||
status: str
|
||||
paid_at: datetime
|
||||
```
|
||||
|
||||
**چرا PostgreSQL؟**
|
||||
- ✅ ACID Transactions
|
||||
- ✅ Data Integrity
|
||||
- ✅ Complex Joins
|
||||
- ✅ Proven for financial data
|
||||
|
||||
### Tier 2: PostgreSQL JSONB - Flexible Structured
|
||||
|
||||
**چی بریزیم توی JSONB:**
|
||||
- Service configurations
|
||||
- User preferences
|
||||
- Feature flags
|
||||
- Custom metadata
|
||||
- Plugin settings
|
||||
|
||||
```python
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
|
||||
class Service(BaseModel):
|
||||
# Structured
|
||||
id = Column(Integer, primary_key=True)
|
||||
user_id = Column(Integer)
|
||||
type = Column(String) # 'vps', 'hosting', etc.
|
||||
|
||||
# Flexible - هر چیزی میتونه باشه!
|
||||
config = Column(JSONB, default={})
|
||||
metadata = Column(JSONB, default={})
|
||||
|
||||
# Example 1: VPS
|
||||
vps = Service(
|
||||
type="vps",
|
||||
config={
|
||||
"cpu": 4,
|
||||
"ram": 8,
|
||||
"disk": 100,
|
||||
"os": "ubuntu-22.04"
|
||||
}
|
||||
)
|
||||
|
||||
# Example 2: WordPress Hosting
|
||||
wp = Service(
|
||||
type="wordpress",
|
||||
config={
|
||||
"domain": "example.com",
|
||||
"php_version": "8.2",
|
||||
"auto_update": True,
|
||||
"cdn_enabled": True,
|
||||
# Future features - بدون migration!
|
||||
"new_feature_2025": {"enabled": True}
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
**Query کردن JSONB:**
|
||||
|
||||
```python
|
||||
# پیدا کردن VPS های بالای 4 CPU
|
||||
services = session.query(Service).filter(
|
||||
Service.config['cpu'].astext.cast(Integer) >= 4
|
||||
).all()
|
||||
|
||||
# پیدا کردن WordPress با CDN enabled
|
||||
services = session.query(Service).filter(
|
||||
Service.config['cdn_enabled'].astext == 'true'
|
||||
).all()
|
||||
|
||||
# Index روی JSONB برای performance
|
||||
from sqlalchemy import Index
|
||||
|
||||
Index(
|
||||
'idx_service_config_cpu',
|
||||
Service.config['cpu'].astext.cast(Integer)
|
||||
)
|
||||
```
|
||||
|
||||
### Tier 3: MongoDB - Completely Dynamic
|
||||
|
||||
**چی بریزیم توی MongoDB:**
|
||||
- Logs و events
|
||||
- Analytics data
|
||||
- User activity tracking
|
||||
- System metrics
|
||||
- Unstructured data
|
||||
|
||||
```python
|
||||
# MongoDB - No schema!
|
||||
{
|
||||
"_id": "service_log_123",
|
||||
"service_id": 123,
|
||||
"timestamp": "2025-01-24T...",
|
||||
"events": [
|
||||
{
|
||||
"type": "cpu_spike",
|
||||
"value": 95,
|
||||
"custom_field_1": "...",
|
||||
# هر چیزی که بخوایم!
|
||||
}
|
||||
],
|
||||
"metrics": {
|
||||
# Structure آزاد
|
||||
"anything": "goes here"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## پیادهسازی در کد
|
||||
|
||||
### 1. Service با JSONB:
|
||||
|
||||
```python
|
||||
# src/infrastructure/database/models/service_model.py
|
||||
|
||||
from sqlalchemy import Column, Integer, String, ForeignKey, Enum as SQLEnum
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import relationship
|
||||
import enum
|
||||
|
||||
class ServiceType(enum.Enum):
|
||||
VPS = "vps"
|
||||
HOSTING = "hosting"
|
||||
WORDPRESS = "wordpress"
|
||||
DOMAIN = "domain"
|
||||
|
||||
class ServiceModel(BaseModel):
|
||||
__tablename__ = "services"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
||||
type = Column(SQLEnum(ServiceType), nullable=False)
|
||||
status = Column(String(20), nullable=False)
|
||||
|
||||
# Flexible configuration
|
||||
config = Column(JSONB, nullable=False, default={})
|
||||
metadata = Column(JSONB, nullable=False, default={})
|
||||
|
||||
# Relationships
|
||||
user = relationship("UserModel", back_populates="services")
|
||||
```
|
||||
|
||||
### 2. Repository با JSONB support:
|
||||
|
||||
```python
|
||||
# src/infrastructure/database/repositories/service_repository.py
|
||||
|
||||
from typing import Dict, Any, List
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
class ServiceRepository:
|
||||
def __init__(self, session: Session):
|
||||
self._session = session
|
||||
|
||||
def find_by_config(
|
||||
self,
|
||||
json_path: str,
|
||||
value: Any
|
||||
) -> List[ServiceModel]:
|
||||
"""Query by JSONB field.
|
||||
|
||||
Example:
|
||||
repo.find_by_config('cpu', 4)
|
||||
repo.find_by_config('cdn_enabled', True)
|
||||
"""
|
||||
return self._session.query(ServiceModel).filter(
|
||||
ServiceModel.config[json_path].astext == str(value)
|
||||
).all()
|
||||
|
||||
def update_config(
|
||||
self,
|
||||
service_id: int,
|
||||
config_updates: Dict[str, Any]
|
||||
) -> ServiceModel:
|
||||
"""Update service config partially."""
|
||||
service = self.get_by_id(service_id)
|
||||
if service:
|
||||
# Merge configs
|
||||
new_config = {**service.config, **config_updates}
|
||||
service.config = new_config
|
||||
self._session.commit()
|
||||
return service
|
||||
```
|
||||
|
||||
### 3. Domain Entity که flexible هست:
|
||||
|
||||
```python
|
||||
# src/core/domain/entities/service.py
|
||||
|
||||
from typing import Dict, Any, Optional
|
||||
from src.core.domain.entities.base import BaseEntity
|
||||
|
||||
class Service(BaseEntity):
|
||||
"""Service domain entity with flexible configuration."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id: Optional[int] = None,
|
||||
user_id: int = None,
|
||||
type: str = None,
|
||||
status: str = None,
|
||||
config: Dict[str, Any] = None,
|
||||
metadata: Dict[str, Any] = None,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(id=id, **kwargs)
|
||||
self.user_id = user_id
|
||||
self.type = type
|
||||
self.status = status
|
||||
self.config = config or {}
|
||||
self.metadata = metadata or {}
|
||||
|
||||
def get_config(self, key: str, default: Any = None) -> Any:
|
||||
"""Get config value safely."""
|
||||
return self.config.get(key, default)
|
||||
|
||||
def set_config(self, key: str, value: Any) -> None:
|
||||
"""Set config value."""
|
||||
self.config[key] = value
|
||||
|
||||
def update_config(self, updates: Dict[str, Any]) -> None:
|
||||
"""Update multiple config values."""
|
||||
self.config.update(updates)
|
||||
```
|
||||
|
||||
## مقایسه روشها
|
||||
|
||||
### Migration-based (Traditional SQL)
|
||||
|
||||
```python
|
||||
# ❌ هر feature جدید = migration جدید
|
||||
|
||||
# Migration 001
|
||||
ALTER TABLE services ADD COLUMN cpu INTEGER;
|
||||
|
||||
# Migration 002
|
||||
ALTER TABLE services ADD COLUMN ram INTEGER;
|
||||
|
||||
# Migration 003
|
||||
ALTER TABLE services ADD COLUMN new_feature VARCHAR(255);
|
||||
|
||||
# بعد از 100 feature = 100 migration! 😱
|
||||
```
|
||||
|
||||
### JSONB-based (Flexible SQL)
|
||||
|
||||
```python
|
||||
# ✅ هیچ migration لازم نیست!
|
||||
|
||||
# روز اول
|
||||
service.config = {"cpu": 4}
|
||||
|
||||
# یک ماه بعد
|
||||
service.config = {"cpu": 4, "ram": 8}
|
||||
|
||||
# یک سال بعد
|
||||
service.config = {
|
||||
"cpu": 4,
|
||||
"ram": 8,
|
||||
"new_feature_2025": True,
|
||||
"another_feature": {"nested": "data"}
|
||||
}
|
||||
|
||||
# بدون هیچ migration! 🎉
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. تصمیمگیری: PostgreSQL vs MongoDB vs JSONB
|
||||
|
||||
```python
|
||||
# PostgreSQL (Structured)
|
||||
✅ User authentication
|
||||
✅ Financial transactions
|
||||
✅ Invoices
|
||||
✅ Core business entities
|
||||
|
||||
# PostgreSQL JSONB
|
||||
✅ Service configurations
|
||||
✅ User preferences
|
||||
✅ Feature flags
|
||||
✅ Plugin settings
|
||||
✅ Custom fields
|
||||
|
||||
# MongoDB
|
||||
✅ Logs & Events
|
||||
✅ Analytics
|
||||
✅ User activity
|
||||
✅ System metrics
|
||||
✅ Temporary data
|
||||
```
|
||||
|
||||
### 2. JSONB Schema Validation (در Application)
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
class VPSConfig(BaseModel):
|
||||
"""Schema for VPS service config."""
|
||||
cpu: int
|
||||
ram: int
|
||||
disk: int
|
||||
os: str
|
||||
backups: Optional[bool] = False
|
||||
|
||||
class WordPressConfig(BaseModel):
|
||||
"""Schema for WordPress service config."""
|
||||
domain: str
|
||||
php_version: str
|
||||
auto_update: bool
|
||||
cdn_enabled: Optional[bool] = False
|
||||
|
||||
# Validation
|
||||
def validate_service_config(service_type: str, config: dict):
|
||||
"""Validate config based on service type."""
|
||||
schemas = {
|
||||
"vps": VPSConfig,
|
||||
"wordpress": WordPressConfig,
|
||||
}
|
||||
schema = schemas.get(service_type)
|
||||
if schema:
|
||||
return schema(**config) # Validates
|
||||
return config
|
||||
```
|
||||
|
||||
### 3. Indexing برای Performance
|
||||
|
||||
```python
|
||||
# در migration
|
||||
from alembic import op
|
||||
|
||||
def upgrade():
|
||||
# Create GIN index on JSONB
|
||||
op.execute("""
|
||||
CREATE INDEX idx_services_config_gin
|
||||
ON services USING GIN (config);
|
||||
""")
|
||||
|
||||
# Index specific keys
|
||||
op.execute("""
|
||||
CREATE INDEX idx_services_config_cpu
|
||||
ON services ((config->>'cpu'));
|
||||
""")
|
||||
```
|
||||
|
||||
## مزایا و معایب
|
||||
|
||||
### PostgreSQL + JSONB (پیشنهاد من)
|
||||
|
||||
**مزایا:**
|
||||
- ✅ انعطاف بالا (مثل MongoDB)
|
||||
- ✅ ACID transactions (برای billing امن)
|
||||
- ✅ Query قدرتمند
|
||||
- ✅ یک database کمتر = سادهتر
|
||||
- ✅ Performance خوب با indexing
|
||||
- ✅ Data integrity
|
||||
|
||||
**معایب:**
|
||||
- ❌ JSONB query ها کمی پیچیدهتر از SQL معمولی
|
||||
- ❌ نیاز به validation در application layer
|
||||
|
||||
### Hybrid (PostgreSQL + MongoDB)
|
||||
|
||||
**مزایا:**
|
||||
- ✅ Best of both worlds
|
||||
- ✅ Separation of concerns
|
||||
- ✅ Optimal performance
|
||||
|
||||
**معایب:**
|
||||
- ❌ پیچیدگی بیشتر
|
||||
- ❌ دو database = maintenance بیشتر
|
||||
- ❌ Consistency بین دو DB
|
||||
|
||||
## نتیجهگیری
|
||||
|
||||
**پیشنهاد برای پیکربند:**
|
||||
|
||||
```python
|
||||
"""
|
||||
Tier 1: PostgreSQL - Critical
|
||||
- Users, Auth
|
||||
- Invoices, Transactions
|
||||
- Wallet, Payments
|
||||
|
||||
Tier 2: PostgreSQL JSONB - Flexible
|
||||
- Service configs
|
||||
- User preferences
|
||||
- Custom settings
|
||||
|
||||
Tier 3: Redis - Cache
|
||||
- Sessions
|
||||
- Cache
|
||||
- Rate limiting
|
||||
|
||||
(Optional) Tier 4: MongoDB - Logs
|
||||
- Activity logs
|
||||
- System metrics
|
||||
- Analytics
|
||||
"""
|
||||
```
|
||||
|
||||
**در عمل:**
|
||||
- شروع با PostgreSQL + JSONB
|
||||
- اگر لازم شد، MongoDB اضافه میکنیم
|
||||
- ساده، flexible، و قابل توسعه
|
||||
|
||||
**PostgreSQL دست و پای ما رو نمیبنده، اگر از JSONB استفاده کنیم!** ✨
|
||||
|
||||
174
docs/architecture/overview.md
Normal file
174
docs/architecture/overview.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# معماری کلی سیستم
|
||||
|
||||
## نمای کلی
|
||||
|
||||
پلتفرم پیکربند بر اساس **Clean Architecture** طراحی شده که قابلیت تست، نگهداری و توسعه را به حداکثر میرساند.
|
||||
|
||||
## لایههای معماری
|
||||
|
||||
### 1. Domain Layer (هسته مرکزی)
|
||||
|
||||
مستقلترین لایه که شامل منطق کسبوکار خالص است:
|
||||
|
||||
**Components:**
|
||||
- **Entities**: موجودیتهای اصلی (User, Service, Invoice, Server)
|
||||
- **Value Objects**: Email, Money, Phone, IPAddress
|
||||
- **Domain Services**: منطق پیچیدهای که به چند entity مرتبط است
|
||||
- **Domain Events**: رویدادهای کسبوکار
|
||||
- **Exceptions**: خطاهای دامین
|
||||
|
||||
**قوانین:**
|
||||
- هیچ وابستگی به لایههای دیگر ندارد
|
||||
- فقط منطق کسبوکار
|
||||
- بدون وابستگی به framework
|
||||
- Pure Python
|
||||
|
||||
### 2. Application Layer (موارد استفاده)
|
||||
|
||||
**Components:**
|
||||
- **Use Cases**: موارد استفاده سیستم (RegisterUser, CreateInvoice)
|
||||
- **DTOs**: Data Transfer Objects
|
||||
- **Interfaces**: تعریف رابطهای سرویسها
|
||||
- **Validators**: اعتبارسنجی ورودیها
|
||||
|
||||
**قوانین:**
|
||||
- وابسته به Domain Layer
|
||||
- مستقل از Infrastructure
|
||||
- تعریف رابطهای مورد نیاز
|
||||
|
||||
### 3. Infrastructure Layer (جزئیات فنی)
|
||||
|
||||
**Components:**
|
||||
- **Database**: PostgreSQL + SQLAlchemy
|
||||
- **Cache**: Redis
|
||||
- **External APIs**: DigitalOcean, Hetzner, OVH
|
||||
- **Tasks**: Celery background jobs
|
||||
- **Security**: Authentication, Authorization
|
||||
- **Logging**: Structured logging
|
||||
|
||||
**قوانین:**
|
||||
- پیادهسازی interface های Application Layer
|
||||
- وابسته به تکنولوژیهای خاص
|
||||
- قابل تعویض
|
||||
|
||||
### 4. Presentation Layer (رابط کاربری)
|
||||
|
||||
**Components:**
|
||||
- **Web**: Reflex pages و components
|
||||
- **API**: REST endpoints (optional)
|
||||
- **State Management**: Reflex states
|
||||
|
||||
**قوانین:**
|
||||
- فقط به Application Layer وابسته
|
||||
- مستقل از Infrastructure details
|
||||
|
||||
## جریان داده
|
||||
|
||||
```
|
||||
User Action
|
||||
↓
|
||||
Presentation Layer (Reflex Component)
|
||||
↓
|
||||
Application Layer (Use Case)
|
||||
↓
|
||||
Domain Layer (Business Logic)
|
||||
↓
|
||||
Application Layer (Interfaces)
|
||||
↓
|
||||
Infrastructure Layer (Implementation)
|
||||
↓
|
||||
External Systems (Database, APIs)
|
||||
```
|
||||
|
||||
## Dependency Rule
|
||||
|
||||
وابستگیها همیشه به سمت داخل (به سمت Domain) هستند:
|
||||
|
||||
```
|
||||
Presentation → Application → Domain
|
||||
Infrastructure → Application → Domain
|
||||
```
|
||||
|
||||
**قانون طلایی**: لایههای داخلی هیچ چیز از لایههای خارجی نمیدانند.
|
||||
|
||||
## مزایای این معماری
|
||||
|
||||
1. **Testability**: هر لایه مستقلا قابل تست
|
||||
2. **Maintainability**: تغییرات محلی و جداسازی شده
|
||||
3. **Flexibility**: تعویض آسان تکنولوژیها
|
||||
4. **Scalability**: قابل مقیاسپذیری در هر لایه
|
||||
5. **Business Logic First**: تمرکز روی منطق کسبوکار
|
||||
|
||||
## Domain-Driven Design (DDD)
|
||||
|
||||
پروژه از اصول DDD استفاده میکند:
|
||||
|
||||
- **Ubiquitous Language**: زبان مشترک با کسبوکار
|
||||
- **Bounded Contexts**: محدودههای مشخص
|
||||
- **Aggregates**: مجموعههای یکپارچه
|
||||
- **Repositories**: دسترسی به داده
|
||||
- **Domain Events**: رویدادهای کسبوکار
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Core
|
||||
- **Language**: Python 3.11+
|
||||
- **Framework**: Reflex 0.4.0
|
||||
- **Database**: PostgreSQL 14+
|
||||
- **Cache**: Redis 7+
|
||||
- **ORM**: SQLAlchemy 2.0+
|
||||
|
||||
### Infrastructure
|
||||
- **Task Queue**: Celery 5.3+
|
||||
- **Testing**: pytest 7.4+
|
||||
- **Logging**: structlog
|
||||
- **API Client**: httpx
|
||||
|
||||
### External Services
|
||||
- **Cloud Providers**: DigitalOcean, Hetzner, OVH
|
||||
- **Payment**: Zarinpal, IDPay
|
||||
- **Monitoring**: Sentry, Prometheus
|
||||
|
||||
## Security Architecture
|
||||
|
||||
- **Authentication**: JWT + 2FA
|
||||
- **Authorization**: RBAC (Role-Based Access Control)
|
||||
- **Encryption**: Data at rest & in transit
|
||||
- **Secrets Management**: Environment variables
|
||||
- **Audit Logging**: تمام اقدامات مهم
|
||||
|
||||
## Scalability Strategy
|
||||
|
||||
### Horizontal Scaling
|
||||
- Load balancing برای Reflex
|
||||
- Database replication
|
||||
- Redis clustering
|
||||
- Celery workers
|
||||
|
||||
### Vertical Scaling
|
||||
- Connection pooling
|
||||
- Query optimization
|
||||
- Caching strategy
|
||||
- Async operations
|
||||
|
||||
## Monitoring & Observability
|
||||
|
||||
- **Metrics**: Request rate, response time, error rate
|
||||
- **Logs**: Structured logging با contextual info
|
||||
- **Tracing**: Request tracing
|
||||
- **Alerts**: Critical issues
|
||||
- **Dashboards**: Grafana/Prometheus
|
||||
|
||||
## Future Considerations
|
||||
|
||||
- Microservices architecture (در صورت نیاز)
|
||||
- Event-driven architecture
|
||||
- CQRS pattern
|
||||
- GraphQL API
|
||||
- Multi-tenancy
|
||||
|
||||
---
|
||||
|
||||
**نسخه**: 1.0.0
|
||||
**آخرین بروزرسانی**: 2025-01-24
|
||||
|
||||
Reference in New Issue
Block a user