# تدریسینو — اپِ ریاضی (فرانت‌اند) اپِ وبِ موبایل‌محورِ **تدریسینو**، آموزشِ ریاضی به سبکِ دولینگو برای پایه‌ی سوم تا دوازدهم: نقشه‌ای از جزیره‌ها برای هر کتاب، آزمون‌های کوتاه از مسئله‌های خودِ کتابِ درسی، دستیارِ هوشِ مصنوعی، همراه‌ها، زنجیره‌ی روزانه و اشتراک. همین مخزن پوسته‌ی اندرویدِ اپ را هم دارد ([`android/`](android/README.md)). بک‌اند مخزنِ جداگانه‌ای است ([`Tadrisino/MathApp`](https://gitea.tadrisino2.ir/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` | --- ## راه‌اندازی ```bash npm install npm run dev # http://localhost:5173 ``` در حالتِ توسعه، Vite درخواست‌های `/api` را به بک‌اند پاس می‌دهد، پس CORS مطرح نیست. پیش‌فرض بک‌اندِ محلی است (`python manage.py runserver` روی پورتِ ۸۰۰۰). بدونِ بک‌اندِ محلی، فایلِ `.env.development.local` بسازید: ```bash 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` می‌آید، نه متنِ خامِ سرور. - **متنِ فارسی** بی‌اعراب و بی «ی»ِ اضافه‌ی نوشته‌شده («پایه‌ی سوم») است (تصمیمِ شرکت)؛ تنوین («قبلاً») می‌ماند. متنِ تازه را همین‌طور بنویسید. متنِ سرور را بک‌اند هنگامِ ساختنِ پاسخ پاک می‌کند و `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/`ش سرو می‌کند): ```bash 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` عوض شود، هشِ تازه‌اش باید در همان فایل بنشیند، وگرنه مرورگر آن را اجرا نمی‌کند.