The API moved to mathapi.tadrisino2.ir on 2026-09-26 (nginx server_name changed at 23:22) and api.math.tadrisino2.ir no longer resolves. The code default for PUBLIC_BASE_URL and the docs' curl examples still named the dead host, so every paymentUrl, the Zarinpal callback and the Bazaar redirect the backend builds pointed nowhere. Historical status notes in CLAUDE.md keep the old name on purpose. config/tests.py now reads the API host from PUBLIC_BASE_URL instead of a literal. 624 tests green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
190 lines
12 KiB
Plaintext
190 lines
12 KiB
Plaintext
# نمونهی فایلِ تنظیمات — هم برای ماشینِ خودتان، هم برای سرور.
|
||
#
|
||
# cp .env.example .env
|
||
#
|
||
# تقریباً هیچکدام اجباری نیستند. هر چیزی که از قبل قابلِ تصمیم بود در خودِ
|
||
# کد پیشفرض شده: دامنهها، origin های مجاز، و کلیدِ امضا (اولین اجرا خودش
|
||
# یک کلیدِ تصادفی میسازد و در .django_secret_key نگه میدارد). حتی با یک
|
||
# فایلِ خالی هم سرویس بالا میآید.
|
||
#
|
||
# روی سرور، بعد از یکبار ساختنِ این فایل، هر آپدیت فقط:
|
||
# git pull && ./deploy.sh
|
||
|
||
# -----------------------------------------------------------------------
|
||
# پایه
|
||
# -----------------------------------------------------------------------
|
||
# DEBUG اینجا عمداً 0 است.
|
||
#
|
||
# این فایل هم روی لپتاپِ توسعهدهنده کپی میشود هم روی سرور، و حالتِ پیشفرض
|
||
# باید آنی باشد که اگر کسی فراموشش کند، بیخطر بماند. یک بار همین فایل با
|
||
# مقدارِ 1 روی سرور نشست و ماهها آنجا ماند.
|
||
#
|
||
# ⚠️ DEBUG=1 روی سرورِ عمومی دو ریسک دارد:
|
||
# • صفحههای خطا کلِ تنظیمات و traceback را نشان میدهند
|
||
# • کدِ ورودِ آزمایشیِ 0000 برای هر شمارهای پذیرفته میشود، یعنی هر
|
||
# کسی میتواند بهجای هر کاربری وارد شود
|
||
#
|
||
# روی ماشینِ خودتان (و فقط آنجا) این را 1 کنید تا خطاها کامل دیده شوند.
|
||
DJANGO_DEBUG=0
|
||
|
||
# خالی بگذارید تا خودش ساخته و در .django_secret_key ذخیره شود.
|
||
DJANGO_SECRET_KEY=
|
||
|
||
# بدونِ Redis سرویس بالا میآید ولی محدودیتِ نرخ بینِ workerها مشترک نیست؛
|
||
# /api/health همین را هشدار میدهد. برای پروداکشنِ واقعی پرش کنید.
|
||
CACHE_URL=
|
||
|
||
# نامِ سرویسِ systemd تا deploy.sh خودش ریاستارت کند (فقط روی سرور).
|
||
# TADRISINO_SERVICE=
|
||
|
||
# -----------------------------------------------------------------------
|
||
# آدرسِ سرویس — دو آدرس، بقیه از آنها ساخته میشوند
|
||
# -----------------------------------------------------------------------
|
||
# ALLOWED_HOSTS، CSRF_TRUSTED_ORIGINS، CORS_ALLOWED_ORIGINS، callbackِ زرینپال،
|
||
# برگشت از پرداخت و redirectِ بازار همه از این دو ساخته میشوند. پیشفرضشان
|
||
# دامنهی فعلی است و لازم نیست ست شوند. برای جابهجایی دامنه فقط همین دو را
|
||
# باز کنید (ترتیبِ کار در docs/operations.md، «عوض کردنِ دامنه»):
|
||
#
|
||
# PUBLIC_BASE_URL=https://mathapi.tadrisino2.ir
|
||
# FRONTEND_URL=https://math.tadrisino2.ir
|
||
#
|
||
# این سه فقط برای دامنهی *اضافه* لازماند (مثلاً دامنهی قبلی در دورانِ جابهجایی)؛
|
||
# مقدارشان به پیشفرضها اضافه میشود، جایگزینشان نمیشود:
|
||
#
|
||
# DJANGO_ALLOWED_HOSTS=old.example.ir
|
||
# CSRF_TRUSTED_ORIGINS=https://old.example.ir
|
||
# CORS_ALLOWED_ORIGINS=https://old-app.example.ir
|
||
|
||
# اختیاری — بدونش OTP واقعی ارسال نمیشه (فقط خطای صریح ۵۰۳ برمیگرده،
|
||
# طبق رفتارِ موجودِ accounts/services.py)
|
||
KAVENEGAR_API_KEY=
|
||
|
||
# شمارههای تستِ تیم — «شماره:کد» با کامای جداکننده.
|
||
#
|
||
# بدونِ این، روی سروری که DEBUG=0 است و کاوهنگار ندارد، هیچ توسعهدهندهای
|
||
# نمیتواند وارد API شود مگر اینکه کسی دستی از پنلِ ادمین یک OTPCode بسازد.
|
||
# با این، هر عضوِ تیم شماره و کدِ خودش را دارد و به کسی وابسته نیست.
|
||
#
|
||
# برای این شمارهها پیامکی ارسال نمیشود و کدشان هیچوقت در پاسخِ API
|
||
# برنمیگردد. هر شمارهی دیگری مسیرِ کاملاً عادیِ OTP را میرود.
|
||
#
|
||
# کد را تصادفی بگذارید (نه 1234)، شماره را دقیقاً همانطور که کلاینت
|
||
# میفرستد بنویسید، و پیش از باز کردنِ سرویس روی کاربرانِ واقعی خالیاش کنید —
|
||
# /api/health تا وقتی پر باشد هشدار میدهد.
|
||
#
|
||
# TEST_LOGIN_PHONES=09120000001:834512,09120000002:110947
|
||
TEST_LOGIN_PHONES=
|
||
|
||
# رمزِ ادمینِ Grafana (کاربرِ admin) — فقط برای دسترسیِ محلی
|
||
GRAFANA_ADMIN_PASSWORD=admin
|
||
|
||
# -----------------------------------------------------------------------
|
||
# RAG / AI tutor (اپ rag) — موقعِ تست پر کنید
|
||
# -----------------------------------------------------------------------
|
||
# بدونِ OPENAI_API_KEY و QDRANT_API_KEY، مسیرِ RAG غیرفعاله و
|
||
# POST /api/ai/ask همون پاسخِ stubِ قبلی رو میده (سازگاریِ عقبرو).
|
||
# فعلاً از GapGPT (پروکسیِ OpenAI برای ایران) استفاده میکنیم.
|
||
OPENAI_API_KEY=
|
||
OPENAI_BASE_URL=https://api.gapgpt.app/v1
|
||
# اگه بعداً خواستی مستقیم OpenAI واقعی رو تست کنی: کلیدِ واقعی رو این پایین
|
||
# پارک کن، بعد فقط دو خطِ بالا رو باهاش عوض کن. هیچ منطقِ سوییچی در کد نیست
|
||
# تا ساده و بیاشتباه بمونه.
|
||
# OPENAI_BASE_URL=https://api.openai.com/v1
|
||
OPENAI_API_KEY_OPENAI_DIRECT=
|
||
OPENAI_CHAT_MODEL=gpt-4.1-mini
|
||
OPENAI_VISION_MODEL=gpt-4.1-mini
|
||
# این رو تغییر نده؛ باید با مدلی که تیمِ دیگه باهاش collectionها رو ساخته یکی باشه.
|
||
OPENAI_EMBEDDING_MODEL=text-embedding-3-small
|
||
|
||
QDRANT_URL=https://qdrant.tadrisino2.ir:443
|
||
QDRANT_API_KEY=
|
||
|
||
# نامِ collection = f"{subject} {grade}".lower() . collectionهای موجود روی
|
||
# سرورِ تیمِ دیگه (بررسیشده): «علوم تجربی سوم» ، «مطالعات اجتماعی چهارم» ،
|
||
# «مطالعات اجتماعی ششم» ، «ریاضی سوم» ، «ریاضی ششم» ، «ریاضی هفتم».
|
||
# یعنی جزءِ گرید فقط «سوم/چهارم/ششم/هفتم» است (بدونِ «دبستان»).
|
||
#
|
||
# کلیدِ فیلترِ درس دستی تنظیم نمیشه — rag/services/known_collections.py خودش
|
||
# تشخیص میده: ریاضی → `chapter` (و شمارهی فصل رو به رشتهی دقیق تبدیل میکنه)،
|
||
# بقیه → `lesson_number`.
|
||
RAG_COLLECTION_NAME_TEMPLATE={subject} {grade}
|
||
RAG_RETRIEVAL_TOP_K=4
|
||
# RAG_FORCE_MOCK=1 یعنی حتی با وجودِ کلیدها هم مسیرِ RAG خاموش بمونه.
|
||
RAG_FORCE_MOCK=
|
||
|
||
# -----------------------------------------------------------------------
|
||
# زرینپال (اپ payment) — درگاهِ اصلیِ پرداختِ ما
|
||
# -----------------------------------------------------------------------
|
||
# بدونِ ZARINPAL_MERCHANT_ID، مسیرِ پرداخت fail-closed میمونه (خطای صریحِ
|
||
# ۵۰۳ بهجایِ پرداختِ ساختگیِ موفق).
|
||
# callbackِ زرینپال از PUBLIC_BASE_URL (بالاتر) ساخته میشود.
|
||
ZARINPAL_MERCHANT_ID=
|
||
# 1 = محیطِ sandbox زرینپال (برای تست بدونِ پرداختِ واقعی)
|
||
ZARINPAL_SANDBOX=1
|
||
# اختیاری — بعدِ تاییدِ پرداخت، کاربر به این URL (مثلاً یک deep link اپ) با
|
||
# ?orderId=...&status=... ریدایرکت میشه. خالی = پاسخِ JSON ساده.
|
||
ZARINPAL_REDIRECT_URL=
|
||
|
||
# -----------------------------------------------------------------------
|
||
# تنظیماتِ مقیاسپذیری (همه دیفالتِ امن دارن)
|
||
# -----------------------------------------------------------------------
|
||
# persistent DB connection (ثانیه). با SQLite بیاثر؛ بعد از Postgres مهم.
|
||
DB_CONN_MAX_AGE=60
|
||
# کشِ کوتاهِ ردیفِ کاربر در auth تا هر request یک SELECT نزنه. 0 = خاموش
|
||
# (پیشفرض). توصیهی پروداکشن با Redis: 30. با هر save/delete روی User باطل میشه.
|
||
AUTH_USER_CACHE_TTL=0
|
||
# سقفِ ارزانِ خواندن روی endpointهای پرترافیکِ GET (home/leaderboard/summary/...).
|
||
READ_THROTTLE_RATE=120/min
|
||
|
||
# ⚠️ تعدادِ پروکسیهایی که جلوی اپ نشستهاند (nginx = ۱). محدودیتِ نرخِ
|
||
# کاربرِ مهمان بر اساسِ IP است و IP از X-Forwarded-For خوانده میشود؛ اگر این
|
||
# عدد از تعدادِ واقعیِ پروکسیها بیشتر باشد، کلاینت میتواند هدر را جعل کند و
|
||
# محدودیت را دور بزند. کمتر باشد، همه پشتِ IP پروکسی یکی شمرده میشوند.
|
||
NUM_PROXIES=1
|
||
|
||
# -----------------------------------------------------------------------
|
||
# بقیه — همه پیشفرضِ کارا دارند و معمولاً لازم نیست دست بخورند
|
||
# -----------------------------------------------------------------------
|
||
# پیامک: بدونِ SENDER هم کاوهنگار با خطِ پیشفرضِ حساب میفرستد، ولی اگر خطِ
|
||
# اختصاصی دارید اینجا بگذارید. قالبِ متنِ پیامک هم قابلِ تغییر است ({code} لازم).
|
||
KAVENEGAR_SENDER=
|
||
# OTP_SMS_TEMPLATE=کد ورود شما به تدریسینو: {code}
|
||
|
||
# کلیدِ endpointهای داخلی (ingest در اپ rag، ساختِ سفارشِ سرور-به-سرور). با
|
||
# DEBUG=1 مقدارِ توسعه دارد؛ با DEBUG=0 خالی است و آن مسیرها بسته میمانند
|
||
# تا وقتی مقدارِ واقعی بگذارید.
|
||
INTERNAL_SERVICE_KEY=
|
||
|
||
# با صفر قلب جلوی جواب دادن گرفته شود؟ (۱ = بله). فقط وقتی فرانت برای ۴۰۳ِ
|
||
# no_hearts صفحهی «قلبها تمام شد» دارد.
|
||
# HEARTS_ENFORCED=0
|
||
|
||
# پرداختِ درونبرنامهایِ کافهبازار. بدونِ این چهار تا، مسیرِ بازار
|
||
# fail-closed میماند (payment/bazaar.py). REFRESH_TOKEN یکبار و دستی از
|
||
# پنلِ devapi گرفته میشود.
|
||
BAZAAR_CLIENT_ID=
|
||
BAZAAR_CLIENT_SECRET=
|
||
BAZAAR_REFRESH_TOKEN=
|
||
# BAZAAR_PACKAGE_NAME=ir.tadrisino.app
|
||
# BAZAAR_API_BASE=https://pardakht.cafebazaar.ir/devapi/v2
|
||
|
||
# آدرسهای زرینپال از روی ZARINPAL_SANDBOX بالا انتخاب میشوند؛ فقط اگر
|
||
# زرینپال دامنهاش را عوض کرد این سه را دستی بدهید.
|
||
# ZARINPAL_API_BASE=
|
||
# ZARINPAL_STARTPAY_BASE=
|
||
# ZARINPAL_CALLBACK_URL=
|
||
|
||
# نوشتنِ لاگ در فایل علاوه بر stdout (داخلِ Docker ست میشود). خالی = فقط stdout.
|
||
LOG_DIR=
|
||
# سقفِ گیرندهی اکشنِ «ارسالِ پیامک به انتخابشدهها» در پنلِ ادمین. این اکشن
|
||
# داخلِ همان request اجرا میشود، پس سقف جلوی تایماوت را میگیرد.
|
||
ADMIN_SMS_MAX_RECIPIENTS=200
|
||
# سقفِ نرخِ /api/health برای پایشِ بیرونی.
|
||
HEALTH_THROTTLE_RATE=60/min
|
||
# تایماوت و پارامترهای RAG. EMBEDDING_DIM باید با مدلِ embedding بالا بخواند.
|
||
OPENAI_TIMEOUT_SECONDS=60
|
||
QDRANT_TIMEOUT_SECONDS=30
|
||
OPENAI_EMBEDDING_DIM=1536
|
||
# کشِ پاسخِ دستیار (ثانیه) — سوالِ تکراری دوباره به مدل نمیرود.
|
||
RAG_ANSWER_CACHE_TTL=1800
|