senior's post-demo changes: parent report in the student's own account, Jalali birth date, invoices, math-only tutor, priced quotas

- remove the family app from the root (separate parent accounts, invite codes, parental
  settings); progress.0006 drops its tables, permissions and migration history, and
  Profile.parent_phone, the two family notification types and ?userId= on
  /api/progress/nodes go with it
- GET /api/user/weekly-report: last 7 days next to the 7 before (estimated minutes,
  questions, accuracy, islands, tutor questions) for the "parent report" page
- profile birthDate in Jalali (accounts/jalali.py), ages 5-99, birthYear derived from it
- GET /api/payment/invoices; orders now snapshot list price and plan title
- tutor answers only math: server pre-filter, scope rule in the prompt (tutor-v11),
  refusal marker replaced with fixed text; self-harm gets a help line instead
- streamed answers now record token usage (it was always 0)
- daily tutor quota: AI_DAILY_QUOTA_FREE (default 3) vs Plan.ai_daily_quota
- delete_users management command for wiping test accounts across every app
- docs/ai-cost-and-guardrails.md: measured cost per question and guardrail results

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-02 02:38:43 +03:30
parent d5dbd1b23d
commit 39247f6d53
67 changed files with 1619 additions and 1140 deletions

View File

@@ -0,0 +1,29 @@
# Generated by Django 5.2.17 on 2026-10-01 21:01
from django.db import migrations
# اپِ family (حسابِ جدای والد، کدِ دعوت، تنظیماتِ والدین) ۲۰۲۶-۱۰-۰۱ از ریشه حذف شد؛
# جایش «گزارشِ والدین» در حسابِ خودِ دانش‌آموز است (progress/report.py). خودِ اپ دیگر
# نصب نیست، پس جدول‌هایش این‌جا drop می‌شوند. IF EXISTS: دیتابیسِ تازه هیچ‌وقت آن‌ها را
# نداشته. داده‌ی آن‌ها نگه داشته نمی‌شود؛ پیش از migrate بکاپ بگیرید.
FAMILY_TABLES = ('family_parentalsettings', 'family_weeklyreportlog', 'family_familylink')
def forget_family_app(apps, schema_editor):
"""ردِ اپ در جدول‌های خودِ جنگو: نوع‌ها و مجوزهای ادمین، و تاریخچه‌ی migration."""
ContentType = apps.get_model('contenttypes', 'ContentType')
ContentType.objects.filter(app_label='family').delete() # مجوزها با CASCADE می‌روند
schema_editor.execute("DELETE FROM django_migrations WHERE app = 'family'")
class Migration(migrations.Migration):
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('progress', '0005_tedi_character'),
]
operations = [
*[migrations.RunSQL(f'DROP TABLE IF EXISTS {table}', migrations.RunSQL.noop) for table in FAMILY_TABLES],
migrations.RunPython(forget_family_app, migrations.RunPython.noop),
]