Files
MathApp_frontend/android
AliReza 737414f246 Payment from the Android app: reach Zarinpal through pay.html so it carries our Referer
The app hands every outside URL to the phone browser, which sends no Referer, and Zarinpal's StartPay
refuses a request without our domain as Referer («دسترسی از این دامنه مجاز نمی‌باشد»). Checked against
production on a pending order: no Referer → refused; Referer https://math.tadrisino2.ir/ → forwards to
the bank (sep.shaparak.ir).

- pay.html + src/pay.ts: opened in the phone browser, forwards only to our own
  /api/payment/orders/<id>/pay link (anything else is refused), so the Referer is math.tadrisino2.ir.
  The app opens it as http:// (the WebView keeps only https on its own host); ArvanCloud moves it to
  https, and the link rides in the fragment, which never reaches a server.
- MainActivity.kt (next APK): payment pages (our subdomains, zarinpal, shaparak) stay inside the WebView
  and `paysInApp()` tells the frontend to navigate directly. Not built.

Not checked: a full payment on a real phone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 18:40:10 +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ِ بک‌اند.