- 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>
اپِ اندرویدِ تدریسینو (پوستهی 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
- Android Studio ← Open ← همین پوشهی
android/. Studio خودش Gradle wrapper را میسازد. Build ← Generate Signed App Bundle / APK، با کلیدِ امضای شرکت. کلیدِ امضا را گم نکنید: بدونِ همان کلید هیچ نسخهی بعدی روی بازار بهروزرسانی نمیشود.- نصب روی گوشیای که کافهبازار دارد و با حسابِ تست وارد شده.
جریانِ خرید (برای عیبیابی)
فرانت 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ِ بکاند.