Sample production review: a Lovable and Supabase app
This is a real review of a public, open-source app, shared as a sample of what you get. The app is a small hobby project, but the checks are the ones I run on any app about to take real users: who can change what, what can cost you money, what breaks quietly, and what you'd lose if the database went.
I've removed the app's name, author and address, and I describe security problems that someone could exploit only by type, not by how to do it. A paying client gets the full detail: the exact file and line, what I saw, and how to check it. I read the public code only; I didn't run the app or touch the live site. That's why some answers below are conditional: with a client's read-only dashboard access and test logins, they become a definite yes or no.
| Prepared by | Bryce Watson |
| Delivered | September 22, 2026 |
| What I reviewed | The public code as it stood on one specific date: 2 database tables, 10 database migrations, 4 server functions, about 60 source files |
| Built with | Lovable; React, TypeScript, Vite; Supabase (database, sign-in, server functions, file storage); a paid web-scraping service |
| What the app does | A personal catalogue: the public can browse it; only the owner is meant to change it |
| Access I had | The public code only |
| Access I didn't have | The Supabase dashboard, hosting, the scraping account, a test login, the live site. A real client would give me read-only access to these, which is why several findings below are marked "Needs checking". |
5 Findings
Summary: 1 Critical, 1 High, 4 Medium, 4 Low and 2 Notes if the setting in F-01 is in the wrong state. If it's in the right state: 0 Critical, 0 High, 3 Medium, 7 Low and 2 Notes. In the client version each finding also has the exact file and line and step-by-step checks.
Security findings, summarised for this public sample
These four are why the verdict hinges on one setting. The good news is that each fix is small and the app's structure makes them easy to get right.
What F-01 looks like in the client version (details blacked out here)
| Severity | Critical if [setting] is on; Low if it's off |
| Confidence | Needs checking: the rules are certain from the code; the setting isn't visible without dashboard access |
| Where | [4 migration files, 9 lines]; [2 data files, 9 lines]; [sign-in code, 2 files] |
| What I found | The exact rules, quoted, and why each one is broader than "owner only" |
| Why it matters | What a stranger could do to your public pages, storage and bill, in plain words |
| How to check it yourself | The dashboard page and setting name, and what "safe" looks like there. No steps that touch the live app. |
| Recommended fix | The rule change, plus a prompt you can paste into Lovable |
| Effort | Small to medium. Quote item Q-01. |
F-05 A bulk-update feature probably runs past the server's time limit and reports the wrong numbers
Medium Likely (the time limit depends on the plan: Needs checking) · Reliability · The bulk-update server function (loop and response) and the page button that calls it
What I found. One call works through up to 20 items one after another, each needing two slow page fetches plus a pause. That adds up to at least 110 seconds before any network time, close to or past the 150 seconds Supabase typically allows. When it's cut off, the page says "failed" even though some items were updated. When it finishes, the message reads a number the function never sends, so it shows "out of undefined", and it says "complete" after the first 20 even when more are left.
Why it matters. Confusing results and wasted money: a timed-out run has already paid for its fetches.
How to check it yourself. Run it once while watching the function's logs in Supabase.
Recommended fix. Do 5 items per call, have the page repeat until done and show progress, and fix the message.
Effort. Small. Quote item Q-04.
F-06 Some scraped details can be silently wrong
Low Likely · Reliability, data quality · Three server functions' page-reading code
What I found. A duration is taken from the first "N min" anywhere on a fetched page, not from the labelled field. The bulk update takes the first search result whatever the edition. A price falls back to the first currency amount on the page, which may be a promotional banner.
Why it matters. Wrong values flow into the app's statistics with no sign they're guesses.
Recommended fix. Read from the labelled fields, match on year, and leave a blank rather than guess.
Effort. Small. Quote item Q-04 (same code as F-05).
F-07 Outside calls have no time limit, and failures are mostly invisible
Low Likely · Reliability · Four calls to outside services across three functions; one background sync in the page
What I found. No outside call sets a timeout. Errors go only to function logs; one function sends raw internal error text back to the browser, and the background sync hides every failure.
Why it matters. When something breaks, the owner finds out only by noticing missing data.
Recommended fix. 15-second timeouts, generic error messages, and a small notice in the page when the sync fails.
Effort. Small. Quote item Q-03.
F-08 The settings file is committed to the repository and not ignored
Low Verified (from the public repository) · Security, deployment · .env and .gitignore
What I found. The .env settings file is in the public repository. Today it holds only the project address and the key that every visitor's browser already receives, which Supabase designs to be public. I confirmed it's that public key, not the private key that bypasses all the rules, so nothing needs changing today. But the ignore file doesn't cover .env, so any real secret added later would be published with the next commit.
Why it matters. This is the finding that looks scariest and matters least. Automated scanners flag it loudly; the real question for this app was whether the database rules hold (F-01). Part of what you're paying for is knowing the difference.
Recommended fix. Ignore .env and keep the example file as a template, then confirm the builder still gets its settings.
Effort. Small. Quote item Q-05.
F-09 No visible backup or export of the owner's data
Medium Needs checking · Data handling · Whole project; the delete and upload code
What I found. Everything lives in one database with nothing in the code to back it up or export it. Whether the plan includes restorable backups isn't visible to me. Deleting a parent item deletes everything nested under it. Deleted items leave their images behind in storage, which keeps growing.
Why it matters. Years of data entry could be lost to one bad change or mistaken delete.
How to check it yourself. In Supabase, open Database > Backups.
Recommended fix. Confirm backups, add a one-command export to a dated file, and clean up images on delete.
Effort. Small. Quote item Q-06.
F-10 Some personal details are public by design
Note Verified (from the database rules) · Privacy
What I found. One public list shows prices, shops and purchase dates, plus the owner's internal account ID on every row. A third-party username is hard-coded in one function. No one else's personal data is stored.
Why it matters. Fine for a showcase, as long as it's a choice. Purchase dates are easy to overlook.
Recommended fix. None required; hide purchase dates from public reads if preferred.
F-11 Code health: the next change is riskier than it needs to be
Low Verified (from the repository) · Code health, deployment
What I found.
- Owner-only buttons show for any signed-in account.
- The only test is a placeholder that checks
true equals true, and nothing runs checks on each change.
- The project records its outside code in three different, competing ways, so what the builder installs can differ from what a developer's laptop installs.
- The server functions pull in outside code without locking the version, so an update could change their behaviour overnight.
- Three page files are 18 to 25 KB each, mixing data, filters and layout.
Why it matters. Nothing breaks today, but every edit is harder to check, and the access rules in F-01 have no test to catch a regression.
Recommended fix. One lockfile, a small automatic check on every push (lint, tests, build), a test that a second account can't write, and owner checks in the page.
Effort. Small to medium. Quote item Q-05.
F-12 Outside libraries weren't scanned
Note Needs checking
What I found. I didn't install anything, so I didn't run a vulnerability scan. The main libraries are recent. With a client I'd run the scan or read their GitHub Dependabot alerts.
What's already done well
- The private database key is used only on the server, and only on the caller's own records. It never reaches the browser.
- Every server function checks the caller's login before doing anything that costs money.
- Both page-fetching functions only fetch from an approved list of sites, which blocks the usual way this feature gets abused.
- Every write rule is tied to the signed-in account; the gap is only that "signed in" isn't the same as "owner".
- A later change removed public listing of the file bucket.
6 Fixed quote
The review itself is the $400. The prices below are for fixing what it found. If you book fixes within 14 days, I take the $400 off.
Suggested bundles
- Must-fix only (security): Q-01, Q-02. $400, within 2 business days.
- Launch-ready (every Critical, High and Medium finding): Q-01 to Q-04 and Q-06. $1,050, within 5 business days. Check your backups first (F-09); if your plan already covers them, Q-06 shrinks to the export and image clean-up and I'll re-price it.
- Everything (adds the code-health clean-up): Q-01 to Q-06. $1,250, within 6 business days.
Bundles are the sum of their items; there's no discount hidden in them.
What you'd pay in total: for example, the $400 review, then the must-fix bundle ($400) booked within 14 days, with the $400 review fee taken off it. That's $400 in all. Launch-ready the same way comes to $1,050 in all.
Each fixed item that fails its acceptance check within 14 days of delivery gets redone free, as long as nobody has changed that code since.