# نمونه‌ی فایلِ تنظیمات — هم برای ماشینِ خودتان، هم برای سرور. # # 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