# نمونه‌ی فایلِ تنظیمات — هم برای ماشینِ خودتان، هم برای سرور. # # 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= # ----------------------------------------------------------------------- # آدرسِ سرویس — این چهار تا پیش‌فرضِ درست دارند # ----------------------------------------------------------------------- # تا پیش از این هر چهارتا باید دستی روی سرور اضافه می‌شدند، و چون در همین # فایل نبودند هر بار از نو کشف می‌شدند: نبودِ اولی یعنی «Disallowed Host»، # دومی یعنی ردِ ورود به پنلِ ادمین، سومی یعنی بلاک شدنِ فرانت در مرورگر، و # چهارمی یعنی شکستنِ بی‌سروصدای مسیرِ پرداخت. # # حالا هر چهارتا مقدارِ پیش‌فرضِ دامنه‌ی خودمان را دارند و لازم نیست ست شوند. # فقط اگر دامنه عوض شد، این‌ها را باز کنید: # # DJANGO_ALLOWED_HOSTS=api.math.tadrisino2.ir,math.tadrisino2.ir,localhost,127.0.0.1 # CSRF_TRUSTED_ORIGINS=https://api.math.tadrisino2.ir # CORS_ALLOWED_ORIGINS=https://math.tadrisino2.ir # PUBLIC_BASE_URL=https://api.math.tadrisino2.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-4o-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 می‌مونه (خطای صریحِ # ۵۰۳ به‌جایِ پرداختِ ساختگیِ موفق). # 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