Füge Stripe-Abonnements zu deiner KI-Web-App hinzu

Monetarisiere deine KI-Web-App durch das Hinzufügen von Stripe-Abonnements (monatlich und jährlich).

Roadmap & Ressourcen

Voraussetzungen (bevor du beginnst)

Checkliste der Voraussetzungen

Stelle sicher, dass du diese Elemente bereit hast, bevor du beginnst.

Bevor du diesem Stripe-Tutorial folgst, stelle sicher, dass deine Web-App bereits Folgendes bereit hat:

1. Deine App ist bereits bereitgestellt (Live-URL erforderlich)

Stripe Checkout funktioniert nur auf einer echten bereitgestellten Website — es funktioniert NICHT in der Vorschau-Umgebung von Google AI Studio.

Deployment-Video

Deployment-Tutorial ansehen

https://youtu.be/HGs-4QjyjHQ?si=EBUOpPx38n9vVROR

---

2. Firebase ist vollständig eingerichtet (ein Video deckt alles ab)

Dein Firebase-Setup muss bereits abgeschlossen sein, einschließlich: - Firebase Authentication aktiviert - Firestore Database erstellt - Deine Web-App mit Firebase verbunden (über deine Firebase-Konfiguration)

Video zur Firebase-Einrichtung

Firebase-Tutorial ansehen

https://youtu.be/juEfJERgBE8?si=je5VF4gKMUJXl8kX

---

✔ Sobald diese Voraussetzungen bereit sind, kannst du ohne Probleme mit Schritt 1 → Schritt 5 fortfahren.

Monatliche und jährliche Abonnement-Pläne erstellen

Öffne Stripe und wechsle in den Test Mode

Erstelle einen monatlich wiederkehrenden Abonnement-Plan

Erstelle einen jährlich wiederkehrenden Abonnement-Plan

Speichere die erforderlichen Stripe-Werte für die spätere Verwendung

Verbinde Stripe-Zahlungen mit deiner App

Öffne Firebase → Extensions

Installiere "Run Payments with Stripe" (von Invertase)

Füge deinen Stripe Secret Key in die Extension-Einstellungen ein

Erstelle einen Webhook in Stripe (wähle die erforderlichen Events aus)

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

Kopiere die Webhook Endpoint URL aus Firebase Functions und füge sie in Stripe ein

Kopiere das Signing Secret von Stripe und füge es in Firebase ein (Webhook Secret)

Speichere und bestätige, dass alles verbunden ist

Erfolgs- und Abbruchseiten der Zahlung einrichten

Öffne dein Projekt in Google AI Studio

Führe Prompt #1 aus: Erstelle die Billing-Konfiguration (bereitgestellte URL + Price IDs)

Prompt: Billing-Konfiguration erstellen

Erstelle eine Billing-Konfigurationsdatei und fülle sie mit meinen echten Werten…

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.

Führe Prompt #2 aus: Erstelle die Erfolgs- und Abbruchseiten

Prompt: Erfolgs- und Abbruchseiten erstellen

Füge zwei einfache Routen/Seiten für Stripe-Weiterleitungen hinzu…

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.

Führe die Prompts aus und bestätige, dass die Dateien/Seiten hinzugefügt wurden

Sorge dafür, dass der Upgrade-Button Stripe Checkout öffnet

(Optional) Erstelle einen Upgrade-Button

Führe Prompt #3 aus: Füge das Monatlich/Jährlich-Auswahl-Modal hinzu

Prompt: Upgrade-Auswahl-UI hinzufügen

Füge eine einfache Upgrade-Auswahl-UI hinzu, ohne die App neu zu gestalten…

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.

Führe Prompt #4 aus: Verbinde die Auswahl mit Stripe Checkout

Prompt: Stripe Checkout verbinden

Implementiere den Stripe-Abonnement-Checkout mit der Firebase Stripe-Extension…

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)

Teste Zahlungen mit deiner bereitgestellten Live-URL

Führe Prompt #5 aus: Aktualisiere das Konto automatisch von Free → Pro

Prompt: Erkennung des Pro-Plans

Füge die Erkennung des Pro-Plans (nur lesend) aus Firestore hinzu…

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.

Führe Prompt #6 aus: Füge Manage Subscription hinzu und verbinde es mit dem Stripe Billing Portal

Prompt: Manage-Subscription-Button

Aufgabe: Füge einen funktionierenden „Manage Subscription“-Button für PRO-Nutzer hinzu…

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- vs Pro-Limits hinzufügen (echte SaaS-Einrichtung)

Führe Prompt #7 aus: Füge Free- vs Pro-Limits hinzu

Prompt: Nutzungs-Limits hinzufügen

Aufgabe: Füge Free/Pro-Nutzungs-Limits hinzu, OHNE das bestehende Billing/Upgrade-System anzufassen oder zu ändern…

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-Regeln hinzufügen (Nutzer können nur auf ihre eigenen Daten zugreifen)

Wichtig: Diese Firestore-Sicherheitsregeln sind ein Beispiel. Du MUSST sie überprüfen und an die Datenstruktur deiner eigenen Web-App anpassen. Jede App benötigt Regeln, die zu ihren spezifischen Collections und ihrem Datenmodell passen.

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-Regeln hinzufügen (Nutzer können nur auf ihre eigenen Dateien zugreifen)

Wichtig: Diese Storage-Sicherheitsregeln sind ein Beispiel. Du MUSST sie überprüfen und an deinen eigenen Projektpfad (zum Beispiel den Namen des uploads-Ordners) und deine Limits anpassen. Jede App benötigt Storage-Regeln, die zu ihrer eigenen Struktur passen.

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); } } }

(Optional) Führe einen schnellen Prompt für kleine UI-Korrekturen aus (zum Beispiel das Aktualisieren der Preise im Modal)

Du kannst später einen zusätzlichen Prompt ausführen, um UI-Details zu verfeinern (wie das Aktualisieren der Preise im Modal), aber wir stellen hier keinen spezifischen Prompt bereit, da dies stark von deinen spezifischen UI-Anpassungen abhängt.