- Admin: refund/cancel/mark-resolved/Bazaar-link actions need change permission; question and curriculum import need add/delete; content browser needs view_question; guest device ids are shown to superusers only. - Accounts: registering a guest's phone revokes the guest's earlier sessions; self-deletion keeps Redemption, UserOffer and the phone's OTP rows; the public demo guest cannot be deleted (DEMO_GUEST_DEVICE_IDS); display-name contact filter covers any separator and social handles. - Payment: callback without Authority is 400; a second Bazaar purchase on a paid order is 409; orders snapshot credits/hearts/days at creation (payment.0011). - Assistant: a broken diagram no longer makes a streamed answer free; a late off-topic marker refuses the answer (not stored, not cached); a disconnect saves the partial answer; only KNOWN_COLLECTIONS are searched. - Infra: secret-key file is created atomically (workers no longer split keys); no default INTERNAL_SERVICE_KEY; Kavenegar key and Bazaar token kept out of error logs; Swagger/ReDoc pinned; schema throttled; docker compose bound to 127.0.0.1; non-ASCII digit ids are 400; ticket text capped at 5000. - docs/security-before-production.md: remaining open items 24-31 and the guard tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
110 lines
5.9 KiB
YAML
110 lines
5.9 KiB
YAML
# ---------------------------------------------------------------------
|
|
# Docker Compose برای اجرای محلیِ Django بههمراه استکِ لاگِ متمرکز
|
|
# (Grafana Alloy → Loki → Grafana). فقط برای dev/local — تنظیمِ پروداکشن نیست.
|
|
#
|
|
# جریانِ لاگ:
|
|
# Django app --(همون JSON log خطبهخطِ موجود، هم روی stdout هم در
|
|
# فایلِ /var/log/django/app.log — بدونِ تغییرِ پیامها)-->
|
|
# Alloy --(این فایل رو از طریقِ ولومِ مشترکِ django_logs میخونه)-->
|
|
# Loki --(ذخیرهسازیِ لاگ روی فایلسیستمِ محلی)-->
|
|
# Grafana --(دیتاسورسِ Loki از قبل provision شده؛ داشبوردِ آماده)
|
|
#
|
|
# ⚠️ قبلاً این نقش با Promtail انجام میشد؛ چون Promtail مارچ ۲۰۲۶ به
|
|
# EOL رسید، با Grafana Alloy (جانشینِ رسمیِ خودِ Grafana Labs) جایگزین
|
|
# شد. جریانِ لاگ (Django → فایلِ مشترک → Loki → Grafana) و لیبلهای
|
|
# level/logger دقیقاً همون قبلیان.
|
|
#
|
|
# اجرا: docker compose up --build
|
|
# - اپ: http://localhost:8000
|
|
# - Grafana: http://localhost:3000 (بدونِ لاگین، anonymous admin فعاله)
|
|
# ---------------------------------------------------------------------
|
|
|
|
services:
|
|
django:
|
|
build: .
|
|
container_name: tadrisino_django
|
|
# migrate هر بار قبل از اجرا صدا زده میشه؛ روی SQLite بیخطر و
|
|
# idempotent است (مطابقِ همون workflow ای که در README برای اجرای
|
|
# محلی/غیرِ Docker هم توصیه شده).
|
|
command: sh -c "python manage.py migrate --noinput && python manage.py runserver 0.0.0.0:8000"
|
|
# فقط روی خودِ لپتاپ: این پشته DEBUG=1 دارد (کدِ 0000 برای هر شماره) و Grafana بیرمز است؛
|
|
# روی 0.0.0.0 هر همسایهی وایفای به آنها میرسید.
|
|
ports:
|
|
- "127.0.0.1:8000:8000"
|
|
environment:
|
|
# این مقادیر فقط برای اجرای محلیِ Docker/دِمو هستن؛ برای پروداکشن
|
|
# واقعی جایگزین بشن (به .env.example نگاه کنید).
|
|
- DJANGO_DEBUG=${DJANGO_DEBUG:-1}
|
|
- DJANGO_SECRET_KEY=${DJANGO_SECRET_KEY:-}
|
|
- DJANGO_ALLOWED_HOSTS=${DJANGO_ALLOWED_HOSTS:-localhost,127.0.0.1}
|
|
- CACHE_URL=${CACHE_URL:-}
|
|
- KAVENEGAR_API_KEY=${KAVENEGAR_API_KEY:-}
|
|
# مسیرِ اضافهای که Django (علاوه بر stdout) همون خطوطِ JSON رو توش
|
|
# هم مینویسه؛ فقط وقتی این env ست باشه فعال میشه (config/settings.py)
|
|
# — یعنی اجرای عادیِ خارج از Docker دقیقاً مثلِ قبل میمونه.
|
|
- LOG_DIR=/var/log/django
|
|
volumes:
|
|
- .:/app # کد برای دیباگ/توسعهی زنده mount میشه
|
|
- django_logs:/var/log/django # ولومِ مشترک با alloy
|
|
# ⚠️ عمداً depends_on نداره: Django برای بالا اومدن یا جوابدادن به
|
|
# درخواستها هیچ نیازی به Loki نداره (فقط توی فایل مینویسه؛ Promtail
|
|
# و Loki مستقل از این میخونن/push میکنن). وابستگیِ استارتآپیِ اضافه
|
|
# فقط باعثِ کندشدنِ بیدلیلِ `docker compose up` میشد.
|
|
|
|
loki:
|
|
image: grafana/loki:2.9.6
|
|
container_name: tadrisino_loki
|
|
ports:
|
|
- "127.0.0.1:3100:3100"
|
|
command: -config.file=/etc/loki/loki-config.yml
|
|
volumes:
|
|
- ./docker/loki/loki-config.yml:/etc/loki/loki-config.yml:ro
|
|
- loki_data:/loki
|
|
|
|
alloy:
|
|
image: grafana/alloy:v1.18.1
|
|
container_name: tadrisino_alloy
|
|
# همون کاری که promtail قبلاً میکرد: config.alloy رو اجرا میکنه که
|
|
# فایلِ لاگِ Django رو میخونه و به Loki push میکنه. پرچمِ
|
|
# server.http.listen-addr فقط برای UI دیباگِ خودِ Alloy روی 12345 است.
|
|
command:
|
|
- run
|
|
- --server.http.listen-addr=0.0.0.0:12345
|
|
- --storage.path=/var/lib/alloy/data
|
|
- /etc/alloy/config.alloy
|
|
ports:
|
|
- "127.0.0.1:12345:12345" # اختیاری: UI دیباگِ Alloy (وضعیتِ کامپوننتها)
|
|
volumes:
|
|
- ./docker/alloy/config.alloy:/etc/alloy/config.alloy:ro
|
|
- django_logs:/var/log/django:ro # همون لاگهای Django رو میخونه (read-only)
|
|
- alloy_data:/var/lib/alloy/data # ذخیرهسازیِ داخلیِ Alloy (شاملِ positions)
|
|
# ⚠️ عمداً فقط به loki وابستهست، نه django: Alloy صرفاً فایلِ
|
|
# لاگِ رویِ ولومِ مشترک رو میخونه (چه Django بالا باشه چه نه) و به
|
|
# Loki push میکنه؛ نیازی نداره منتظرِ استارتشدنِ Django بمونه.
|
|
depends_on:
|
|
- loki
|
|
|
|
grafana:
|
|
image: grafana/grafana:10.4.3
|
|
container_name: tadrisino_grafana
|
|
ports:
|
|
- "127.0.0.1:3000:3000"
|
|
environment:
|
|
# فقط برای دسترسیِ محلی/دِمو ساده شده (بدونِ لاگین)؛ برای هر چیزِ
|
|
# عمومی/پروداکشن حتماً anonymous access رو خاموش و پسورد ست کنید.
|
|
- GF_AUTH_ANONYMOUS_ENABLED=true
|
|
- GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer
|
|
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-admin}
|
|
volumes:
|
|
- ./docker/grafana/provisioning:/etc/grafana/provisioning:ro
|
|
- ./docker/grafana/dashboards:/var/lib/grafana/dashboards:ro
|
|
- grafana_data:/var/lib/grafana
|
|
depends_on:
|
|
- loki
|
|
|
|
volumes:
|
|
django_logs:
|
|
loki_data:
|
|
alloy_data:
|
|
grafana_data:
|