Files
MathApp_frontend/android
AliReza f8cf86e4e8 UI readability pass and Bazaar in-app purchase bridge
- muted text #9e9ec0 -> #727299 (contrast 2.6 -> 4.5 on white); tab labels 11px
- map: chapter titles wrap to two lines instead of being cut off
- reduced-motion respected (MotionConfig + CSS), focus-visible ring,
  no pull-to-refresh, short vibration on correct/wrong answers
- src/lib/bazaar.ts: bridge to the Android WebView wrapper; checkout uses
  Bazaar IAP only inside that app, Zarinpal everywhere else (unchanged)
- android/: WebView wrapper with Poolakey; written but never built

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 19:13:12 +03:30
..

اپِ اندرویدِ تدریسینو (پوسته‌ی WebView + پرداختِ بازار)

همان سایتِ math.tadrisino2.ir داخلِ یک WebView. تنها کدِ بومی پرداختِ درون‌برنامه‌ایِ کافه‌بازار است (کتابخانه‌ی Poolakey)، چون بازار برای اپی که در آن منتشر می‌شود پرداختِ محصولِ دیجیتال را فقط از راهِ خودش می‌پذیرد. باقیِ اپ همان فرانتِ وب است و با دیپلویِ فرانت به‌روز می‌شود، بی‌آن‌که نسخه‌ی تازه‌ی اپ لازم باشد.

⚠️ این پروژه هنوز یک بار هم build نشده. روی ماشینی نوشته شد که Android SDK نداشت (۲۰۲۶-۱۰-۰۳). APIِ Poolakey از README خودِ کتابخانه است. اولین کار: باز کردن در Android Studio، build، و یک خریدِ واقعی روی گوشی.

پیش از build — سه چیز از پیشخانِ بازار (سنیور / حسابِ شرکت)

چه کجا گذاشته می‌شود وضعیت
اسمِ پکیج applicationId در app/build.gradle.kts com.tadrisino.app حدس است؛ تأیید نشده
کلیدِ RSAِ عمومیِ اپ BAZAAR_RSA_KEY در app/build.gradle.kts ندارد؛ بدونِ آن خرید شروع نمی‌شود
SKUِ هر بسته (محصولِ مصرف‌شدنی) پنلِ ادمینِ بک‌اند: /admin/subscription/plan/ ← «Bazaar sku» هیچ‌کدام تعریف نشده

قیمتِ هر محصول در پیشخانِ بازار باید با قیمتِ همان بسته در ادمین یکی باشد؛ سرور مبلغ را از بازار نمی‌خواند.

build

  1. Android Studio ← Open ← همین پوشه‌ی android/. Studio خودش Gradle wrapper را می‌سازد.
  2. Build ← Generate Signed App Bundle / APK، با کلیدِ امضای شرکت. کلیدِ امضا را گم نکنید: بدونِ همان کلید هیچ نسخه‌ی بعدی روی بازار به‌روزرسانی نمی‌شود.
  3. نصب روی گوشی‌ای که کافه‌بازار دارد و با حسابِ تست وارد شده.

جریانِ خرید (برای عیب‌یابی)

فرانت  POST /api/subscription/purchase  {planId, paymentMethod:"bazaar"}  → orderId, bazaarSku
فرانت  TadrisinoAndroid.bazaarPurchase(sku, orderId)
اپ     Poolakey.purchaseProduct(sku, payload=orderId)  → purchaseToken
اپ     رویدادِ «tadrisino:bazaar» {orderId, purchaseToken}
فرانت  POST /api/payment/bazaar/verify  {orderId, purchaseToken}   ← سرور از بازار می‌پرسد
فرانت  TadrisinoAndroid.bazaarConsume(token)   ← تا همان بسته دوباره خریدنی باشد

اگر پول رفت ولی تأییدِ سرور نرسید، کاربر دوباره «پرداخت» می‌زند: فرانت همان سفارش را می‌فرستد و اپ توکنِ ماندهٔ همان سفارش را از getPurchasedProducts پیدا می‌کند.

قرارداد سمتِ وب: src/lib/bazaar.ts. سمتِ سرور: payment/bazaar.py و docs/operations.mdِ بک‌اند.