Files
MathApp/README.md
Zareian ae0375c26c make the API docs page answer a consumer's first questions, and fix a missing endpoint
The Swagger header was a list of features. That is what the project does, not
what a caller needs. It now opens with the three things anyone integrating
against this API asks first: how do I get a token, what does an error look like,
and when do I get rate limited -- plus the field-naming and date conventions,
and a note that the schema is the contract and clients should be generated from
it rather than written from memory. Swagger UI and Redoc both render Markdown,
so it is structured rather than one long paragraph, which also fixes how badly
the old mixed Persian/Latin line wrapped right-to-left.

Two defects surfaced while checking the rendered schema:

- /api/health was absent from the schema entirely. The trailing-slash alias was
  excluded with extend_schema(exclude=True)(HealthView), but that decorator
  mutates the class, and both routes pointed at the same class, so the canonical
  route disappeared with it. A subclass now carries the exclusion, and the
  endpoint is back, exactly once. Endpoint count is 56, not 55.
- One endpoint was tagged 'محتوا (content)' while every other content endpoint
  used 'Curriculum (content)', which split the group into two sections.

Tags are now declared with descriptions and ordered by the path a real user
takes, rather than alphabetically.

Comment pass over the codebase, keeping the substance and dropping the noise:
the "⚠️ اضافه شده" prefixes dated comments against a moment no current reader
shares; "فاز ۲ / بخش ۴" referenced a plan that no longer exists and only
repeated the app name on the next line; "فاز اول - ۴ از ۱۱ اپ" had drifted (there
are fourteen). INSTALLED_APPS is now grouped by responsibility. The
TEST_LOGIN_PHONES block in settings shrank from 29 lines to 8 now that the same
explanation lives in docs/operations.md and .env.example -- a comment beside the
code should carry what a code reader needs, not a copy of the runbook.

Checked mechanically that no comment references an identifier that no longer
exists: zero. The dated measurements in rag/services/ingest.py and
generate_questions_from_chunks.py were deliberately left alone -- a measurement
carrying the date it was taken is the useful kind.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 01:28:32 +03:30

151 lines
8.5 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
بک‌اندِ اپلیکیشنِ آموزشیِ تدریسینو — یک REST API روی Django که برنامه‌ی درسی،
آزمون‌ها، پیشرفتِ کاربر، دستیارِ هوشِ مصنوعی، اشتراک و پرداخت را سرو می‌کند.
فرانت‌اند ریپوی جداگانه‌ای است ([`MathApp_frontend`](https://gitea.tadrisino2.ir/Tadrisino/MathApp_frontend)).
**قراردادِ بینِ دو طرف، اسکیمای OpenAPI همین ریپوست** — نه حافظه‌ی کسی، نه یک
فایلِ دستی. هر تغییری در API باید از آنجا دیده شود.
| | |
|---|---|
| **وضعیت** | روی پروداکشن، در حالِ سرویس‌دهی |
| **آدرسِ زنده** | `https://api.math.tadrisino2.ir` · [سلامت](https://api.math.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://api.math.tadrisino2.ir/api/health
```
`200` یعنی سالم، `503` یعنی چیزی واقعاً خراب است. هیچ سکرتی برنمی‌گرداند.
رویه‌ی کامل — متغیرهای محیطی، ورودِ توسعه‌دهنده‌ها، بکاپ، عیب‌یابی:
[`docs/operations.md`](docs/operations.md).
---
## مستندات
| سند | موضوع |
|---|---|
| [`docs/operations.md`](docs/operations.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` هشدارش می‌دهد.