AI Web Uygulamanıza Stripe Abonelikleri Ekleyin
Stripe abonelikleri (aylık ve yıllık) ekleyerek AI web uygulamanızdan para kazanın.
Yol Haritası ve Kaynaklar
Gereksinimler (Başlamadan Önce)
Ön Koşullar Kontrol Listesi
Başlamadan önce bunların hazır olduğundan emin olun.
Bu Stripe eğitimini takip etmeden önce web uygulamanızda şunların hazır olduğundan emin olun:
1. Uygulamanız Zaten Yayında (Canlı URL Gerekli)
Stripe Checkout yalnızca gerçekten yayına alınmış bir web sitesinde çalışır — Google AI Studio önizleme ortamında ÇALIŞMAZ.
Yayına Alma Videosu
Yayına Alma Eğitimini İzleyin
https://youtu.be/HGs-4QjyjHQ?si=EBUOpPx38n9vVROR
---
2. Firebase Tamamen Kurulu (Tek Video Her Şeyi Anlatıyor)
Firebase kurulumunuz halihazırda tamamlanmış olmalıdır; buna şunlar dahildir: - Firebase Authentication etkinleştirilmiş - Firestore Database oluşturulmuş - Web uygulamanız Firebase'e bağlanmış (kendi Firebase yapılandırmanızla)
Firebase Kurulum Videosu
Firebase Eğitimini İzleyin
https://youtu.be/juEfJERgBE8?si=je5VF4gKMUJXl8kX
---
✔ Bu gereksinimler hazır olduğunda, Adım 1 → Adım 5 arasında sorunsuz şekilde devam edebilirsiniz.
Aylık ve Yıllık Abonelik Planları Oluşturun
Stripe'ı açın ve Test Mode'a geçin
Aylık yinelenen abonelik planı oluşturun
Yıllık yinelenen abonelik planı oluşturun
Gerekli Stripe değerlerini daha sonra kullanmak üzere kaydedin
Stripe Ödemelerini Uygulamanıza Bağlayın
Firebase → Extensions bölümünü açın
"Run Payments with Stripe" eklentisini kurun (Invertase tarafından)
Stripe Secret Key'inizi eklenti ayarlarına yapıştırın
Stripe'ta bir Webhook oluşturun (gerekli olayları seçin)
- checkout.session.completed
- customer.subscription.created
- invoice.paid
- invoice.payment_failed
- customer.subscription.updated
- customer.subscription.deleted
- invoice.upcoming
- payment_intent.succeeded
- payment_intent.payment_failed
- customer.subscription.paused
- charge.refunded
- charge.dispute.created
Firebase Functions'tan Webhook Endpoint URL'sini kopyalayın ve Stripe'a yapıştırın
Stripe'ın Signing Secret değerini kopyalayın ve Firebase'e yapıştırın (Webhook Secret)
Kaydedin ve her şeyin bağlı olduğunu doğrulayın
Ödeme Başarılı ve İptal Sayfalarını Kurun
Projenizi Google AI Studio'da açın
Prompt #1'i çalıştırın: Faturalandırma Yapılandırmasını Oluşturun (Yayına Alınmış URL + Price ID'ler)
Prompt: Faturalandırma Yapılandırması Oluşturun
Bir faturalandırma yapılandırma dosyası oluşturun ve gerçek değerlerimle doldurun...
Create a billing config file and fill it with my real values (no placeholders). Use EXACTLY: DEPLOYED_URL = "https://deployment-url.com" MONTHLY_PRICE_ID = "price_MONTHLY_HERE" YEARLY_PRICE_ID = "price_YEARLY_HERE" Create: src/billingConfig.js (or .ts if the project is TypeScript) and export: - DEPLOYED_URL - MONTHLY_PRICE_ID - YEARLY_PRICE_ID - A function successUrl() that returns the correct URL for /success - A function cancelUrl() that returns the correct URL for /failure Important: - Detect if the app uses hash routing automatically: If existing routes contain "/#/" then use DEPLOYED_URL + "/#/success" and "/#/failure" Otherwise use DEPLOYED_URL + "/success" and "/failure" Do not change any existing UI or app logic. Return only the new file content.
Prompt #2'yi çalıştırın: Success + Cancel sayfalarını oluşturun
Prompt: Başarılı ve İptal Sayfaları Oluşturun
Stripe yönlendirmeleri için iki basit rota/sayfa ekleyin...
Add two simple routes/pages for Stripe redirects: success and failure. Success page: - Text: "Payment successful" - Redirect to dashboard after 1.5 seconds Failure page: - Text: "Payment cancelled" - Redirect to dashboard after 1.5 seconds Use the same routing style already used in the project (hash or normal). Do not redesign UI. Return exact files changed.
Prompt'ları çalıştırın ve dosyaların/sayfaların eklendiğini doğrulayın
Yükseltme Butonunun Stripe Checkout'u Açmasını Sağlayın
(İsteğe bağlı) Yükseltme butonu oluşturun
Prompt #3'ü çalıştırın: Aylık/Yıllık seçim modalını ekleyin
Prompt: Yükseltme Seçim Arayüzü Ekleyin
Uygulamayı yeniden tasarlamadan basit bir yükseltme seçim arayüzü ekleyin...
Add a simple upgrade choice UI without redesigning the app. When the user clicks the existing Upgrade button: - Show a small modal (or dropdown) with 2 options: 1) Monthly 2) Yearly - Add a close button. Keep current styling. Do not change any other UI. Return exact files changed.
Prompt #4'ü çalıştırın: Seçimi Stripe Checkout'a bağlayın
Prompt: Stripe Checkout'u Bağlayın
Firebase Stripe Extension kullanarak Stripe abonelik ödemesini uygulayın...
Implement Stripe subscription checkout using Firebase Stripe Extension. On Monthly selection: - Create a Firestore doc at: customers/{uid}/checkout_sessions/{autoId} - Fields: price: MONTHLY_PRICE_ID (import from billingConfig) mode: "subscription" success_url: successUrl() (import from billingConfig) cancel_url: cancelUrl() (import from billingConfig) On Yearly selection: - Same but price: YEARLY_PRICE_ID After creating the doc: - Listen to that same checkout session document until it contains a field "url" - Redirect the browser to that url Do not add Stripe secret keys to frontend. Do not touch existing CRUD features. Return exact files changed. Test payments using your deployed live URL (not the preview)
Ödemeleri yayına alınmış canlı URL'nizi kullanarak test edin
Prompt #5'i çalıştırın: Hesabı Free → Pro olarak otomatik güncelleyin
Prompt: Pro Plan Tespiti
Firestore'dan Pro plan tespiti (salt okunur) ekleyin...
Add Pro plan detection (read-only) from Firestore. - Listen in real-time (onSnapshot) to: customers/{uid}/subscriptions - Set isPro = true if any subscription status is "active" or "trialing" - If isPro true: - Show a "Pro" badge - Hide the Upgrade button - If isPro false: - Show a "Free" badge - Show the Upgrade button Important: Do NOT block Free users from using the app features. Do not redesign UI. Return exact files changed.
Prompt #6'yı çalıştırın: Manage Subscription ekleyin ve Stripe Billing Portal'a bağlayın
Prompt: Abonelik Yönetimi Butonu
Görev: PRO kullanıcılar için çalışan bir "Manage Subscription" butonu ekleyin...
Task: Add a working "Manage Subscription" button for PRO users using Stripe Customer Portal (Firebase Stripe Extension). Context: - The app already uses the Firebase Stripe Extension (customers/{uid} and checkout_sessions work). - The app uses hash routing (/#/dashboard). - Do NOT change the UI design. Only add logic. - The button must work in production (no CORS errors). Requirements: 1) Show "Manage Subscription" button ONLY when the current user is PRO (isPro === true). 2) On click, DO NOT call any cloudfunctions.net URL directly and DO NOT use fetch to Cloud Functions. 3) Instead, create a Firestore document at: customers/{uid}/portal_sessions/{autoId} with fields: - return_url: "https://vloma.com/#/dashboard" 4) After creating the doc, listen in real-time to that same document until the extension writes a field: - url Then redirect the browser to that url (window.location.href = url). 5) Add basic UX: - disable the button while loading - show a friendly alert if no url appears after 20 seconds - log the real error to console Implementation notes: - Use the existing Firebase client (auth + firestore). - Keep existing files structure. Modify only the minimal files needed. - Return the exact files changed and the exact code changes. Deliverable: - A working Manage Subscription button that opens Stripe Customer Portal and returns to /#/dashboard.
Free ve Pro Limitlerini Ekleyin (Gerçek SaaS Kurulumu)
Prompt #7'yi çalıştırın: Free ve Pro limitlerini ekleyin
Prompt: Kullanım Limitleri Ekleyin
Görev: Mevcut faturalandırma/yükseltme sistemine DOKUNMADAN veya onu değiştirmeden Free/Pro kullanım limitleri ekleyin...
Task: Add Free/Pro usage limits WITHOUT touching or changing the existing billing/upgrade system. CRITICAL RULES (must follow): - DO NOT modify the existing Stripe checkout / upgrade code. - DO NOT modify how "isPro" is determined in the project. - DO NOT create or use users/{uid}.plan field (do not add plan to Firestore at all). - DO NOT change Firestore rules or Storage rules. - Keep UI the same (only small toast/alert/modal allowed). Limits: - FREE: max 5 files, max 5 folders, max 100MB total stored - PRO: max 50 files, max 50 folders, max 5GB total stored How to implement (safe approach): 1) Use the CURRENT existing "isPro" boolean/state already working in the app. - Whatever source it currently uses (Stripe Extension subscriptions / custom claims / existing code), keep it exactly as-is. - Only READ isPro, do not re-implement it. 2) Track usage from the existing Firestore structure (do not rename collections): - Files count = number of docs in users/{uid}/files - Folders count = number of docs in users/{uid}/folders - Total storage used = sum of file sizes from the file docs (field: size bytes). If old docs don’t have size, treat missing size as 0, and ensure new uploads always write size. 3) Enforce limits ONLY in the UI/Client for now: - Before creating a new file doc or uploading: check limits using current isPro. - Before creating a new folder doc: check limits using current isPro. - If Free exceeds limit: block action and show: “Free plan limit reached. Upgrade to Pro to continue.” Add an “Upgrade” button that triggers the EXISTING checkout flow (call the same function already used in the app). 4) IMPORTANT: After checkout completes, the app MUST refresh/reflect Pro automatically: - Do not add new plan logic. - Just ensure the same existing listener/state updates isPro and the UI re-checks limits. - Add a small debug log (console.log) showing current isPro value after returning from checkout. Deliverable: - Limits work and show upgrade prompt. - Paying and upgrading still changes the app to Pro exactly like before. - Return exact files changed.
Firestore Kuralları Ekleyin (kullanıcılar yalnızca kendi verilerine erişebilir)
Önemli: Bu Firestore güvenlik kuralları bir örnektir. Bunları kendi web uygulamanızın veri yapısına uyacak şekilde MUTLAKA gözden geçirmeli ve uyarlamalısınız. Her uygulamanın kendi koleksiyonlarına ve veri modeline uygun kurallara ihtiyacı vardır.
firestore.rules
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { function signedIn() { return request.auth != null; } function isOwner(uid) { return signedIn() && request.auth.uid == uid; } // ------------------------- // Users data (your app data) // ------------------------- match /users/{uid} { allow read, write: if isOwner(uid); // Everything under this user is also only for the owner match /{allPaths=**} { allow read, write: if isOwner(uid); } } // ------------------------- // Stripe Extension // customers/{uid}/... // ------------------------- match /customers/{uid} { // user can read their stripe docs allow read: if isOwner(uid); // user must NOT write to stripe docs directly allow write: if false; // user can create a checkout session doc match /checkout_sessions/{id} { allow create, read: if isOwner(uid); allow update, delete: if false; } // user can create a portal session doc match /portal_sessions/{id} { allow create, read: if isOwner(uid); allow update, delete: if false; } // subscriptions/payments are server-controlled (read only) match /subscriptions/{id} { allow read: if isOwner(uid); allow write: if false; } match /payments/{id} { allow read: if isOwner(uid); allow write: if false; } } } }
Storage Kuralları Ekleyin (kullanıcılar yalnızca kendi dosyalarına erişebilir)
Önemli: Bu Storage güvenlik kuralları bir örnektir. Bunları kendi proje yolunuza (örneğin uploads klasörünün adı) ve limitlerinize uyacak şekilde MUTLAKA gözden geçirmeli ve uyarlamalısınız. Her uygulamanın kendi yapısına uygun storage kurallarına ihtiyacı vardır.
storage.rules
rules_version = '2'; service firebase.storage { match /b/{bucket}/o { function signedIn() { return request.auth != null; } function isOwner(uid) { return signedIn() && request.auth.uid == uid; } match /user_uploads/{uid}/{allPaths=**} { allow read: if isOwner(uid); // write create/update/delete // request.resource null delete، allow write: if isOwner(uid) && (request.resource == null || request.resource.size <= 200 * 1024 * 1024); } } }
(İsteğe bağlı) Küçük arayüz düzeltmeleri için hızlı bir prompt çalıştırın (örneğin, modaldaki fiyatları güncellemek)
Arayüz ayrıntılarını (modaldaki fiyatları güncellemek gibi) cilalamak için daha sonra ek bir prompt çalıştırabilirsiniz, ancak bu büyük ölçüde sizin arayüz özelleştirmelerinize bağlı olduğundan burada özel bir prompt vermiyoruz.