118 lines
7.8 KiB
Markdown
118 lines
7.8 KiB
Markdown
# 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` مقیّد شود.**
|
||
- **لاگِ ساختاریافته**: همهی درخواستهای `/api/` بهصورتِ JSON لاگ میشن (متد/مسیر/وضعیت/مدت/کاربر، بدونِ بدنه/هدر/سکرت)؛ قابلِ مشاهده و جستوجو در Grafana (بخشِ Docker بالا).
|
||
|
||
## قبل از دیپلوی پروداکشن
|
||
|
||
- [x] `DEBUG` و `SECRET_KEY` و `ALLOWED_HOSTS` از env خونده میشن (دیفالتِ
|
||
`DEBUG` روی `False` است)
|
||
- [x] `DEV_MASTER_OTP` و برگردوندنِ `devOtp` توی پاسخ، فقط وقتی `DEBUG=True`
|
||
فعالن؛ در پروداکشن غیرفعالن
|
||
- [x] rate limit (throttle) روی endpointهای احرازهویت و بقیهی endpointهای
|
||
حساسِ پروژه (پرداخت، خرید اشتراک، تخفیف، AI، محتوا، خانواده،
|
||
پشتیبانی، affiliate، …) پیادهسازی شده؛ برای کاربرهای مهمان بر
|
||
اساسِ IP کلید میخوره تا چرخشِ حساب مهمان دورش نزنه
|
||
- [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 ها با توجه به ترافیکِ واقعی
|