Step-by-step guide to build a project management tool with Lovable, including architecture, features, integrations, and best practices for teams

Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
Build a simple project-management MVP in Lovable by wiring a React frontend to Supabase (for auth + storage), creating pages for Projects and Tasks, and using Lovable Chat Mode to create files, edit code, set Secrets, Preview, and Publish — no terminal needed. Paste the provided Lovable prompts into Chat Mode one-by-one: they instruct Lovable which files to create/modify, how to configure Supabase Secrets in Lovable Cloud, and how to verify in Preview. When you need deeper control (migrations, custom CLI tasks) use GitHub sync/export and run commands locally — that path is labeled explicitly.
Minimal Project Management app: React SPA with Supabase auth, Projects list, Project detail with Tasks, create/edit/delete UI. Uses Lovable Chat Mode to create files, the Secrets UI for SUPABASE_URL / SUPABASE_ANON\_KEY, Preview to test, Publish to make the site live. No CLI required for the basic flow.
Tools inside Lovable: Chat Mode edits and file diffs, Preview, Publish, and Secrets UI. We will:
Paste each of the following prompts into Lovable chat (one at a time). Each prompt tells Lovable exactly what to change.
Goal: Create React app skeleton and supabase helper.
Files to create: src/main.tsx, src/App.tsx, src/lib/supabase.ts, public/index.html, vite config if not present (ask Lovable to detect)
Acceptance criteria (done when): Lovable reports files created and Preview shows a welcome page with “PM App” and a Sign in button that reads Supabase status “not signed in”.
Secrets needed: None yet — code will read from process.env but will work once Secrets are set.
// Create src/lib/supabase.ts
// Initialize Supabase client using environment variables
import { createClient } from '@supabase/supabase-js';
// Use environment variables via import.meta.env.VITE_SUPABASE_URL etc.
// Lovable will wire these from Secrets.
export const supabase = createClient(
import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_ANON_KEY
);
// Create src/App.tsx
// Simple routing: Home with Sign in/out and links to Projects
import React from 'react';
import { supabase } from './lib/supabase';
export default function App() {
const [user, setUser] = React.useState(null);
React.useEffect(() => {
const u = supabase.auth.user();
setUser(u);
const { data: sub } = supabase.auth.onAuthStateChange((_e, session) => {
setUser(session?.user ?? null);
});
return () => sub?.unsubscribe();
}, []);
return (
<div>
<h1>PM App</h1>
{user ? (
<div>
<p>Signed in as {user.email}</p>
<button onClick={() => supabase.auth.signOut()}>Sign out</button>
<a href="/projects">Projects</a>
</div>
) : (
<div>
<p>Not signed in</p>
<button onClick={() => supabase.auth.signIn({ provider: 'github' })}>
Sign in (GitHub)
</button>
</div>
)}
</div>
);
}
// Create src/main.tsx and public/index.html as basic Vite React app entry
Goal: Add pages for listing projects, viewing a project with tasks, and basic create/delete actions using Supabase client.
Files to create/modify: src/pages/Projects.tsx, src/pages/ProjectView.tsx, src/routes.tsx (or modify src/App.tsx to include routes), update package.json if routing library missing (ask Lovable to add react-router-dom).
Acceptance criteria (done when): In Preview you can navigate to /projects, see an empty list, create a project with a name, click into a project, add tasks, and delete tasks. All operations call supabase and show basic error/success feedback.
Secrets/integration: Requires Supabase DB tables (projects, tasks). If you don't run migrations yet, Lovable should show UI errors but still allow client-side calls; recommend using Supabase SQL Editor manually or run migration outside Lovable (see pitfalls).
// Create src/pages/Projects.tsx
// List and create projects
import React from 'react';
import { supabase } from '../lib/supabase';
export default function Projects() {
const [projects, setProjects] = React.useState([]);
const [name, setName] = React.useState('');
async function load() {
const { data } = await supabase.from('projects').select('*').order('id', { ascending: false });
setProjects(data ?? []);
}
React.useEffect(() => { load(); }, []);
async function create() {
await supabase.from('projects').insert({ name });
setName('');
load();
}
return (
<div>
<h2>Projects</h2>
<input value={name} onChange={e => setName(e.target.value)} placeholder="Project name" />
<button onClick={create}>Create</button>
<ul>{projects.map(p => <li key={p.id}><a href={`/projects/${p.id}`}>{p.name}</a></li>)}</ul>
</div>
);
}
// Create src/pages/ProjectView.tsx
// Show tasks, add/delete
import React from 'react';
import { supabase } from '../lib/supabase';
import { useParams } from 'react-router-dom';
export default function ProjectView() {
const { id } = useParams();
const [project, setProject] = React.useState(null);
const [tasks, setTasks] = React.useState([]);
const [text, setText] = React.useState('');
async function load() {
const { data: p } = await supabase.from('projects').select('*').eq('id', id).single();
const { data: t } = await supabase.from('tasks').select('*').eq('project_id', id);
setProject(p);
setTasks(t ?? []);
}
React.useEffect(() => { if (id) load(); }, [id]);
async function addTask() {
await supabase.from('tasks').insert({ project_id: id, title: text, completed: false });
setText('');
load();
}
async function delTask(tid) {
await supabase.from('tasks').delete().eq('id', tid);
load();
}
if (!project) return <div>Loading...</div>;
return (
<div>
<h2>{project.name}</h2>
<input value={text} onChange={e => setText(e.target.value)} placeholder="New task" />
<button onClick={addTask}>Add</button>
<ul>{tasks.map(t => <li key={t.id}>{t.title} <button onClick={() => delTask(t.id)}>Delete</button></li>)}</ul>
</div>
);
}
Goal: Tell Lovable to store VITE_SUPABASE_URL and VITE_SUPABASE_ANON\_KEY in the Cloud Secrets UI and wire them to the app, then open Preview.
Files to modify: none — this is a Lovable Secrets + Preview action.
Acceptance criteria (done when): Secrets saved, Preview shows Sign in working and Projects/Tasks operations succeed (no DB errors).
Secrets/integration steps:
// Prompt Lovable to apply Secrets and restart Preview environment
// No code file changes — ask Lovable to ensure import.meta.env.VITE_SUPABASE_* is populated from Secrets.
Accurate: This uses Lovable Chat Mode edits, Preview, Publish, and the Secrets UI. Any DB migrations or CLI tasks must be done outside Lovable via GitHub sync or Supabase dashboard — those steps are explicitly called out above.
This prompt helps an AI assistant understand your setup and guide to build the feature
This prompt helps an AI assistant understand your setup and guide to build the feature
This prompt helps an AI assistant understand your setup and guide to build the feature

Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
Build it with modular AI generators, validate every generated change before shipping, keep secrets out of the browser, use Lovable-native flows (Chat Mode edits, Preview, Publish, Secrets UI, GitHub sync), and rely on a reliable backend (eg. Supabase or a serverless proxy) for auth, persistence, and secreted LLM calls. Start by scaffolding small generator components (task templates, PR/body composers, boilerplate files), wire them to safe server-side calls for LLMs, and iterate using Lovable's Preview + Publish loop so you never depend on a terminal inside the app.
Client saves a generated task to Supabase (use anon key client-side; secret DB ops go server-side).
// Install @supabase/supabase-js in your frontend build
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = 'https://your-project.supabase.co'
// PUBLIC anon key is safe for client read/write rules if row-level security is configured
const supabaseKey = 'public-anon-key'
const supabase = createClient(supabaseUrl, supabaseKey)
// Save a generated task
async function saveGeneratedTask(task) {
// task = { title, description, generatedBy, metadata }
const { data, error } = await supabase.from('tasks').insert([task])
if (error) throw error
return data
}
Server-side proxy for OpenAI (deploy as Edge Function / small server). Put OPENAI\_KEY in Secrets UI or your server env.
// Node/Express example
import express from 'express'
import fetch from 'node-fetch'
const app = express()
app.use(express.json())
app.post('/api/generate', async (req, res) => {
// Use OPENAI_KEY only on server-side!
const prompt = req.body.prompt
const r = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.OPENAI_KEY}`
},
body: JSON.stringify({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }]
})
})
const j = await r.json()
res.json(j)
})
app.listen(3000)
From startups to enterprises and everything in between, see for yourself our incredible impact.
Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We’ll discuss your project and provide a custom quote at no cost.