تهيئة مشروع TaskFlow
التعليمات
في هذا المعمل، ستقوم بإعداد الأساس الكامل لواجهة TaskFlow البرمجية. بنهاية التمرين، سيكون لديك حزمة Docker Compose عاملة مع FastAPI وPostgreSQL 18 وRedis — جميعها متصلة ومتحقق منها عبر نقطة نهاية فحص الصحة.
الخطوة 1: إنشاء هيكل مجلدات المشروع
أنشئ هيكل المجلدات التالي لمشروع TaskFlow:
mkdir -p taskflow/app/{api/v1,models,schemas,core,tests}
cd taskflow
أنشئ ملفات __init__.py في كل مجلد حزمة Python:
touch app/__init__.py
touch app/api/__init__.py
touch app/api/v1/__init__.py
touch app/models/__init__.py
touch app/schemas/__init__.py
touch app/core/__init__.py
touch app/tests/__init__.py
الخطوة 2: إنشاء ملف المتطلبات
أنشئ requirements.txt مع قيود الإصدارات:
# إطار العمل الويب
fastapi>=0.136,<1.0
uvicorn[standard]>=0.34,<1.0
# قاعدة البيانات
sqlalchemy>=2.0.49,<2.1
psycopg2-binary>=2.9.10,<3.0
alembic>=1.18.4,<2.0
# التحقق والإعدادات
pydantic>=2.13,<3.0
pydantic-settings>=2.8,<3.0
# المصادقة
PyJWT>=2.10,<3.0
pwdlib[argon2]>=0.2,<1.0
# التخزين المؤقت
redis>=7.1.1,<9.0
# الاختبار
pytest>=9.0.2,<10.0
anyio>=4.0,<5.0
httpx>=0.28,<1.0
# الأدوات المساعدة
python-dotenv>=1.0.1,<2.0
python-multipart>=0.0.20,<1.0
أمران في هذا الملف أهم من الملف نفسه.
1. شغّل المُحلّل قبل أن تثق به. كل سطر أعلاه يسمّي حزمة حقيقية ومُصانة — وهذا
ليس كافياً. مجموعة القيود قد تصبح غير قابلة للتحقيق مع الوقت دون أن يكون أي سطر
فيها خاطئاً: حزمة ترفع الحد الأدنى الذي تدعمه من حزمة أخرى، فيصبح السقف الذي كان
صحيحاً يوم كُتب أدنى من الأرضية. يُبلغ pip عن هذا بالرسالة ResolutionImpossible،
ولن يلتقطه أي شيء آخر. افحص الملف وحده قبل أن تبني عليه أي شيء:
pip install --dry-run -r requirements.txt
ضع الأمر نفسه في CI. هو أرخص حارس ستضيفه على الإطلاق.
2. النطاقات ليست ملف قفل (lockfile). القيود أعلاه تحدد الإصدارات المسموح بها،
لا الإصدار الذي حصلت عليه فعلاً. شخصان يشغّلان pip install بفارق شهر سيحصلان على
بناءين مختلفين من هذا الملف، وهذا نقيض قابلية التكرار. النطاقات مكانها
requirements.txt، أما المجموعة المُحلّلة بدقة فمكانها ملف قفل تحفظه في المستودع —
يُنتَج بـ pip freeze أو pip-compile أو uv lock. انشر من القفل، وطوّر على النطاق.
لاحظ أن تبعية الاختبار هنا هي anyio وليست pytest-asyncio. الاختبارات التي ستكتبها
في المرحلة الرابعة تستخدم الواسم @pytest.mark.anyio، وهو من إضافة pytest التابعة
لـ AnyIO نفسها. وتثبيت إضافة async ثانية لا يستخدمها أحد هو تحديداً ما يصنع مشكلة
السقف المذكورة أعلاه.
الخطوة 3: إنشاء إعدادات البيئة
أنشئ ملف .env في جذر المشروع:
# التطبيق
APP_NAME=TaskFlow
APP_VERSION=0.1.0
DEBUG=true
# قاعدة البيانات
POSTGRES_USER=taskflow
POSTGRES_PASSWORD=taskflow_secret_2026
POSTGRES_DB=taskflow
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
DATABASE_URL=postgresql://taskflow:taskflow_secret_2026@postgres:5432/taskflow
# Redis
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_URL=redis://redis:6379/0
# JWT (أنشئ مفتاحك السري الخاص في بيئة الإنتاج!)
JWT_SECRET_KEY=dev-secret-key-change-in-production
JWT_ALGORITHM=HS256
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30
الخطوة 4: إنشاء وحدة الإعدادات
أنشئ app/core/config.py:
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
app_name: str = "TaskFlow"
app_version: str = "0.1.0"
debug: bool = False
# قاعدة البيانات
database_url: str = "postgresql://taskflow:taskflow_secret_2026@postgres:5432/taskflow"
# Redis
redis_url: str = "redis://redis:6379/0"
# JWT
jwt_secret_key: str = "dev-secret-key-change-in-production"
jwt_algorithm: str = "HS256"
jwt_access_token_expire_minutes: int = 30
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
settings = Settings()
الخطوة 5: إنشاء تطبيق FastAPI
أنشئ app/main.py:
from fastapi import FastAPI
from app.core.config import settings
app = FastAPI(
title=settings.app_name,
version=settings.app_version,
docs_url="/docs",
redoc_url="/redoc",
)
@app.get("/health")
async def health_check():
return {
"status": "healthy",
"app": settings.app_name,
"version": settings.app_version,
}
الخطوة 6: إنشاء ملف Dockerfile
أنشئ Dockerfile مع بناء متعدد المراحل:
# ---- المرحلة 1: البناء ----
FROM python:3.13-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
# ---- المرحلة 2: التشغيل ----
FROM python:3.13-slim AS runtime
WORKDIR /app
# نسخ الحزم المثبتة من مرحلة البناء
COPY --from=builder /install /usr/local
# نسخ كود التطبيق
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
الخطوة 7: إنشاء إعدادات Docker Compose
أنشئ docker-compose.yml:
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "8000:8000"
volumes:
- .:/app
env_file:
- .env
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
postgres:
image: postgres:18
environment:
POSTGRES_USER: ${POSTGRES_USER:-taskflow}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-taskflow_secret_2026}
POSTGRES_DB: ${POSTGRES_DB:-taskflow}
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U taskflow -d taskflow"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
redis:
image: redis:8-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
volumes:
postgres_data:
redis_data:
الخطوة 8: البناء والتشغيل
شغّل الحزمة الكاملة:
docker compose up --build -d
تحقق من نقطة نهاية فحص الصحة:
curl http://localhost:8000/health
يجب أن ترى:
{
"status": "healthy",
"app": "TaskFlow",
"version": "0.1.0"
}
تحقق من توثيق الواجهة البرمجية المُنشأ تلقائيا بزيارة http://localhost:8000/docs في متصفحك.
الخطوة 9: التحقق من جميع الخدمات
تحقق أن جميع الحاويات تعمل:
docker compose ps
يجب أن تظهر جميع الخدمات الثلاث (app، postgres، redis) بحالة Up (healthy).
ماذا تقدّم
المحرر يحتوي مسبقاً على 6 أقسام ملفات مع تعليقات TODO. استبدل كل TODO بالكود الفعلي. سيقوم المقيّم الذكي بتقييم كل قسم وفقاً لمعايير التقييم.