# Tadrisino API بک‌اند اپلیکیشن آموزشی Tadrisino — Django + Django REST Framework. احراز هویت با OTP، محتوای درسی و پیشرفت کاربر، دستیار هوش مصنوعی، اشتراک و پرداخت، تخفیف، اعلان‌ها، همکاری در فروش، پشتیبانی و حساب خانواده. ## اجرا ```bash python3 -m venv venv source venv/bin/activate # ویندوز: venv\Scripts\activate pip install -r requirements.txt # مهم: از این به بعد DEBUG دیفالتش False هست (برای امنیتِ پروداکشن). # برای اجرای محلی/تست با Swagger (که به DEV_MASTER_OTP و devOtp توی # پاسخ نیاز داره)، این env var رو ست کنید: export DJANGO_DEBUG=1 # ویندوز (PowerShell): $env:DJANGO_DEBUG=1 python manage.py migrate python manage.py createsuperuser # اختیاری، برای /admin python manage.py runserver ``` در پروداکشن، `DJANGO_DEBUG` رو ست نکنید (یا `0` بذارید) و حتماً `DJANGO_SECRET_KEY` و `DJANGO_ALLOWED_HOSTS` (کاما-جدا) رو هم از env بدید. ## اجرا با Docker (اپ + استکِ لاگِ متمرکز) برای اجرای محلی، در کنارِ Django یک استکِ لاگِ متمرکز هم فراهم شده: `Loki` (ذخیره‌سازیِ لاگ) + `Grafana Alloy` (جمع‌آوریِ لاگ از فایلِ اپ) + `Grafana` (جستجو/فیلترِ لاگ‌ها). این فقط برای dev/local هست، نه یک تنظیمِ پروداکشن (مثلاً هنوز از `runserver` استفاده می‌شه، نه gunicorn). ```bash # اختیاری: تنظیماتِ خودتون رو ست کنید (وگرنه دیفالت‌های dev استفاده می‌شن) cp .env.example .env docker compose up --build ``` - اپ Django: `http://localhost:8000` - Grafana: `http://localhost:3000` (بدونِ نیاز به لاگین، anonymous admin فعاله؛ فقط برای محیطِ محلی) داشبوردِ «Tadrisino Django Logs» به‌صورتِ خودکار در Grafana لود می‌شه و امکانِ فیلتر بر اساسِ سطحِ لاگ (`level`) و جستجوی متنی رو می‌ده. **جریانِ لاگ:** Django همون خطوطِ JSON موجود رو (بدونِ تغییرِ پیام‌ها یا محافظت‌های حساسیتی) هم روی stdout و هم در `/var/log/django/app.log` (یک ولومِ Docker) می‌نویسه ← Grafana Alloy این فایل رو می‌خونه ← به Loki push می‌کنه ← Grafana از Loki می‌خونه. جزئیاتِ بیشتر در کامنت‌های بالای `docker-compose.yml`، `docker/alloy/config.alloy` و `config/settings.py` (بخشِ `LOG_DIR`). اجرای بدونِ Docker (روش قبلی، بالای همین فایل) دقیقاً همون‌طور که بود کار می‌کنه — `LOG_DIR` فقط داخلِ Docker ست می‌شه. ## مستندات API | | | |---|---| | Swagger UI | `http://127.0.0.1:8000/api/docs/` | | Redoc | `http://127.0.0.1:8000/api/redoc/` | | پنل ادمین | `http://127.0.0.1:8000/admin/` | **شروع سریع در Swagger:** 1. `POST /api/auth/session` با `{"type":"guest","deviceId":"d_test1"}` → یک `token` بگیرید. 2. روی دکمه‌ی **Authorize** بزنید و فقط خودِ `token` رو (بدون کلمه‌ی Bearer) وارد کنید. 3. برای تست لاگین با شماره: `POST /api/auth/otp/request` بزنید، یا در محیط توسعه کد **0000** رو با هر شماره‌ای در `/api/auth/login` امتحان کنید. ## ساختار پروژه | اپ | مسئولیت | مدل‌های اصلی | |---|---|---| | `accounts` | هویت کاربر و session | `User`, `Profile`, `Session`, `OTPCode` | | `content` | محتوای درسی و پیشرفت روی درس | `Grade`, `Unit`, `Node`, `Lesson`, `Question`, `Choice`, `NodeProgress` | | `progress` | آمار، لیدربرد، streak | `UserStats`, `LeaderboardEntry`, `StreakRecord`, `UserHearts` | | `ai_tutor` | دستیار هوش مصنوعی | `Conversation`, `Message`, `MessageFeedback` | | `subscription` | پلن و اشتراک | `Plan`, `Subscription` | | `payment` | سفارش و تراکنش | `Order`, `Transaction` | | `discount` | کد تخفیف و آفر | `DiscountCode`, `Redemption`, `Offer`, `UserOffer` | | `notifications` | اعلان‌ها | `Notification` | | `affiliate` | همکاری در فروش | `AffiliateAccount`, `Conversion` | | `support` | تیکت و گزارش باگ | `BugReport`, `Ticket`, `TicketMessage` | | `family` | حساب خانواده / کنترل والدین | `FamilyLink`, `ParentalSettings`, `WeeklyReportLog` | | `statuslog` | لاگ عمومی تغییر status، مستقل از بقیه‌ی اپ‌ها | `StatusChangeLog` | | `config` | تنظیمات و url های اصلی پروژه | — | ## نکات فنی مهم - **احراز هویت**: Bearer token امضاشده و stateless (`django.core.signing`، بدون کتابخانه‌ی JWT خارجی)، هماهنگ با مدل `Session`. - **`accounts.User`** عمداً `AUTH_USER_MODEL` جنگو نیست؛ یک مدل بیزنسی مستقل است. - بین اپ‌ها به‌جای FK واقعی از ارجاع سبک (`user_id`, `object_id` + `label`) استفاده شده تا هر اپ در آینده قابل جدا شدن باشد. - `POST /api/ai/ask` فعلاً پاسخ stub برمی‌گرداند؛ محل اتصال مدل واقعی در `ai_tutor/views.py` (تابع `generate_tutor_answer`) مشخص شده. - `DEV_MASTER_OTP` (کد `0000`) فقط برای تست در توسعه است — **پیش از دیپلوی پروداکشن باید حذف یا به `DEBUG` مقیّد شود.** ## قبل از دیپلوی پروداکشن - [x] `DEBUG` و `SECRET_KEY` و `ALLOWED_HOSTS` از env خونده می‌شن (دیفالتِ `DEBUG` روی `False` است) - [x] `DEV_MASTER_OTP` و برگردوندنِ `devOtp` توی پاسخ، فقط وقتی `DEBUG=True` فعالن؛ در پروداکشن غیرفعالن - [x] rate limit (`ScopedRateThrottle`) روی `auth/otp/request` (۵/ساعت) و `auth/login` (۱۰/ساعت) اضافه شد - [x] IDOR در `GET /api/home` و `GET /api/progress/nodes` اصلاح شد: قبلاً بدون هیچ توکنی، با فرستادنِ `userId` دلخواه می‌شد آمار/پیشرفتِ هر کاربرِ دیگه‌ای رو خوند؛ حالا auth اجباریه و فقط خودِ کاربر یا والدِ تأییدشده‌اش (`FamilyLink` با `status='accepted'`) اجازه‌ی دسترسی دارن - [ ] دیتابیس Postgres به‌جای SQLite - [x] اتصال واقعی به سرویسِ پیامک برای ارسالِ OTP: دیگه استاب نیست؛ از طریق کاوه‌نگار (kavenegar.com) ارسال می‌شه (کلید از `KAVENEGAR_API_KEY`)، و هر شکست (شبکه/کلید/رد اپلیکیشنی) به‌جای موفقیتِ ساختگی، خطای صریح ۵۰۳ برمی‌گردونه - [ ] بررسیِ دوره‌ای throttle rate ها با توجه به ترافیکِ واقعی