DEV Community

Cover image for How to Add Team Collaboration to Your AI-Generated App (v0, Lovable, Bolt, Base44) Without Writing Code
Shola Jegede
Shola Jegede Subscriber

Posted on

How to Add Team Collaboration to Your AI-Generated App (v0, Lovable, Bolt, Base44) Without Writing Code

You built an app with v0, Lovable, Bolt, or Base44 in minutes. Now your team needs to use it with different access levels. Here is how to add the entire collaboration layer without touching a single line of code yourself.

In this article, you will learn:

  • Why AI-generated apps ship without user management and what that means for your team
  • What real multi-user collaboration actually requires under the hood
  • How to build an AI-powered changelog tool in v0 as the demo app
  • How to add Kinde auth, protected routes, roles, and organization workspaces through prompts alone
  • How to test that the collaboration layer actually works

Let's dive in!

What AI Builders Give You and What They Don't

v0, Lovable, Bolt, and Base44 are remarkable. You describe what you want, and in minutes you have a working, deployable application with UI, logic, and routes. This has genuinely changed what one person can ship in an afternoon.

What none of them give you by default is user management. When your AI builder generates an app, everyone who visits the URL sees the same thing. There is no concept of "Alice is an admin and can publish" or "Bob is a viewer and can only read." There are no team workspaces. There is no authentication.

Adding that layer after the fact is where most people get stuck, because it usually means diving into the generated code and understanding how it works, which defeats the whole point.

This article shows you how to do it entirely through prompts, using Kinde for auth, roles, and team management. The demo app is an AI changelog generator, a tool your team can use to turn raw GitHub commits or release notes into polished public changelogs. Admins publish. Members draft. The public reads.

What Real Team Collaboration Requires

Before you prompt anything, being clear on what collaboration actually means in a web app saves a lot of confusion later. Four things need to work together:

Layer What it means What Kinde provides
Authentication Users can sign in and sign out Login, sign-up, passwordless OTP, social login
Identity The app knows who is logged in User object with name, email, ID on every request
Roles Different users can do different things Roles (admin, member, viewer) attached to users
Organizations Users belong to a team workspace Orgs that group users with isolated data

You need all four for a real product. A lot of AI-generated apps nail authentication but skip the rest, and then wonder why every user sees every other user's data.

Kinde handles all four out of the box, free for up to 10,500 monthly active users, no credit card required.

What You Need Before You Start

A v0.app account. Sign up at v0.app. Free tier available. The prompts in this article are written for v0 but work in Lovable, Bolt, and Base44 with minor adjustments.

A Kinde account. Sign up at kinde.com. Free up to 10,500 monthly active users, no credit card.

Once you have your Kinde account, create an application for your project. Navigate to Settings → Applications → Add application. Give it a name, select Back-end web as the application type, and hit Save.

Then open the application you just created and navigate to View details to grab these values:

  • KINDE_CLIENT_ID
  • KINDE_CLIENT_SECRET
  • KINDE_ISSUER_URL (your Kinde domain, e.g. https://yourapp.kinde.com)

And two you define yourself:

  • KINDE_SITE_URL where your app runs locally (http://localhost:3000)
  • KINDE_POST_LOGIN_REDIRECT_URL where users land after login (http://localhost:3000/dashboard)
  • KINDE_POST_LOGOUT_REDIRECT_URL where users land after logout (http://localhost:3000)

Kinde dashboard — Settings > Applications > View details, showing the App keys section with KINDE_CLIENT_ID, KINDE_CLIENT_SECRET, and KINDE_ISSUER_URL fields visible

Keep these open in a tab. You will paste them into v0 shortly.

Step #1: Build the Base App in v0

The demo app is an AI changelog generator. Teams paste in raw commit messages or release notes, the app uses an AI model to turn them into readable entries, and admins publish them to a public page.

Open v0.app and use this prompt:

Prompt:

Build an AI changelog generator for software teams. The app should have:

- A landing page with the product name "Changelog" and two buttons: "Sign in" and "Start free"
- A dashboard at /dashboard with:
  - A sidebar with: Dashboard, New Entry, Published, Team, Settings
  - A main area showing a list of changelog entries as cards, each with: version number, title, date, status badge (Draft / Published), and Edit + Delete buttons
- A "New Entry" page at /dashboard/new with:
  - A text area labeled "Paste your commits or release notes"
  - A "Generate with AI" button
  - A title field, version field, and content editor that populates after generation
  - A "Save as draft" and "Publish" button
- A public changelog page at /changelog showing only published entries in clean readable format

Use Next.js App Router with TypeScript. Clean, minimal design. Do not add any authentication yet.
Enter fullscreen mode Exit fullscreen mode

v0.app showing the changelog dashboard preview — sidebar on left, changelog entry cards in main area, status badges visible

Let v0 generate the app. Once the preview looks right, push it to GitHub using v0's built-in GitHub integration.

Step #2: Wire In Kinde Auth

Now prompt v0 to install Kinde and set up the auth infrastructure. One prompt handles everything.

Prompt:

Add Kinde authentication to this Next.js app using @kinde-oss/kinde-auth-nextjs.

Do the following:
1. Install the package
2. Create the auth route handler at app/api/auth/[kindeAuth]/route.ts using handleAuth from @kinde-oss/kinde-auth-nextjs/server
3. Wrap the root layout in app/layout.tsx with KindeAuthProvider from @kinde-oss/kinde-auth-nextjs/server
4. Create a .env.local file with these placeholder variables:
   KINDE_CLIENT_ID=
   KINDE_CLIENT_SECRET=
   KINDE_ISSUER_URL=
   KINDE_SITE_URL=http://localhost:3000
   KINDE_POST_LOGIN_REDIRECT_URL=http://localhost:3000/dashboard
   KINDE_POST_LOGOUT_REDIRECT_URL=http://localhost:3000
5. No UI changes yet — just the plumbing
Enter fullscreen mode Exit fullscreen mode

Once v0 finishes, click on the Settings button in v0's editor and then go to Environment Variables tab to fill in your actual Kinde values. Do not commit this file to GitHub. It is gitignored by default.

Then add your callback URLs in the Kinde dashboard. Navigate to Settings → Applications → View details → Callback URLs and add:

  • Allowed callback URL: http://<your_v0_published_url>/api/auth/kinde_callback
  • Allowed logout redirect URL: http://<your_v0_published_url>

Kinde dashboard — Settings > Applications > View details > Callback URLs section with the localhost callback URL added

Step #3: Add Login and Sign-Up Buttons

Prompt:

Update the landing page and dashboard to use Kinde auth components.

Do the following:
1. On the landing page (app/page.tsx), replace the "Sign in" button with LoginLink and "Start free" with RegisterLink:

import { LoginLink, RegisterLink } from "@kinde-oss/kinde-auth-nextjs/components";

<LoginLink postLoginRedirectURL="/dashboard">Sign in</LoginLink>
<RegisterLink postLoginRedirectURL="/dashboard">Start free</RegisterLink>

2. In the dashboard sidebar, show the logged-in user's name and email using getKindeServerSession:

import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server";

const { getUser } = getKindeServerSession();
const user = await getUser();

Show user.given_name and user.email in the sidebar footer.

3. Add a sign-out link at the bottom of the sidebar that links to /api/auth/logout
Enter fullscreen mode Exit fullscreen mode

The landing page with

The dashboard sidebar showing the logged-in user's name and email in the footer with a sign-out link

Step #4: Protect the Dashboard Routes

Right now anyone can navigate directly to /dashboard without logging in. The Kinde middleware fixes this with one file.

Prompt:

Add route protection using Kinde middleware.

Create a file at middleware.ts in the project root with exactly this content:

import { withAuth } from "@kinde-oss/kinde-auth-nextjs/middleware";
export default withAuth;
export const config = {
  matcher: ["/dashboard/:path*"]
};

This automatically redirects any unauthenticated request to /dashboard or any sub-route to the Kinde login page.

Also add an authentication check at the top of app/dashboard/page.tsx:

import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server";
import { redirect } from "next/navigation";

const { isAuthenticated } = getKindeServerSession();
if (!(await isAuthenticated())) {
  redirect("/api/auth/login");
}
Enter fullscreen mode Exit fullscreen mode

The public /changelog page stays open to anyone. Everything under /dashboard now requires a logged-in user.

Step #5: Add Roles for Admins, Members, and Viewers

This is where the collaboration layer becomes real. Not everyone on the team should be able to publish or delete changelog entries.

First, create the roles in Kinde. Navigate to Roles → Add role and create three:

  • admin — can publish, edit, delete all entries, and manage team
  • member — can create and edit drafts, cannot publish or delete
  • viewer — read-only access to the dashboard

Kinde dashboard Roles page showing three roles: admin, member, and viewer, each with their key name visible

Assign yourself the admin role: navigate to Users → select your user → Roles → assign admin.

Now prompt v0 to use those roles in the UI:

Prompt:

Add role-based access control to the dashboard using Kinde roles.

The roles are: admin, member, viewer. These are configured in the Kinde dashboard.

Do the following:
1. In app/dashboard/page.tsx, get the user's roles:

const { getRoles } = getKindeServerSession();
const roles = await getRoles();
const isAdmin = roles?.some(role => role.key === "admin");
const isMember = roles?.some(role => role.key === "member" || role.key === "admin");

2. On each changelog entry card:
   - Show "Edit" button for admins and members
   - Show "Delete" button only for admins
   - Show "Publish" button only for admins
   - Viewers see no action buttons

3. In the sidebar:
   - Show "New Entry" link for admins and members only
   - Show "Team" link for admins only
   - Viewers see Dashboard and Published only

4. On the "New Entry" page:
   - Show the "Publish" button only for admins
   - Members see "Save as draft" only

Use conditional rendering, not CSS visibility, so the DOM does not contain controls the user cannot access.
Enter fullscreen mode Exit fullscreen mode

Side-by-side comparison — Admin view showing Edit, Delete, and Publish buttons on entries and full sidebar, vs Viewer view showing no action buttons and reduced sidebar

Step #6: Add Organization Workspaces

Roles tell your app what a user can do. Organizations tell your app what data they can see. Without organizations, every user shares every changelog entry, which means one company's unreleased changelog is visible to everyone else.

Kinde organizations are isolated team workspaces. Each organization has its own members and its own data.

Kinde allows organization creation by default when is_create_org is passed during sign-up. No dashboard setting needs to change. If you ever want to disable this behaviour, the toggle is at Settings → Environment → Policies → Allow organization creation on sign up.

Kinde Settings > Organizations showing

Prompt:

Update the app to support Kinde organizations as team workspaces.

Do the following:
1. Update the "Start free" RegisterLink on the landing page to create an org on sign-up:

<RegisterLink
  authUrlParams={{ is_create_org: "true" }}
  postLoginRedirectURL="/dashboard"
>
  Start free
</RegisterLink>

2. In app/dashboard/page.tsx, get the current org:

const { getOrganization } = getKindeServerSession();
const org = await getOrganization();
const orgCode = org?.orgCode;

3. Show the organization name (org?.name) at the top of the sidebar above the navigation links so users always know which workspace they are in.

4. Add a "Switch workspace" link below the org name linking to /api/auth/login?prompt=select_account for users who belong to multiple organizations.

5. For all data queries (changelog entries), add a comment: // TODO: filter by orgCode so it is clear where the org scoping goes when a real database is connected.
Enter fullscreen mode Exit fullscreen mode

Dashboard sidebar showing the organization name at the top (e.g.

Step #7: Add the AI Generation Feature

The "Generate with AI" button on the New Entry page should take raw commit messages and return a polished changelog entry. v0 can wire this up using the Vercel AI SDK.

Prompt:

Add AI-powered changelog generation to the New Entry page using the Vercel AI SDK.

Do the following:
1. Install the ai and @ai-sdk/openai packages
2. Create a server action at app/actions/generate.ts:

"use server";
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";

export async function generateChangelog(rawInput: string) {
  const { text } = await generateText({
    model: openai("gpt-4o-mini"),
    prompt: `You are a technical writer. Convert the following raw commit messages or release notes into a clean, professional changelog entry. Use plain language a non-technical reader can understand. Format it as a short paragraph followed by a bullet list of changes.

Raw input:
${rawInput}

Return only the changelog text, nothing else.`,
  });
  return text;
}

3. On the New Entry page, wire the "Generate with AI" button to call this action with the content of the text area. Show a loading state while generating. Populate the content editor with the result when done.

4. Add OPENAI_API_KEY= to .env.local as a placeholder  I will fill this in.
Enter fullscreen mode Exit fullscreen mode

The New Entry page showing raw commits pasted in the top text area, the

Putting It All Together

Here is every prompt in sequence and what each one adds:

Prompt What it built What Kinde provided
1 — Base app Changelog dashboard shell
2 — Kinde install Auth route handler, KindeAuthProvider Session management, JWT
3 — Login UI LoginLink, RegisterLink, user in sidebar User identity
4 — Route protection withAuth middleware Unauthenticated redirect
5 — Roles getRoles(), conditional UI rendering RBAC — admin/member/viewer
6 — Organizations getOrganization(), org name in sidebar Team workspace isolation
7 — AI generation generateChangelog server action

Seven prompts. A complete collaboration layer. No hand-written code.

Testing Your Collaboration Layer

Before sharing the app, verify these scenarios work:

Test 1 — Unauthenticated block. Open an incognito window and navigate to /dashboard. You should land on the Kinde login page.

Test 2 — Sign up with workspace. Click "Start free" and complete sign-up. You should land on the dashboard with your organization name visible in the sidebar.

Test 3 — Role-based UI. Sign in as your admin user and confirm you see Publish, Delete, and the Team link. Then change your role to viewer in the Kinde dashboard, refresh, and confirm those controls are gone.

Test 4 — AI generation. Paste a few commit messages into the New Entry page and click "Generate with AI." The content editor should populate with a polished changelog entry.

Test 5 — Workspace isolation. Create a second Kinde user and have them sign up with a different organization name. Log in as user one, create a draft entry. Log in as user two and confirm they cannot see user one's entries.

What Is Next

This article built the collaboration shell. The next steps to make it production-ready:

Connect a real database. Add Convex or Supabase and filter all queries by orgCode from getOrganization(). Every entry and every piece of data scoped to the team that created it.

Add team invites. Use the Kinde Management API to let admins invite colleagues by email directly from the Team settings page.

Make the public changelog live. The /changelog route is already public. Connect it to the published entries in your database and it becomes a real public-facing changelog page for your product.

The auth infrastructure is already in place. Everything else builds on top of it.

Create a free Kinde account if you have not already, and try this on whatever app you are building.

Top comments (0)