Перейти до вмісту

Тарифи та білінг

ПолеЗначення
Статус🚧 в розробці (мікс: підписки Free/Pro/Max — backend-only, нічого не gate-ять; tutor-tokens — 🟢 prod)
Поверхніweb (підписки — лише backend; tutor-tokens — web UI + bot заплановано)
Доступністьtutor-tokens — потрібен акаунт для покупки (каталог пакетів публічний); підписки Free/Pro/Max — недоступні користувачу (нема UI, плани не засіяні)
ВласникTODO:
Останнє підтвердження2026-06-14 · curl (api.abitly.org/tutor/tokens/packages — 3 живі пакети; /subscriptions/plans[]; abitly.org/uk/tutor — жива сторінка) + код:main (abitly-api-v2, abitly-frontend-v2)

Описує дві паралельні монетизаційні моделі платформи та їхній реальний стан:

  1. Підписки Free / Pro / Max — багаторівневі тарифи з помісячним білінгом і per-plan фічами. Повністю реалізовані в api-v2 (модуль subscriptions), але на момент перевірки нічого не обмежують: фронтенд не має ні сторінки тарифів, ні API-клієнта, плани в проді не засіяні (/subscriptions/plans[]), а FeatureResolverService не викликається жодним продуктовим модулем.
  2. AI-tutor токени — разові покупки пакетів токенів, якими користувач оплачує звернення до AI-тьютора. Це жива prod-монетизація: публічний каталог пакетів, оплата через Monobank, баланс гейтить надсилання повідомлень тьютору.

Окремо від тарифів існує модель premium one-off (разові покупки навчальних матеріалів) — інша поверхня оплати, описана у своїй картці.

Точка входу: https://abitly.org/uk/tutor (роут /tutor, без локалізованого перейменування в PATHNAMES).

  1. Лендинг тьютора показує блок пакетів (PricingSection / LandingPackageCard) — дані з публічного GET /tutor/tokens/packages (не потребує логіну).
  2. Купівля пакета: гість → Google-логін; залогінений → POST /tutor/tokens/purchase { packageSlug, returnUrl } → редирект на Monobank.
  3. Повернення на /tutor/purchase/success — пулінг GET /tutor/tokens/order-status?orderId=… до walletCreditedAt (токени зараховано в гаманець).
  4. У чаті тьютора баланс показує BalancePill; при нестачі токенів — InsufficientTokensModal (стрім тьютора повертає balance_exhausted).

Платіжний редирект — той самий рейл, що й матеріали: data-flows — оплата Monobank. Особливість: після оплати webhook не просто помічає ордер як paid, а кредитує зовнішній tutor-wallet (TutorWalletClientService), із lease-таймстампом і звіркою через wallet-reconciler.cron.

Підписки Free/Pro/Max (🚧 backend-only)

Section titled “Підписки Free/Pro/Max (🚧 backend-only)”

Користувацького flow немає — нема сторінки тарифів і API-клієнта на фронтенді. Спроєктований backend-flow (для довідки, не доступний у проді):

  1. GET /subscriptions/plans — список активних планів із фічами (сторінка тарифів). У проді зараз повертає [].
  2. POST /subscriptions/subscribe { planSlug } — Free → одразу ACTIVE; платний → PENDING_PAYMENT + Monobank-інвойс.
  3. POST /subscriptions/change-plan — апгрейд (одразу, з пропорційним донарахуванням) / даунгрейд (з кінця періоду).
  4. POST /subscriptions/cancel — скасування в кінці періоду.
  5. Помісячне поновлення — щоденний крон 08:00 UTC створює новий Monobank-інвойс (нативного recurring у Monobank немає). Деталі станів і крону — у домен-доці api-v2.
ДжерелоЕндпоінт / entityПризначення
api-v2GET /tutor/tokens/packages (public)каталог пакетів токенів — 3 живі: small_250 (49₴/250), best_1000 (149₴/1000), power_2000 (249₴/2000)
api-v2POST /tutor/tokens/purchase · GET /tutor/tokens/order-status (JWT) + Monobank webhookпокупка токенів; entity TokenOrder (таблиця nmt_tests.tutor_token_orders)
api-v2GET /subscriptions/plans (public) · /subscriptions/me · /subscribe · /change-plan · /cancel · /features[/:key] (JWT)модуль підписок — робочі ендпоінти, але без споживачів на фронтенді; /plans у проді → []
api-v2entities Plan, PlanFeature, UserFeatureOverride, Subscription, SubscriptionInvoiceтарифи, key-value фічі плану, per-user override, підписка, інвойси (shared Postgres)
api-v2admin POST/PATCH/DELETE /admin/subscriptions/plans[…]CRUD планів/фіч, guard AdminApiKeyGuard (X-Admin-Key) — плани засіваються лише адміном

Per-feature першоджерело — домен-доки api-v2: subscriptions/overview, plans-and-features.

Зв’язки з іншими фічами

Section titled “Зв’язки з іншими фічами”
  • Checkout Monobank — спільний платіжний рейл для покупки токенів і (потенційно) підписок; той самий merchant, різні webhook-URL і reference.
  • Навчальні матеріали — окрема монетизація (premium one-off), не тариф; разом із підписками шарить MonobankService із BillingModule.
  • Автентифікація — покупка токенів і підписка вимагають JWT; pending-purchase resume після Google-логіну.
  • AI-тьютор (/tutor) — споживач токенів; картки тьютора ще немає (див. індекс).
РепоШляхПримітка
abitly-api-v2src/api/subscriptions/**модуль Free/Pro/Max: контролери, feature-resolver.service.ts, subscription-billing.{service,cron}.ts, guards/admin-api-key.guard.ts
abitly-api-v2src/api/tutor-billing/** · src/database/entities/tokenOrder.tsпокупка токенів: контролер, webhook, tutor-wallet-client.service.ts, wallet-reconciler.cron.ts
abitly-api-v2src/api/tutor/** · src/api/billing/**AI-тьютор (/tutor/sessions, guard TutorDevAuthGuard → у проді = JWT); MonobankService спільний у BillingModule
abitly-frontend-v2src/app/[locale]/(main)/tutor/** · src/components/pages/ai-tutor/**лендинг тьютора з PricingSection, /tutor/purchase/success
abitly-frontend-v2src/api/tokens/** · src/components/pages/shared/Tutor/components/Tokens/**API-клієнт токенів; BalancePill, InsufficientTokensModal
abitly-frontend-v2немає клієнта /subscriptions/* і сторінки тарифів Free/Pro/Max (підтверджено пошуком по src/)
  • Підписки нічого не gate-ять. FeatureResolverService (override → план → free-fallback) існує і покритий тестами, але getFeatureValue/getAllFeatures викликаються виключно всередині модуля subscriptions (для GET /subscriptions/features) і в тестах. Жоден продуктовий модуль (offers, materials, nmt-test, vstuplysty…) не імпортує SubscriptionsModule і не звертається до резолвера → ліміти планів (напр. max_saved_offers, has_analytics) не діють.
  • Підписки не мають UI і не засіяні в проді. Фронтенд не має сторінки тарифів чи API-клієнта; GET /subscriptions/plans у проді → [], GET /subscriptions/features/max_saved_offers (anon) → {"value":null}. Засів планів — лише через адмін-ендпоінти (AdminApiKeyGuard).
  • tutor-tokens — жива, але вузька монетизація: покриває лише AI-тьютора, не дає доступу до інших платних фіч. Каталог пакетів публічний; покупка і баланс — за JWT.
  • Token credit — багатокроковий: webhook не лише помічає ордер paid, а кредитує зовнішній wallet через TutorWalletClientService; невдалий кредит підхоплює wallet-reconciler.cron (walletCreditAttemptedAt lease). cost_unitsbigint, не приводити до Number(). ⚠️ Суми пакетів продубльовані whitelist-ом у tutor-сервісі — міняти лише «трійкою», інакше кредити мовчки 400-яться: див. інцидент 2026-07-16.
  • Power-вартість vs. ціна: ціни/розміри пакетів і priceCoins приходять із backend (/tutor/tokens/packages); не хардкодити на фронтенді.
  • Власник фічіTODO:.
ДатаПодіяДжерело
TODO:реліз модуля subscriptions (Free/Pro/Max + billing) у main — без споживачів-гейтівabitly-api-v2
TODO:реліз tutor-tokens (AddTutorTokenOrders) і прод-лендингу /tutorabitly-api-v2 / abitly-frontend-v2
2026-06-14створено картку; розмежовано prod (tutor-tokens) vs. dormant backend (Free/Pro/Max); гейтинг звірено пошуком call-site + live APIPR Wave 1
2026-07-16інцидент: 45 днів покупки токенів не кредитували гаманець (дрейф whitelist у tutor); виправлено + бекфіл — пост-мортемabitly-AI-tutor@cdf904c