docs: handbook, diagrams and guides brought up to 2026-10-02

- technical-handbook: question packs instead of subscriptions, real
  hearts with the new wait screen (screenshot), math-only tutor and what
  is charged (new 9-7), admin cancel/refund, Bazaar planId, account
  deletion, 59 endpoints, 779 tests, 14 apps, status and open decisions.
- Diagrams redrawn: use-case (buy a pack, refunds), data model
  (QuestionCredit, HeartsPass, Profile.birth_date), pack payment sequence.
- The PDF is now built from the Markdown by docs/build_handbook.py
  (pandoc + Chrome, font in docs/assets); the hand-made HTML it used to
  come from was not in the repo and had been lost.
- architecture, operations, security-before-production (item 13 closed),
  ai-cost-and-guardrails and README follow the same changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-02 23:10:50 +03:30
parent 8a4753bd15
commit 7683920b0b
13 changed files with 196 additions and 55 deletions

View File

@@ -260,18 +260,24 @@ temperature و با `OPENAI_CHAT_REASONING_EFFORT` صدا زده می‌شوند
## قلب‌ها، مثلِ دولینگو
هر پاسخِ غلط یک قلب کم می‌کند (مشترکِ فعال قلب از دست نمی‌دهد). **هر ۵ ساعت یک
هر پاسخِ غلط یک قلب کم می‌کند (اشتراکِ فعال یا روزهای قلبِ بسته‌ی سوال = قلبِ نامحدود). **هر ۵ ساعت یک
قلب برمی‌گردد** (`HEART_REFILL_INTERVAL`) و **۲۴ ساعت بعد از اولین قلبی که از
حالتِ پر کم شد، همه یک‌جا پر می‌شوند** (`HEART_FULL_REFILL_AFTER`، فیلدِ
`full_refill_at`). `GET /api/user/hearts` هر دو زمان را می‌دهد: `nextRefillAt`
و `fullRefillAt`. تا ۲۰۲۶-۰۹-۲۴ هر قلب ۲۴ ساعت بود؛ تایمرِ قدیمیِ بلندتر از ۵
ساعت در اولین خواندن کوتاه می‌شود.
**با صفر قلب، بک‌اند فقط وقتی جواب را رد می‌کند که `HEARTS_ENFORCED=1` باشد**
(۴۰۳ با `code: "no_hearts"` و `nextRefillAt`). پیش‌فرض خاموش است چون فرانتِ فعلی
برای این پاسخ صفحه ندارد و دانش‌آموزِ بی‌قلب را به صفحه‌ی خطای عمومی می‌برد. تا
روشن نشده، «قلبِ نامحدودِ» اشتراک فقط در ظاهرِ اپ اعمال می‌شود و با صدا زدنِ
مستقیمِ API دور زده می‌شود.
**با صفر قلب، بک‌اند جواب را رد می‌کند** (۴۰۳ با `code: "no_hearts"`، `nextRefillAt` و
`fullRefillAt`). `HEARTS_ENFORCED` از ۲۰۲۶-۱۰-۰۲ پیش‌فرض روشن است و فرانت برای این پاسخ صفحه‌ی
«قلب‌هات تموم شد» را با شمارشِ معکوس دارد (`src/components/NoHeartsScreen.tsx`). از همان روز:
- چکِ قلب داخلِ همان تراکنشی است که قلب را کم می‌کند. پیش‌تر بیرونش بود و دو جوابِ غلطِ هم‌زمان با
یک قلبِ باقی‌مانده هر دو پذیرفته می‌شدند (با دو thread بازتولید شد).
- پایانِ درس یا جزیره بی‌قلب و بی‌جواب دادنِ سوال‌هایش ۴۰۳ می‌گیرد؛ پیش‌تر `quiz/complete` اجازه
می‌داد با قلبِ صفر جزیره‌به‌جزیره جلو رفت. کسی که آخرین قلبش را روی آخرین سوال از دست داده،
همه را جواب داده و جزیره را تمام می‌کند.
- قلبی که در انتظار برگشته پیش از جواب ذخیره می‌شود؛ پیش‌تر پاسخِ جوابِ درست «۰ قلب» می‌گفت و
اپ دانش‌آموز را دوباره به صفحه‌ی انتظار می‌برد.
تست‌ها: `content/tests_hearts_gate.py`.
**امتیاز فقط برای جوابِ ثبت‌شده است.** `lessons/{id}/complete` و
`nodes/{id}/quiz/complete` عددِ `correctCount`ِ کلاینت را به تعدادِ سوال‌های