Taking an app to production means stacking layers on top of what already works. The diagram below shows the order: start with the live app, protect it with authentication and RLS, monetize it with payments, and finally connect external workflows via webhook.
Illustrative diagram — conceptual recreation of the production layers, not a real screenshot.
🛡️ Why authenticate
An app without login is an app open: anyone with the URL can trigger the workflow and consume your AI tokens — and you pay for other people's usage. Authentication solves two problems at once: it protects the use (only registered users can trigger the backend) and protects the data (each person sees only their own).
💡 The risk of an open app
While the app is running in production without authentication, your tokens are ticking away for anyone. Adding login is the first step toward “real production” — before thinking about revenue, you close the door.
- •Usage: only authenticated users trigger the workflow.
- •Data: each user has their own, isolated from everyone else.
- •Cost: you stop paying for other people’s usage.
✗ App open in production
- ✗Any shared URL uses up your tokens.
- ✗Without users, there’s no way to isolate data.
- ✗Without login, there’s no way to charge later.
✓ Authenticated app
- ✓Login/signup filters who can trigger the backend.
- ✓Each user has their own protected data.
- ✓Base ready for free and paid tiers.
🎯 Practical tip
Don’t leave an unauthenticated app online for long. Login is the first layer of production—everything else (fine-grained security, payments) builds on it.
🔑 Authentication with Supabase
O Supabase acts as the database and authentication provider: in Plan Mode, you ask the AI to add login/sign-up to the app using Supabase. On the platform side, you create the project and define the database password (separate from the login password) and choose the region.
Supabase setup
Create the project
Set the database password (different from your login password!) and choose the region closest to your users.
Copy URL + publishable key
Get the project URL and publishable key from Supabase to use as environment variables.
Add as env vars in Vercel
Set the URL and key as environment variables in Vercel and redeploy so the frontend can connect to Supabase.
⚠️ Attention
- ✗The database password no is the login password—keep the two separate.
- ✗Secrets only in env vars; never in frontend code or chat.
Database + auth ready to go.
≠ login password.
Close to the user.
Environment variables in Vercel.
🧱 Row-Level Security (RLS)
Row-Level Security are rules that live inside the database, not in the interface code. They ensure that a user sees only their own rows—even if there's a frontend bug. It's a layer of defense that doesn't depend on the screen code being perfect: a lock at the deepest level.
✗ No RLS
- ✗A frontend bug can expose another user’s data.
- ✗Security depends entirely on the screen’s code.
- ✗A single failure exposes the entire database.
✓ With RLS enabled
- ✓The database refuses to return rows belonging to another user.
- ✓Defense in depth: an extra safeguard beyond the frontend.
- ✓Row-level isolation at the lowest level.
🧭 Defense in depth
Good security doesn't rely on a single layer. RLS works alongside authentication: even if the login is bypassed or the screen has a bug, the database continues to reject anything that doesn't belong to the user. Enable RLS on the table and test it.
🎯 Practical tip
Treat RLS as non-negotiable: enable it from the start and confirm in the security audit that it is enabled on every table with user data.
Not in the frontend.
Isolates data.
Defense in depth.
In the table, and test.
🗄️ SQL migration & auth URLs
Two settings make authentication work end to end. A SQL migration: run the AI-generated SQL in the Supabase SQL editor to create the table (e.g., the leads table). And the Auth URLs: configure the app URL (Vercel) and the redirect URL so the login returns to the app correctly.
-- migração gerada pela IA create table leads ( id uuid primary key default gen_random_uuid(), user_id uuid references auth.users not null, empresa text, score int, created_at timestamptz default now() ); -- liga o Row-Level Security alter table leads enable row level security;
🗄️ SQL migration
- •Open the Supabase SQL editor.
- •Paste and run the SQL generated by the AI.
- •Confirm the table was created (e.g., leads).
🔗 Auth URLs
- •Set the app URL (the Vercel one).
- •Set the login redirect URL.
- •Under authentication → URL configuration.
🎯 Practical tip
If the login "works" but doesn't return to the app, the redirect URL is almost always the likely culprit. Confirm that the Vercel URL and redirect URL are exact in the Supabase auth settings.
Run the migration.
Created with SQL.
The Vercel one.
Returns from login.
🔎 Security audit
Before moving on, do a explicit audit: clear the conversation and ask the AI to act as a security expert and review the app. An audit requested deliberately catches vulnerabilities that slip by in day-to-day work — and gives you a clear list of what to fix.
The audit checklist
Protected routes
Confirm that sensitive pages/endpoints require an authenticated user.
No exposed keys
Ensure that no API key appears in the frontend (which runs in the user's browser).
Secrets only in env vars
Check that all secrets come from environment variables, never from version-controlled code.
RLS active
Verify that Row-Level Security is enabled on all tables containing user data.
✓ Passed the audit
- ✓Sensitive routes require login.
- ✓No keys in the frontend.
- ✓RLS confirmed on all tables.
✗ Red Flags
- ✗Endpoint accessible without authentication.
- ✗Secret key reaching the browser.
- ✗Table with user data and no RLS.
🎯 Practical tip
Request an audit with an explicit scope ("review protected routes, exposed keys, secrets in env, and RLS"). The more specific the request, the more useful the report — and fix anything that fails before moving on.
💳 Stripe: Freemium Model
With the Stripe, the app becomes a SaaS: a model freemium with a limited free tier and a subscription-based paid tier, via Stripe Checkout. The motivation is the same as for authentication—limiting usage so you don't pay for users' unlimited AI consumption—but now there's revenue on the other side.
🆓 Free Tier
Limited—for example, 2 lead qualifications per day.
- •Lets you try out the app.
- •The limit controls your token costs.
⭐ Pro Tier
Subscription — e.g., US$ 29/month, unlimited qualifications.
- •Recurring billing through Checkout.
- •Revenue that sustains the app.
🧭 From workflow to product
Payment completes the transition: what started as “just a workflow” is now an app that can generate revenue. In Plan Mode, the AI creates the packages, env vars, tables, the Stripe client/server, the pricing page, and updates the navbar.
🎯 Practical tip
Think of freemium as two linked goals: the free tier protects your costs, and the paid tier generates revenue. Set the free limit with actual token usage in mind.
Free + paid.
Controls cost.
Recurring.
Payment flow.
🧾 Product, Keys & Stripe Webhook
The Stripe integration brings together four pieces from different points in time. You create the recurring product and copies the price ID; gets the keys (publishable + secret); create the webhook pointing to your URL with the right events; and runs the subscription table migration in Supabase.
The integration pieces
Recurring product + price ID
Create a monthly subscription product, set the price, and copy the price ID.
Keys: publishable + secret
Under developers → API keys, copy the publishable key and the secret key.
Webhook + events + webhook secret
Create an endpoint pointing to the Vercel URL + /api/stripe-webhook, listening for checkout.session.completed and subscription events; copy the webhook secret.
Subscription table migration
Run the generated SQL to create the subscriptions table and add the four keys as env vars in Vercel; redeploy.
⚠️ Attention
- ✗Use the exact webhook URL provided by the AI — don’t make one up.
- ✗Keep a notepad to paste keys/IDs into during the process.
- ✗Test checkout with a test card (future date, any CVC).
From the product.
Publishable + secret.
Events + secret.
Table in the database.
🪝 Frontend for n8n Workflow
To give an n8n workflow a polished interface, the standard approach is to replace two nodes: the first (the form) with a Webhook trigger, and the last per node “Respond to Webhook”. The frontend (generated and improved with the design skill) sends the data to the webhook URL and displays the response—connected through an env var in Vercel.
Convert the workflow + connect the frontend
Replace the first node with a Webhook
Remove the form node and add a Webhook trigger, connecting it to the existing logic.
Replace the last node with "Respond to Webhook"
Remove the final output node and add "Respond to Webhook" to return the response to the frontend.
Publish and copy the production URL
Publish the workflow in n8n and copy the webhook's production URL (not the test URL).
Connect via an env var in Vercel
Add the n8n webhook URL as an env var in Vercel and redeploy; test by filling out the form in production.
🎯 Practical tip
The pattern for connecting any n8n workflow to a website is always the same: replace the first and last nodes with webhooks. Make sure the workflow is published before copying the URL—and always use the production one.
Replaces the form.
Returns the response.
Published URL.
Connects to Vercel.
🪜 Incremental Iteration (Recap)
The entire journey is a lesson in incremental iteration: the app started as a one-sentence prompt and grew in layers — design → authentication → payment → integration. Good engineering works like this: start small, publish early, and scale as needed, without planning everything all at once.
The layers, in order
App + design
From idea to live app, with professional design that doesn’t look AI-generated (Module 4.1).
Authentication + security
Real users with their data protected: Supabase, RLS, and auditing.
Payment + integration
Subscription revenue with Stripe and external workflows connected by webhook.
✓ Incremental iteration
- ✓Start small and publish the first version.
- ✓Grow in layers, one feature at a time.
- ✓Gather real feedback across the layers.
✗ Big Bang
- ✗Try planning everything before publishing anything.
- ✗Add design, auth, and payments all at once.
- ✗Delay the launch while waiting for the “perfect version.”
🎯 Practical tip
Learning path outcome: you can connect a backend/logic to a polished frontend that people actually use. You don’t need to plan everything in advance—ship small and grow in layers.
Self-healing (optional): why is Row-Level Security an extra layer of security?
📌 Module Summary
End of the trail:
You went from concept to a real app live on the web—with automations, deployment, authentication, and payments. Time to build your own.