# 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/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` هشدارش می‌دهد.