Files
MathApp/README.md

115 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 ها با توجه به ترافیکِ واقعی