Zareian 96f0204fcf refill hearts like Duolingo: one every 5 hours, all of them after 24
Each heart used to take 24 hours, so a student who lost all five waited up to
five days. Now one heart returns every 5 hours, and 24 hours after the first
heart was lost they all come back at once (the owner's call). /api/user/hearts
reports both times (nextRefillAt, fullRefillAt); an existing timer longer than
5 hours is shortened the first time it is read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 06:58:39 +03:30

Tadrisino API

بک‌اندِ اپلیکیشنِ آموزشیِ تدریسینو — یک REST API روی Django که برنامه‌ی درسی، آزمون‌ها، پیشرفتِ کاربر، دستیارِ هوشِ مصنوعی، اشتراک و پرداخت را سرو می‌کند.

فرانت‌اند ریپوی جداگانه‌ای است (MathApp_frontend). قراردادِ بینِ دو طرف، اسکیمای OpenAPI همین ریپوست — نه حافظه‌ی کسی، نه یک فایلِ دستی. هر تغییری در API باید از آنجا دیده شود.

وضعیت روی پروداکشن، در حالِ سرویس‌دهی
آدرسِ زنده https://api.math.tadrisino2.ir · سلامت
استک Python 3.11+ · Django 5.2 · DRF · SQLite · Qdrant (RAG)
API ۵۶ اندپوینت · مستنداتِ زنده در /api/docs/
تست ۴۸۹ تست، همه سبز (python manage.py test)
محتوا ۸ پایه · ۵۸ فصل · ۲۶۳ نود · ۲٬۶۱۷ درس · ۲٬۴۶۳ سوال

شروعِ سریع

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) وارد کنید.

دستورهای پرکاربردِ دیگر:

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.


دیپلوی

کلِ انتشار یک خط است:

ssh -t administrator@78.38.35.249 \
  'cd ~/mathapp-v2 && ./deploy.sh; sudo systemctl restart zareian-mathapp'

deploy.sh کد را می‌گیرد، وابستگی‌ها را نصب می‌کند، مهاجرت می‌زند، محتوا را seed می‌کند، فایل‌های استاتیک را جمع می‌کند و در پایان ثابت می‌کند که سرویس واقعاً ری‌استارت شده — نه اینکه فقط فرض کند. ری‌استارت جداست چون sudo داخلِ اسکریپت نمی‌تواند رمز بپرسد.

پس از هر انتشار، از بیرون و بدونِ SSH تأیید کنید:

curl https://api.math.tadrisino2.ir/api/health

200 یعنی سالم، 503 یعنی چیزی واقعاً خراب است. هیچ سکرتی برنمی‌گرداند.

رویه‌ی کامل — متغیرهای محیطی، ورودِ توسعه‌دهنده‌ها، بکاپ، عیب‌یابی: docs/operations.md.


مستندات

سند موضوع
docs/operations.md دیپلوی، متغیرهای محیطی، سلامت، بکاپ، ورودِ توسعه‌دهنده‌ها
docs/content-authoring.md افزودن و ویرایشِ محتوا از پنلِ ادمین، ساختِ انبوهِ سوال
docs/architecture.md تصمیم‌های معماری و دلیلشان
docs/frontend/README.md راهنمای اتصالِ فرانت‌اند + کلاینتِ تایپ‌دار
docs/docker.md استکِ لاگِ محلی (Loki + Alloy + Grafana)
docs/extraction-playbook.md استخراجِ محتوا از کتاب با مدلِ ویژن و هزینه‌هایش

محدودیت‌های شناخته‌شده

اینها عمداً نوشته شده‌اند تا کسی دوباره کشفشان نکند:

  • دیتابیس هنوز SQLite است، نه Postgres. برای حجمِ فعلی کافی‌ست، ولی تک‌نویسنده بودنش اولین گلوگاهِ مقیاس است.
  • بکاپِ خودکار وجود ندارد. db.sqlite3 در گیت نیست و تنها نسخه‌ی داده‌ی کاربران است. روشِ بکاپِ دستی در docs/operations.md آمده؛ خودکار کردنش اولین کارِ ارزشمندِ بعدی است.
  • CACHE_URL روی سرور ست نشده، پس محدودیتِ نرخ بینِ workerها مشترک نیست. Redis روی همان ماشین بالاست. /api/health این را هشدار می‌دهد.
  • KAVENEGAR_API_KEY تنظیم نشده، پس POST /api/auth/otp/request برای شماره‌های واقعی 503 می‌دهد. راهِ ورودِ تیمِ توسعه در docs/operations.md توضیح داده شده.
  • پوششِ محتوا یکدست نیست. پایه‌های هشتم تا دوازدهم کاملند (هر نود چهار سوال)؛ در پایه‌های سوم/ششم/هفتم ۳۹ نود از ۱۴۵ کمتر از چهار سوال دارند — هیچ‌کدام خالی نیست، پس روی نقشه نودِ غیرقابلِ بازی وجود ندارد.
  • محتوای ویدیویی وجود ندارد، هرچند Lesson.kind و video_url می‌توانند بیانش کنند.
  • DEV_MASTER_OTP (کد 0000) باید پشتِ DEBUG بماند. روشن بودنش یعنی هر کسی می‌تواند به‌جای هر کاربری وارد شود. /api/health هشدارش می‌دهد.
Description
No description provided
Readme 67 MiB
Languages
Python 96.8%
Shell 2.2%
HTML 0.9%