- seed_content no longer undoes admin work: a SeedRecord ledger (content/seed_sync.py)
stops deleted/renamed/re-worded content from being recreated and keeps admin-edited
lesson text; new rows in the seed files still arrive (migration content.0010)
- plan list cache is invalidated on Plan save (receiver used a stale 'v1' key)
- token refresh per-IP cap 30/hour -> 600/hour (TOKEN_REFRESH_IP_RATE)
- a failed gateway result only changes a pending order (forged NOK no longer
overwrites refunded/canceled)
- tutor gets the correct answer only after the student has answered
- support reply notification moved to a TicketMessage post_save signal
- global daily cap on paid AI questions (AI_GLOBAL_DAILY_MAX, default 3000)
- Bazaar verify uses only the order's SKU; bazaar orders require a SKU
- /api/health warns on the committed signing key; deploy.sh saves local commits;
400 for bad ?unit= / ?period=; account delete keeps the referrer's Conversion
- earlier today: no stub answers outside DEBUG, ?grade= removed, logged fallbacks
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- packs (20 / 60 / 150 questions for 45,000 / 119,000 / 259,000 toman) never expire and
give 7 / 30 / 60 days of unlimited hearts; old subscription plans stay for existing
subscribers but are no longer on sale
- credit ledger (subscription.QuestionCredit): +N per paid pack (once per order), -1 per
tutor question that reaches the API; the free daily questions are spent first; questions
stopped by the server filter, cached answers and failed answers cost nothing
- unlimited hearts from packs live in HeartsPass, so buying a pack never rewrites a
running subscription
- Message.charge records how each question was paid; GET /api/ai/quota and the ask
responses report free-left-today and credits
- HEARTS_ENFORCED now defaults to on: zero hearts stops answering until refill or a pack
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Five a day was too close to the free three. Pricing keeps the tutor under ~40% of net revenue
at typical use (a third of the cap); full numbers in the cost report and docs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- profile publicId ("User482917", accounts/public_id.py); admin shows and searches it
- plans API reports aiDailyQuota per plan and freeAiDailyQuota; migration 0007 sets the
temporary prices (monthly 99,000 / yearly 990,000 toman, 5 tutor questions a day) unless
an admin already edited the yearly plan
- tutor tone follows the learner's age (18+ gets an adult tone at any grade); notation
still follows the grade's book; answer cache keyed by tone (prompt tutor-v12-age-tone)
- POST /api/user/delete: phone users confirm with a fresh SMS code (same checks as login,
now shared in verify_phone_otp), guests type "حذف"; payment records are kept, demo
accounts refused
- delete_users --skip-paid
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The frontend plays node quizzes, but a node only completed once every one of its
8-13 lessons was completed separately, so students were stuck after the first
island of each unit. POST /api/nodes/{id}/quiz/complete now completes the node
(any score; score only sets stars/xp) and returns nextNodeId.
Also closes the other backend gaps found while auditing the frontend:
- /api/ai/ask without lessonId now picks the book from the user's grade instead
of skipping retrieval, so the "ask Pi" tab is grounded in the textbook.
- guest sessions return a refreshToken; they used to go silently 401 after 1h.
- lesson_complete throttle 10/hour -> 120/hour (a lesson here is 1-2 questions).
- progressPercent is per grade, not over all 2,617 lessons of every grade.
- a one-year plan (299,000 toman) is created by migration when no plan exists.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
کارتِ اشتراک زیرِ هر پلن فهرستِ امکانات و یک برچسب («محبوبترین»، «بهترین
ارزش») نشان میدهد، و هر دو در کدِ فرانت هاردکد بودند — یعنی عوض کردنِ یک
بندِ متنی به دیپلویِ تازهی اپ نیاز داشت.
Plan حالا features و badge دارد. `popular` سرِ جایش ماند: بولین است و متنِ
برچسب را نمیدهد، پس این جایگزینش نیست، کنارش است. هیچکدام اجباری نیستند و
پلنهای موجود بدونشان همچنان سرو میشوند.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>