153 lines
9.0 KiB
Markdown
153 lines
9.0 KiB
Markdown
# Tadrisino API
|
||
|
||
بکاندِ اپلیکیشنِ آموزشیِ تدریسینو — یک REST API روی Django که برنامهی درسی،
|
||
آزمونها، پیشرفتِ کاربر، دستیارِ هوشِ مصنوعی، اشتراک و پرداخت را سرو میکند.
|
||
|
||
فرانتاند ریپوی جداگانهای است ([`MathApp_frontend`](https://gitea.tadrisino2.ir/Tadrisino/MathApp_frontend)).
|
||
**قراردادِ بینِ دو طرف، اسکیمای OpenAPI همین ریپوست** — نه حافظهی کسی، نه یک
|
||
فایلِ دستی. هر تغییری در API باید از آنجا دیده شود.
|
||
|
||
| | |
|
||
|---|---|
|
||
| **وضعیت** | روی پروداکشن، در حالِ سرویسدهی |
|
||
| **آدرسِ زنده** | `https://mathapi.tadrisino2.ir` · [سلامت](https://mathapi.tadrisino2.ir/api/health) |
|
||
| **استک** | Python 3.11+ · Django 5.2 · DRF · SQLite · Qdrant (RAG) |
|
||
| **API** | ۶۱ اندپوینت · مستنداتِ زنده در `/api/docs/` |
|
||
| **تست** | ۶۸۵ تست، همه سبز (`python manage.py test`) |
|
||
| **محتوا** | ۸ پایه · ۵۸ فصل · ۲۶۳ نود · ۲٬۶۱۷ درس · ۲٬۵۴۵ سوال |
|
||
|
||
---
|
||
|
||
## شروعِ سریع
|
||
|
||
```bash
|
||
python3 -m venv venv && source venv/bin/activate
|
||
pip install -r requirements.txt
|
||
cp .env.example .env # برای توسعهی محلی: DJANGO_DEBUG=1 را ست کنید
|
||
python manage.py migrate
|
||
python manage.py seed_content # برنامهی درسی و سوالهای واقعی از content/seed/
|
||
python manage.py runserver
|
||
```
|
||
|
||
سرویس روی `http://127.0.0.1:8000` بالا میآید. `.env` خودکار خوانده میشود —
|
||
لازم نیست چیزی را `export` کنید.
|
||
|
||
| | |
|
||
|---|---|
|
||
| Swagger UI | `/api/docs/` |
|
||
| Redoc | `/api/redoc/` |
|
||
| اسکیمای OpenAPI | `/api/schema/` |
|
||
| پنلِ ادمین | `/admin/` |
|
||
| سلامتِ سرویس | `/api/health` |
|
||
|
||
**اولین درخواست در Swagger:** `POST /api/auth/session` با
|
||
`{"type":"guest","deviceId":"d_test1"}` بزنید، `token` را بردارید، روی
|
||
**Authorize** کلیک کنید و همان رشته را (بدونِ کلمهی `Bearer`) وارد کنید.
|
||
|
||
دستورهای پرکاربردِ دیگر:
|
||
|
||
```bash
|
||
python manage.py test # کلِ تستسوییت
|
||
python manage.py createsuperuser # دسترسی به /admin
|
||
python manage.py seed_test_data # دادهی ساختگی برای توسعه (فقط محلی)
|
||
```
|
||
|
||
---
|
||
|
||
## معماری
|
||
|
||
هر اپ یک مسئولیت دارد و مدلهای خودش را نگه میدارد:
|
||
|
||
| اپ | مسئولیت |
|
||
|---|---|
|
||
| `accounts` | هویت، session، ورود با OTP |
|
||
| `content` | برنامهی درسی، درس، سوال، پیشرفت روی نقشه |
|
||
| `progress` | آمار، لیدربرد، streak، شخصیتهای بازی |
|
||
| `ai_tutor` · `rag` | دستیارِ هوشِ مصنوعی: بازیابی از Qdrant + تولید با GPT |
|
||
| `subscription` · `payment` · `discount` | پلن، سفارش، تراکنش، کدِ تخفیف |
|
||
| `notifications` · `affiliate` · `support` · `family` · `campaigns` | امکاناتِ جانبی |
|
||
| `statuslog` | لاگِ عمومیِ تغییرِ وضعیت، مستقل از بقیه |
|
||
| `config` | تنظیمات، روتهای اصلی، middleware |
|
||
|
||
سه تصمیمِ معماری که غیرِبدیهیاند و دانستنشان لازم است:
|
||
|
||
- **احرازِ هویت، سیستمِ خودمان است نه جنگو.** توکنِ bearerِ امضاشده و stateless
|
||
با `django.core.signing` (بدونِ کتابخانهی JWT)، پشتیبانیشده با مدلِ
|
||
`accounts.Session`. `accounts.User` عمداً `AUTH_USER_MODEL` **نیست** — یک
|
||
مدلِ بیزنسیِ مستقل است. هدرِ نامعتبر یعنی درخواستِ ناشناس، نه خطا؛ هر ویو
|
||
خودش تصمیم میگیرد که آیا ورود لازم است یا نه (`accounts/authentication.py`).
|
||
- **اپها با قرارداد از هم جدا شدهاند، نه با ForeignKey.** ارجاعِ بینِ اپها با
|
||
`user_id` و `object_id` + `label` انجام میشود تا هر اپ بعداً قابلِ جدا شدن
|
||
باشد. **FK بینِ اپها اضافه نکنید.**
|
||
- **محدودیتِ نرخ (throttle) متمرکز است.** هر اندپوینتِ حساس یک
|
||
`throttle_scope` دارد و نرخش در `REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']`
|
||
داخلِ `config/settings.py` تعریف میشود. اندپوینتِ جدید یعنی **هر دو**.
|
||
|
||
جزئیاتِ بیشتر: [`docs/architecture.md`](docs/architecture.md).
|
||
|
||
---
|
||
|
||
## دیپلوی
|
||
|
||
کلِ انتشار یک خط است:
|
||
|
||
```bash
|
||
ssh -t administrator@78.38.35.249 \
|
||
'cd ~/mathapp-v2 && ./deploy.sh; sudo systemctl restart zareian-mathapp'
|
||
```
|
||
|
||
`deploy.sh` کد را میگیرد، وابستگیها را نصب میکند، مهاجرت میزند، محتوا را
|
||
seed میکند، فایلهای استاتیک را جمع میکند و در پایان **ثابت میکند که سرویس
|
||
واقعاً ریاستارت شده** — نه اینکه فقط فرض کند. ریاستارت جداست چون `sudo`
|
||
داخلِ اسکریپت نمیتواند رمز بپرسد.
|
||
|
||
پس از هر انتشار، از بیرون و بدونِ SSH تأیید کنید:
|
||
|
||
```bash
|
||
curl https://mathapi.tadrisino2.ir/api/health
|
||
```
|
||
|
||
`200` یعنی سالم، `503` یعنی چیزی واقعاً خراب است. هیچ سکرتی برنمیگرداند.
|
||
|
||
رویهی کامل — متغیرهای محیطی، ورودِ توسعهدهندهها، بکاپ، عیبیابی:
|
||
[`docs/operations.md`](docs/operations.md).
|
||
|
||
---
|
||
|
||
## مستندات
|
||
|
||
| سند | موضوع |
|
||
|---|---|
|
||
| [`docs/operations.md`](docs/operations.md) | دیپلوی، متغیرهای محیطی، سلامت، بکاپ، ورودِ توسعهدهندهها |
|
||
| [`docs/technical-handbook.md`](docs/technical-handbook.md) · [PDF](docs/technical-handbook.pdf) | **مستندِ فنیِ کامل و تحویلِ پروژه:** معماری، مدلِ سناریو و رابطهای، API، Qdrant، گیمیفیکیشن، امنیت، استقرار، مقیاس |
|
||
| [`docs/security-before-production.md`](docs/security-before-production.md) | **پیش از کاربرِ واقعی:** هرچه برای دمو عمداً باز مانده، خطرش و راهِ بستنش |
|
||
| [`docs/content-authoring.md`](docs/content-authoring.md) | افزودن و ویرایشِ محتوا از پنلِ ادمین، ساختِ انبوهِ سوال |
|
||
| [`docs/architecture.md`](docs/architecture.md) | تصمیمهای معماری و دلیلشان |
|
||
| [`docs/frontend/README.md`](docs/frontend/README.md) | راهنمای اتصالِ فرانتاند + کلاینتِ تایپدار |
|
||
| [`docs/docker.md`](docs/docker.md) | استکِ لاگِ محلی (Loki + Alloy + Grafana) |
|
||
| [`docs/extraction-playbook.md`](docs/extraction-playbook.md) | استخراجِ محتوا از کتاب با مدلِ ویژن و هزینههایش |
|
||
|
||
---
|
||
|
||
## محدودیتهای شناختهشده
|
||
|
||
اینها عمداً نوشته شدهاند تا کسی دوباره کشفشان نکند:
|
||
|
||
- **دیتابیس هنوز SQLite است**، نه Postgres. برای حجمِ فعلی کافیست، ولی
|
||
تکنویسنده بودنش اولین گلوگاهِ مقیاس است.
|
||
- **بکاپِ خودکار وجود ندارد.** `db.sqlite3` در گیت نیست و تنها نسخهی دادهی
|
||
کاربران است. روشِ بکاپِ دستی در [`docs/operations.md`](docs/operations.md)
|
||
آمده؛ خودکار کردنش اولین کارِ ارزشمندِ بعدی است.
|
||
- **`CACHE_URL` روی سرور ست نشده**، پس محدودیتِ نرخ بینِ workerها مشترک نیست.
|
||
Redis روی همان ماشین بالاست. `/api/health` این را هشدار میدهد.
|
||
- **`KAVENEGAR_API_KEY` تنظیم نشده**، پس `POST /api/auth/otp/request` برای
|
||
شمارههای واقعی `503` میدهد. راهِ ورودِ تیمِ توسعه در
|
||
[`docs/operations.md`](docs/operations.md) توضیح داده شده.
|
||
- **پوششِ محتوا یکدست نیست.** پایههای هشتم تا دوازدهم کاملند (هر نود چهار
|
||
سوال)؛ در پایههای سوم/ششم/هفتم ۳۹ نود از ۱۴۵ کمتر از چهار سوال دارند —
|
||
هیچکدام خالی نیست، پس روی نقشه نودِ غیرقابلِ بازی وجود ندارد.
|
||
- **محتوای ویدیویی وجود ندارد**، هرچند `Lesson.kind` و `video_url` میتوانند
|
||
بیانش کنند.
|
||
- **`DEV_MASTER_OTP` (کد `0000`) باید پشتِ `DEBUG` بماند.** روشن بودنش یعنی هر
|
||
کسی میتواند بهجای هر کاربری وارد شود. `/api/health` هشدارش میدهد.
|