Commit Graph

9 Commits

Author SHA1 Message Date
ae0375c26c make the API docs page answer a consumer's first questions, and fix a missing endpoint
The Swagger header was a list of features. That is what the project does, not
what a caller needs. It now opens with the three things anyone integrating
against this API asks first: how do I get a token, what does an error look like,
and when do I get rate limited -- plus the field-naming and date conventions,
and a note that the schema is the contract and clients should be generated from
it rather than written from memory. Swagger UI and Redoc both render Markdown,
so it is structured rather than one long paragraph, which also fixes how badly
the old mixed Persian/Latin line wrapped right-to-left.

Two defects surfaced while checking the rendered schema:

- /api/health was absent from the schema entirely. The trailing-slash alias was
  excluded with extend_schema(exclude=True)(HealthView), but that decorator
  mutates the class, and both routes pointed at the same class, so the canonical
  route disappeared with it. A subclass now carries the exclusion, and the
  endpoint is back, exactly once. Endpoint count is 56, not 55.
- One endpoint was tagged 'محتوا (content)' while every other content endpoint
  used 'Curriculum (content)', which split the group into two sections.

Tags are now declared with descriptions and ordered by the path a real user
takes, rather than alphabetically.

Comment pass over the codebase, keeping the substance and dropping the noise:
the "⚠️ اضافه شده" prefixes dated comments against a moment no current reader
shares; "فاز ۲ / بخش ۴" referenced a plan that no longer exists and only
repeated the app name on the next line; "فاز اول - ۴ از ۱۱ اپ" had drifted (there
are fourteen). INSTALLED_APPS is now grouped by responsibility. The
TEST_LOGIN_PHONES block in settings shrank from 29 lines to 8 now that the same
explanation lives in docs/operations.md and .env.example -- a comment beside the
code should carry what a code reader needs, not a copy of the runbook.

Checked mechanically that no comment references an identifier that no longer
exists: zero. The dated measurements in rag/services/ingest.py and
generate_questions_from_chunks.py were deliberately left alone -- a measurement
carrying the date it was taken is the useful kind.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 01:28:32 +03:30
fa56308a35 make the tutor grade-aware and its answers measurable
مهم‌ترین خواسته‌ی سینیور این بود که بسنجیم پاسخِ AI واقعاً یاد می‌دهد یا نه.
برای سنجیدن، اول باید پاسخ‌ها قابلِ ردیابی می‌شدند.

پرامپت‌ها پایه‌آگاه شدند: تا پیش از این «معلمِ دبستانی» برای پایه نهم هاردکد
بود، هم در تولیدِ پاسخ و هم در vision — یعنی دانش‌آموزِ نهم لحنِ ابتدایی
می‌گرفت. PROMPT_VERSION حالا روی هر پیام ذخیره می‌شود.

هر پاسخ حاشیه‌نویسی می‌شود: مدل، نسخه‌ی پرامپت، پایه، collection، مقدارِ
فیلتر، تعداد chunk، توکن، تأخیر و from_cache. فیدبک reason اختیاری گرفت تا
لایک/دیسلایک بعداً قابلِ تحلیل باشد («بشه چک کرد کدوم بهتر بوده»).

ai_feedback_report --by prompt_version نسبتِ رضایت را کنارِ مصرف/هزینه
می‌گذارد. rag_eval سوال‌های واقعی را از مسیرِ واقعی می‌پرسد، با
--retrieval-only برای اجرای ارزان.

rag/services/lesson_context.py از lessonId تنها پایه و فصل را درمی‌آورد؛
normalize_grade_title هم اختلافِ «پایه نهم» در دیتابیس با «ریاضی نهم» در
نامِ collection را می‌بندد — بدونِ آن مسیرِ gradeId بی‌سروصدا خالی برمی‌گشت.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 19:00:40 +03:30
ff57adbc5f throttle hot read endpoints and cap unbounded list responses
progress/views.py
  - GuestAwareReadThrottle (same guest-by-IP pattern as the other apps);
    throttle_scope='read' on UserSummaryView, StreakCalendarView,
    LeaderboardView.
notifications/views.py
  - GuestAwareReadThrottle + throttle_scope='read' on NotificationListView.
  - list capped at NOTIFICATIONS_MAX=100 newest (Meta.ordering already
    newest-first); unreadCount still counted over the full set.
notifications/tests.py
  - 150 rows -> 100 returned newest-first, unreadCount = 75.
rag/views.py
  - ChunkListView: explicit order_by('-id') before the existing [:200] cap.
ai_tutor/views.py
  - ConversationMessagesView: return the newest 200 messages in
    chronological order instead of the whole conversation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 08:45:43 +03:30
5416fbb2ba real RAG answers on POST /api/ai/ask, plus SSE streaming and answer cache
When RAG is configured the endpoint retrieves lesson-scoped chunks and
generates a grounded answer; otherwise the previous deterministic stub
runs unchanged, so keyless runs and existing tests are unaffected.
Quota / idempotency / user-row lock / clean-503 behaviour is preserved on
every path.

models.py
  - Conversation.subject (CharField) and Conversation.lesson_number
    (IntegerField): retrieval metadata sent on the first ask and reused
    for the rest of the conversation.
migrations/0004_conversation_lesson_number_conversation_subject.py
  - migration for the two new fields.
serializers.py
  - AskRequestSerializer: optional subject / grade / lessonNumber to pin
    the Qdrant collection and lesson/chapter.
  - AskResponseSerializer: usedChunks (retrieved [{title, summary}]) and
    retrievalDebug (collection / filterKey / chapter-or-lesson / counts,
    emitted only under DEBUG).
views.py
  - generate_tutor_answer(): unchanged signature; RAG-configured branch
    calls rag.services generation, stub branch otherwise.
  - AskAIView.post(): resolve subject/grade/lessonNumber (falling back to
    the Conversation), check the answer cache via resolve_target(), run
    retrieve_context + generate_answer on a miss and populate the cache,
    return usedChunks (+ retrievalDebug under DEBUG). Failures still
    release the reserved quota slot and surface as 503.
  - AskAIView._streaming_response(): opt-in "stream": true returns a
    text/event-stream of chunk / done / error events; same retrieval,
    phase-3 persist, idempotency and quota accounting as the JSON path,
    and it consults the answer cache first. Non-stream JSON contract is
    untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-29 02:30:33 +03:30
683bd40169 cleanup: trim bloated multi-line comments across the project 2026-08-26 03:22:20 +03:30
80298b47b1 throttling, abuse-protection & logging/monitoring pass 2026-08-23 23:44:00 +03:30
cb18c93a3e Harden auth, AI tutor, payments, and subscriptions 2026-08-22 04:42:36 +03:30
f945f960c9 Update project 2026-08-19 17:15:55 +03:30
331148037e Initial commit - clean project structure 2026-08-18 16:48:15 +03:30