Lightweight CRM Template for Lovable
Companies, contacts and an append-only note timeline for a founder doing their own sales, with shared team reads and owner-only writes.
Stack: React + Vite, TypeScript, Tailwind CSS, shadcn/ui, Supabase
What is in the download
- A build prompt optimised for speed of entry rather than field completeness
- A schema with companies, contacts, notes and a pipeline stage enum
- Shared team reads with owner-only writes, and a with-check clause that blocks reassignment
- A GIN full-text index so search works without a separate search service
- Six verification queries, including one proving user B cannot steal user A's record
What it is not
- Not a pre-built app you clone and run. There is no repository and no node_modules.
- Not a design file or a theme. Lovable generates the interface from the prompt.
- Not a substitute for reading the SQL. You are running it against your own database.
Setup order
Running these out of order is the usual reason a template appears broken. The schema comes before the prompt, because the prompt references the table names it creates.
Decide shared or private before running schema.sql
This schema is a shared team CRM: every authenticated user reads every record. For per-user isolation, change the select policies to owner_id = auth.uid() first.
Run schema.sql in the Supabase SQL editor
Run verify.sql as two different users
Queries 3 and 4 only mean anything when run by someone who does not own the record.
Paste prompt.md into Lovable
Things that catch people out
- owner_id defaults to auth.uid() in the schema, so the client never sends it. That is what makes ownership server-derived rather than a value the browser can choose.
- The with check clause on the update policies is the part people omit. Without it an owner can update their own row and set owner_id to somebody else, or a user can claim a record by rewriting the owner. Verification query 4 tests exactly that.
- Shared reads are a deliberate default for a sales team. It is the one policy decision in these templates you should consciously confirm rather than accept.
prompt.md
DownloadThe build prompt
# Context
Build a lightweight CRM for a small team tracking companies, the people at them, and what was
said. The target user is a founder doing their own sales, so speed of entry matters more than
completeness of fields, and nothing should require leaving the keyboard.
## Core Features (Priority Order)
1. Contact list with fast search across name, company and email
2. Contact detail view with a chronological note timeline
3. Add a note in two keystrokes from the contact view, no modal
4. Companies as first-class records, with their contacts listed
5. Ownership: every record has an owner, and the team can see all records
6. A simple pipeline stage on each contact, changed inline from the list
## Visual Style
- Dense list, roomy detail. The list is for scanning, the detail is for reading
- shadcn/ui: Table for the list, Command for search, Badge for stage, Avatar for contacts,
Textarea for notes, Select for stage changes
- Stage colours consistent between list and detail
## Technical Requirements
- Breakpoints sm 640px, md 768px, lg 1024px; the list becomes cards below md
- Search filters client-side against loaded rows for instant feedback, then falls back to a
server query when the term is longer than the loaded page
- Optimistic update on a stage change, reverted on failure with a visible message
- Empty states for no contacts, no search results and no notes, each different
- Dark mode via Tailwind's dark: prefix
## Implementation Strategy
1. The schema from schema.sql and the contact list read
2. Contact detail and the note timeline
3. Note creation, with the optimistic path and the failure path
4. Companies, then the company-to-contact relationship
5. Pipeline stage last, because it changes the list and the detail together
## Safe-Guard Instructions
- Ownership is server-derived from auth.uid(). Never accept an owner id from the client.
- A note is append-only in the UI even though the schema allows the author to edit their own.
Do not add bulk delete.
- Do not add a policy that lets a user reassign another user's records.
## Growth Features (Required for Distribution)
- **B2B Sales:** make one contact view shareable as a read-only summary, so a colleague can
see the history without an account, and make it obvious when a share link is active.schema.sql
In the bundleCompanies, contacts, notes and policies
-- Lightweight CRM schema for Lovable + Supabase
-- Reviewed row-level security. Read the comments before running this.
--
-- Model choice worth understanding: this is a SHARED team CRM. Every authenticated user can
-- read every record, because a sales team that cannot see each other's pipeline is not
-- useful. Writes are restricted to the owner. If you need per-user isolation instead, change
-- the select policies to owner_id = auth.uid() and re-run the verification queries.
create type public.pipeline_stage as enum
('new', 'contacted', 'qualified', 'proposal', 'won', 'lost');
create table public.companies (The rest of schema.sql, with every policy written and its denials verified, is in The Complete Lovable Bundle.
Get the Bundleverify.sql
In the bundlePolicy verification queries
-- Verification queries. Run these as user A, then sign in as user B and repeat 3 and 4.
-- 1. Should return the whole team's contacts. This schema is deliberately shared.
select id, full_name, stage, owner_id from public.contacts limit 20;
-- 2. Should SUCCEED, and owner_id should default to you without being supplied.
insert into public.contacts (full_name, email) values ('Verify Person', 'v@example.com');
select full_name, owner_id = auth.uid() as owned_by_me
from public.contacts where email = 'v@example.com';
-- As user B, against a contact owned by user A:
The rest of verify.sql, with every policy written and its denials verified, is in The Complete Lovable Bundle.
Get the BundleNext
If you want a prompt rather than a whole starting point, the prompt library has 101 of them across six categories. If you are watching what this costs to build, how Lovable credits work explains why a vague prompt against a large project is expensive twice over.