subscription/views.py
- PlansListView: served from cache (subscription:plans:v1, 1h TTL);
plans change ~never and the list is read on every subscription screen.
subscription/receivers.py (new)
- post_save/post_delete on Plan -> cache.delete(PLANS_CACHE_KEY).
subscription/apps.py
- SubscriptionConfig.ready() imports receivers.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Tadrisino API
بکاند اپلیکیشن آموزشی Tadrisino — Django + Django REST Framework.
احراز هویت با OTP، محتوای درسی و پیشرفت کاربر، دستیار هوش مصنوعی، اشتراک و پرداخت، تخفیف، اعلانها، همکاری در فروش، پشتیبانی و حساب خانواده.
| اپ | مسئولیت |
|---|---|
accounts |
احراز هویت، session، پروفایل کاربر |
content |
پایهها، مباحث، درسها، سوالها، پیشرفت |
progress |
آمار، لیدربرد، streak |
ai_tutor |
مکالمات دستیار هوش مصنوعی |
rag |
لایهی RAG: بازیابی از Qdrant + تولید با GPT، پشتِ POST /api/ai/ask |
subscription / payment / discount |
پلن، سفارش، تراکنش، کد تخفیف |
notifications, affiliate, support, family |
امکانات جانبی |
statuslog |
لاگ عمومی تغییر status، مستقل از بقیهی اپها |
۱. راهاندازی محیط توسعه
پیشنیازها
- پایتون ۳.۱۲
- pip
تنظیم محیط
python3 -m venv venv
source venv/bin/activate # ویندوز: venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env
.env.example (تمام متغیرهایی که واقعاً توسط اپ خونده میشن):
DJANGO_DEBUG=1
DJANGO_SECRET_KEY=
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1
CACHE_URL=
KAVENEGAR_API_KEY=
GRAFANA_ADMIN_PASSWORD=admin
مقادیر .env رو به شل خودتون export کنید (یا از direnv/python-dotenv استفاده کنید):
export DJANGO_DEBUG=1 # ویندوز (PowerShell): $env:DJANGO_DEBUG=1
DEBUGدیفالتشFalseاست. برای فعالکردنِ کمککنندههای dev-only در Swagger (DEV_MASTER_OTPو فیلدِdevOtpتوی پاسخها)، محلیDJANGO_DEBUG=1رو ست کنید.
سریعترین راه اجرای پروژه
python manage.py migrate
python manage.py runserver
اپ روی http://127.0.0.1:8000 بالا میاد.
مایگریشنها
python manage.py migrate
دیتای تستی (Seed)
یک دیتاست کوچک و idempotent میسازه که همهی اپها رو پوشش میده (کاربر، محتوا، پیشرفت،
اشتراک، پرداخت، تخفیف، دستیار هوش مصنوعی، اعلان، افیلیت، پشتیبانی، خانواده). اجرای مکرر
امن است — با get_or_create هیچ رکورد تکراریای نمیسازه. پیشفرض فقط وقتی DEBUG=True
اجرا میشه، مگر با --force.
python manage.py seed_test_data # لوکال (DEBUG=True)
python manage.py seed_test_data --force # staging (DEBUG=False)
python manage.py seed_test_data --reset # پاککردنِ دیتای قبلیِ seed و ساختِ دوباره
مستندات API
| Swagger UI | http://127.0.0.1:8000/api/docs/ |
| Redoc | http://127.0.0.1:8000/api/redoc/ |
| OpenAPI schema | http://127.0.0.1:8000/api/schema/ |
| پنل ادمین | http://127.0.0.1:8000/admin/ |
شروع سریع در Swagger:
POST /api/auth/sessionبا{"type":"guest","deviceId":"d_test1"}→ یکtokenبگیرید.- روی دکمهی Authorize بزنید و فقط خودِ
tokenرو (بدون کلمهی Bearer) وارد کنید. - برای تست لاگین با شماره:
POST /api/auth/otp/requestبزنید، یا در محیط توسعه کد 0000 رو با هر شمارهای درPOST /api/auth/loginامتحان کنید (dev-only، نیاز بهDEBUG=True).
دستورهای پرکاربرد
python manage.py createsuperuser # اختیاری، برای /admin
python manage.py test # اجرای کل تستسوییت
دستیار هوش مصنوعی (RAG)
POST /api/ai/ask پاسخ را از روی محتوای واقعیِ کتاب میسازد: embedding سوال →
جستجوی Qdrant محدود به همان درس/فصل → تولید با GPT. تیکههای استفادهشده در
usedChunks برمیگردند.
- نیازمندِ
OPENAI_API_KEYوQDRANT_API_KEYدر.env(اپrag؛ تنظیماتِOPENAI_*/RAG_*درconfig/settings.py). بدونِ کلید، همان پاسخِ stub قبلی. - تست در Swagger:
POST /api/ai/askبا{"userQuestion":"...","subject":"ریاضی","grade":"ششم","lessonNumber":2}. "stream": trueپاسخ را بهصورت SSE توکنبهتوکن میفرستد (قراردادِ JSON بدونِ این فلگ دستنخورده).python manage.py rag_catalogفهرستِ زندهی collectionهای Qdrant را نشان میدهد (فقطخواندنی).- افزودنِ محتوای خودمان:
POST /api/rag/ingest/textو/api/rag/ingest/pdf(داخلی، هدرِX-Internal-Key).
۲. راهنمای دیپلوی پروداکشن
متغیرهای محیطی موردنیاز
| متغیر | لازم در پروداکشن | توضیح |
|---|---|---|
DJANGO_DEBUG |
باید ستنشده یا 0 باشه |
دیفالتهای امنیتیِ پروداکشن رو فعال میکنه |
DJANGO_SECRET_KEY |
بله | بدونش وقتی DEBUG=False است اپ اصلاً بالا نمیاد |
DJANGO_ALLOWED_HOSTS |
بله | لیستِ host ها، کاما-جدا |
CACHE_URL |
بله | آدرسِ Redis، مثلاً redis://host:6379/0 — برای rate limitِ مشترک وقتی DEBUG=False لازمه |
KAVENEGAR_API_KEY |
بله | ارسال واقعیِ OTP از طریق کاوهنگار |
GRAFANA_ADMIN_PASSWORD |
فقط اگه از استکِ Grafana استفاده میکنید | بخشِ Docker پایین رو ببینید |
تنظیمات پروداکشن
DEBUGباید ست نشه (یا0باشه). باDEBUG=False:SECRET_KEYاجباریه — هیچ fallback ناامنی وجود نداره.CACHE_URL(Redis) اجباریه —LocMemCacheفقط برای dev هست.DEV_MASTER_OTPو فیلدِdevOtpتوی پاسخها غیرفعال میشن.
- برای ترافیک واقعی بهجای SQLیت پیشفرض، از یک دیتابیسِ پروداکشنگرید استفاده کنید (پروژه با همون SQLite شیپ میشه؛ عوضکردنِ engine یک تصمیمِ زیرساختیه، خارج از این ریپو).
- از طریق یک سرورِ WSGI/ASGI (مثلاً gunicorn) جلوی اپ سرو کنید — تنظیماتِ Docker موجود
همچنان
runserverاجرا میکنه و فقط برای dev/local مستند شده (پایین رو ببینید).
تنظیمات Docker/دیپلوی
docker-compose.yml موجود، اپ رو بههمراه یک استکِ لاگِ متمرکز
(Loki + Grafana Alloy + Grafana) اجرا میکنه. این یک تنظیمِ dev/local هست، نه دیپلویِ
پروداکشن (سرویسِ django همچنان runserver اجرا میکنه، نه یک سرورِ پروداکشن).
cp .env.example .env # اختیاری — بدونش compose از دیفالتهای dev استفاده میکنه
docker compose up --build
| سرویس | آدرس | توضیح |
|---|---|---|
| اپ Django | http://localhost:8000 |
|
| Grafana | http://localhost:3000 |
دسترسیِ anonymous admin، فقط محیطِ محلی |
| Loki | http://localhost:3100 |
ذخیرهسازیِ لاگ، در معرضِ کاربر نیست |
| Alloy | http://localhost:12345 |
رابطِ دیباگِ اختیاری |
ترتیبِ لازمِ بالا آمدن
Compose خودش این رو مدیریت میکنه:
- اول
lokiبالا میاد. alloyوgrafanaبعد ازlokiبالا میان (depends_on).djangoهیچ وابستگیای به استکِ لاگ نداره — خودشmigrateبعدrunserverرو اجرا میکنه و منتظرِ Loki/Alloy/Grafana نمیمونه.
دستورهای manage.py داخلِ Docker
اگه فقط از طریقِ Docker اجرا میکنید (بدونِ venv محلی)، python manage.py ... رو مستقیم
روی سیستم خودتون اجرا نکنید — باید داخلِ کانتینرِ django اجرا بشه:
docker compose exec django python manage.py createsuperuser
docker compose exec django python manage.py seed_test_data
docker compose exec django python manage.py test
(migrate نیازی به این نیست — طبقِ بالا، خودکار قبل از runserver اجرا میشه.)
مایگریشنها
python manage.py migrate --noinput
در Docker، این بهصورت خودکار بهعنوان بخشی از دستورِ سرویسِ django، قبل از runserver اجرا میشه.
راهنمای seed برای staging/تست
- هرگز
seed_test_dataرو روی یک دیتابیسِ پروداکشنِ واقعی اجرا نکنید. - روی staging (
DEBUG=False)، صریحاً با--forceاجرا کنید:python manage.py seed_test_data --force - برای پاککردن و ساختِ دوبارهی دیتای seed بین چرخههای تست، از
--resetاستفاده کنید. همهی رکوردهای seedشده در فیلدهای متنیِ قابلمشاهده با تگِ[SEED]مشخص شدن، برای شناساییِ راحتتر و پاکسازی.
چطور API دیپلویشده رو verify کنیم
curl -i https://<host>/api/schema/ # باید 200 برگردونه (OpenAPI schema)
curl -i https://<host>/api/docs/ # باید 200 برگردونه (Swagger UI)
curl -i -X POST https://<host>/api/auth/session \
-H "Content-Type: application/json" \
-d '{"type":"guest","deviceId":"verify-1"}' # باید یک token برگردونه
نکات مهمِ پروداکشن
DEV_MASTER_OTP(کد0000) و فیلدِdevOtpتوی پاسخها فقط وقتیDEBUG=Trueوجود دارن — قبل از رفتن روی محیطِ واقعی مطمئن بشیدDEBUGخاموشه.- احراز هویت با Bearer token امضاشده و stateless (
django.core.signing)، هماهنگ با مدلSession— بدون کتابخانهی JWT خارجی. accounts.Userیک مدل بیزنسیِ مستقله، نهAUTH_USER_MODELجنگو.- همهی لاگهای ساختاریافتهی درخواست (
method/path/status/duration/user، بدونِ بدنه/هدر/سکرت) روی stdout و — وقتیLOG_DIRست باشه (مثلِ داخلِ Docker) — در/var/log/django/app.logنوشته میشن؛ قابلِ مشاهده در Grafana از طریقِ استکِ بالا. POST /api/ai/askبا تنظیمِOPENAI_API_KEY/QDRANT_API_KEYپاسخِ واقعیِ RAG میدهد (اپrag)؛ بدونِ کلید همان stub. جزئیات: بخشِ «دستیار هوش مصنوعی (RAG)» بالاتر.- ارسالِ OTP از طریقِ کاوهنگار (
KAVENEGAR_API_KEY) انجام میشه؛ شکستِ ارسال بهجای موفقیتِ ساختگی، خطای صریحِ503برمیگردونه. - هر خطای پیشبینینشده (نه فقط خطاهای شناختهشدهی API) همیشه پاسخِ JSON برمیگردونه،
نه صفحهی HTML پیشفرضِ جنگو، و کامل با traceback لاگ میشه (
config/exceptions.py).