AliReza f7009b11e8 Instant home on reopen: snapshot of profile/grades/map/stats on the device, refreshed behind the scenes
A signed-in user with a snapshot goes straight to home; the same boot requests run in the
background and replace it. Snapshot is cleared whenever tokens are cleared and on a new login,
ignored from another build or when older than 7 days, and dropped when the fresh profile is a
different user (reboot remounts MainApp via a generation key; AnimatePresence otherwise kept the
exiting one). Notifications/characters wait for the profile answer so an expired access token
costs the same requests as before. refreshHome applies only the latest answer. Home shows a
"saved data" strip when the map could not be refreshed.

Measured locally (old vs new build, same backend, Chrome throttling, median of 3, time to map):
Fast 3G 2.46s -> 1.80s (expired token 3.63s -> 1.80s); Slow 3G 8.52s -> 6.14s (expired 12.6s ->
6.13s); API requests per open unchanged (6 valid, 11 expired). 12/12 behaviour checks passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 19:57:42 +03:30
2026-10-07 19:04:45 +03:30
2026-08-16 12:18:41 +03:30

تدریسینو — اپِ ریاضی (فرانت‌اند)

اپِ وبِ موبایل‌محورِ تدریسینو، آموزشِ ریاضی به سبکِ دولینگو برای پایه‌ی سوم تا دوازدهم: نقشه‌ای از جزیره‌ها برای هر کتاب، آزمون‌های کوتاه از مسئله‌های خودِ کتابِ درسی، دستیارِ هوشِ مصنوعی، همراه‌ها، زنجیره‌ی روزانه و اشتراک. همین مخزن پوسته‌ی اندرویدِ اپ را هم دارد (android/).

بک‌اند مخزنِ جداگانه‌ای است (Tadrisino/MathApp) و قراردادِ API اسکیمای OpenAPIِ همان‌جاست. این اپ تنها کلاینتِ آن API است.

سایتِ زنده https://math.tadrisino2.ir · API: https://mathapi.tadrisino2.ir
فناوری React 18 · TypeScript (strict) · Vite 6 · Tailwind 4 · Motion
وابستگی‌ها عمداً کم: بی‌کتابخانه‌ی router و state؛ ناوبری و داده‌ی مشترک در خودِ کد
اندروید پوسته‌ی WebView روی همین سایت، با پرداختِ درون‌برنامه‌ایِ کافه‌بازار (Poolakey)؛ بسته‌ی com.tadrisino.math.app

راه‌اندازی

npm install
npm run dev          # http://localhost:5173

در حالتِ توسعه، Vite درخواست‌های /api را به بک‌اند پاس می‌دهد، پس CORS مطرح نیست. پیش‌فرض بک‌اندِ محلی است (python manage.py runserver روی پورتِ ۸۰۰۰). بدونِ بک‌اندِ محلی، فایلِ .env.development.local بسازید:

VITE_DEV_PROXY_TARGET=https://mathapi.tadrisino2.ir

⚠️ در این حالت هر کاری در اپ بکنید روی دیتابیسِ واقعی نوشته می‌شود.

دستور کار
npm run dev سرورِ توسعه
npm run typecheck بررسیِ نوع‌ها (strict)
npm run build type-check و بعد build در dist/
npm run preview اجرای همان build

ساختار

src/
  config.ts            آدرسِ API (بخشِ پایین)
  api/                 تنها درِ ارتباط با سرور — هیچ جای دیگر fetch نمی‌زند
    http.ts            توکن، timeout، تکرارِ GET، refreshِ تک‌نسخه‌ای، SSE، Idempotency-Key
    index.ts           یک تابع برای هر اندپوینت
    types.ts           شکلِ پاسخ‌ها، از روی پاسخِ واقعیِ سرور
  app/                 App (جریانِ ورود) و MainApp (تب‌ها و صفحه‌ها)
  nav/                 ناوبریِ پشته‌ای، هماهنگ با دکمه‌ی back گوشی
  state/               داده‌ی مشترک (پروفایل، نقشه، کتابِ انتخاب‌شده، همراه) و گفتگوی دستیار
  screens/             یک فایل برای هر صفحه
  components/          اجزای مشترک: مسیرِ جزیره‌ها، نوارِ کتاب‌ها، برگه‌ی پایین، بازخورد، …
  mascots/             همراه‌ها (سیگما، دلتا، پی، امگا): SVG از کد، شش حالتِ چهره
  diagram/             شکلِ درس و جوابِ دستیار: توصیفِ JSON از بک‌اند → SVG؛ همه‌ی مختصات این‌جا حساب می‌شود
  lib/                 اعدادِ فارسی، تاریخِ شمسی، MathText، پیامِ خطا، صدا، پلِ کافه‌بازار، روش‌های پرداخت
android/               پوسته‌ی اندروید (README خودش)
pay.html · src/pay.ts  صفحه‌ی واسطِ پرداختِ زرین‌پال برای اپِ اندرویدِ فعلی

قاعده‌ها:

  • کلاینت را از حافظه ننویسید. قرارداد را از اسکیمای بک‌اند بخوانید (python manage.py spectacular --file schema.yaml --format openapi) و هر تغییرِ types.ts را با پاسخِ واقعیِ سرور بسنجید.
  • صفحه‌ها هرگز مستقیم سرور را صدا نمی‌زنند: همیشه screens/* → api/index.ts → api/http.ts.
  • اعداد: برای نمایش toFa، برای ورودی digitsOnly (کیبوردِ فارسی ارقامِ ۰-۹ می‌فرستد و \d در JS آن‌ها را نمی‌شناسد).
  • رنگ‌ها در src/styles/index.css (@theme) تعریف شده‌اند: bg-coral، text-ink، …
  • خطا: پیامِ کاربر همیشه از friendlyError می‌آید، نه متنِ خامِ سرور.
  • بازشدنِ فوری: کاربرِ واردشده خانه را از عکسِ روی گوشی می‌بیند (state/homeSnapshot.ts: پروفایل، پایه‌ها، نقشه، آمار) و همان درخواست‌های بوت پشتِ صحنه تازه‌اش می‌کنند. عکس با پاک شدنِ توکن و ورودِ تازه پاک می‌شود، با بیلدِ دیگر یا کهنه‌تر از ۷ روز خوانده نمی‌شود، و درستی (قفل، اشتراک، قلب) همیشه با سرور است. داده‌ی تازه‌ای که در خانه دیده می‌شود باید در AppData بماند تا در عکس هم برود.
  • متنِ فارسی بی‌اعراب و بی «ی»ِ اضافه‌ی نوشته‌شده («پایه‌ی سوم») است (تصمیمِ شرکت)؛ تنوین («قبلاً») می‌ماند. متنِ تازه را همین‌طور بنویسید. متنِ سرور را بک‌اند هنگامِ ساختنِ پاسخ پاک می‌کند و plainPersian در MathText همان کار را برای پاسخِ زنده‌ی دستیار. lib/plainMath.ts هر LaTeX یا markdownی را که برسد ساده می‌کند و باید با content/plain_math.pyِ بک‌اند هم‌رفتار بماند.

آدرسِ بک‌اند و عوض کردنِ دامنه

دامنه هیچ‌جای کد نیامده. آدرسِ API به این ترتیب خوانده می‌شود (src/config.ts):

  1. dist/config.js (از public/config.js) — در زمانِ اجرا؛ بعد از build هم روی سرور ویرایش‌شدنی است.
  2. VITE_API_BASE_URL — در زمانِ build، از .env.production.
  3. /api — هم‌دامنه، وقتی nginxِ دامنه‌ی فرانت مسیرِ /api را به بک‌اند پراکسی کند.

برای جابه‌جاییِ دامنه:

  • سریع، بدونِ build: روی سرور در dist/config.js بنویسید apiBaseUrl: "https://<دامنه‌ی تازه>/api" و کشِ آروان را برای همین فایل پاک کنید.
  • ماندگار: خطِ VITE_API_BASE_URL در .env.production را عوض کنید و build بگیرید.
  • سمتِ بک‌اند دامنه‌ی تازه‌ی فرانت باید مجاز باشد (FRONTEND_URL)، و در CSPِ nginx (connect-src) دامنه‌ی تازه‌ی API بیاید. رویه‌ی کامل: docs/operations.mdِ بک‌اند، بخشِ «عوض کردنِ دامنه».

روش‌های پرداخت

برگه‌ی پرداخت روش‌ها را از paymentMethods در dist/config.js می‌خواند (src/lib/paymentMethods.ts)، جدا برای مرورگر (web) و داخلِ اپِ اندروید (app)؛ مقدارها "zarinpal" و "bazaar". پیش‌فرض: مرورگر فقط زرین‌پال، اپ هر دو. نسخه‌ای که فقط در کافه‌بازار است: paymentMethods: { app: ["bazaar"] }؛ build لازم نیست، فقط کشِ آروانِ این فایل را پاک کنید.


انتشار

روی سرور (~/mathapp_frontend_new، که nginxِ math.tadrisino2.ir از dist/ش سرو می‌کند):

cd ~/mathapp_frontend_new && ./deploy.sh   # fetch، npm ci، type-check، build در dist.next و جابه‌جاییِ بی‌وقفه

buildِ قبلی در dist.prev می‌ماند (برگشت: rm -rf dist && mv dist.prev dist) و dist/config.jsِ ویرایش‌شده روی سرور به buildِ تازه منتقل می‌شود. سرور مشترکِ شرکت است: پیش از هر کار آن‌جا قواعدِ CLAUDE.mdِ بک‌اند (بخشِ «Working on the servers») را بخوانید.

جای دیگر: npm ci && npm run build و سرو کردنِ dist/. اپ مسیرِ جدا (route) ندارد و همه‌چیز از / بار می‌شود؛ فقط index.html و config.js نباید طولانی کش شوند (باقیِ فایل‌ها نامِ hashدار دارند). درگاهِ پرداخت کاربر را به /?orderId=…&status=… برمی‌گرداند و لینکِ دعوت /?ref=CODE است؛ هر دو را خودِ اپ می‌خواند.

CSPِ سایت در nginx است (ops/nginx/zareian-front-headers.conf در مخزنِ بک‌اند). اگر اسکریپتِ درون‌خطیِ index.html عوض شود، هشِ تازه‌اش باید در همان فایل بنشیند، وگرنه مرورگر آن را اجرا نمی‌کند.

Description
No description provided
Readme 2.4 MiB
Languages
TypeScript 94.4%
Kotlin 3.2%
CSS 1.2%
HTML 0.6%
Shell 0.4%
Other 0.2%