Bryce Watson
Sample report · production review Prepared by Bryce Watson

← Back to the main page

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 byBryce Watson
DeliveredSeptember 22, 2026
What I reviewedThe public code as it stood on one specific date: 2 database tables, 10 database migrations, 4 server functions, about 60 source files
Built withLovable; React, TypeScript, Vite; Supabase (database, sign-in, server functions, file storage); a paid web-scraping service
What the app doesA personal catalogue: the public can browse it; only the owner is meant to change it
Access I hadThe public code only
Access I didn't haveThe 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".

1 The short answer

Verdict Not ready until one setting is checked.

That check takes five minutes in the Supabase dashboard. The app is meant to be owner-only for changes, and the page code looks that way, but the database rules don't actually know who the owner is. So whether the app is safe right now comes down to one setting that isn't in the code. If it's in the wrong state, F-01 is Critical and also exposes the owner's paid services and file storage: fix it before anything else. If it's in the right state, the app is fine for now, but the rules should still name the owner directly this week, so a future settings change can't quietly open it up.

2 What to do first

  1. Check one dashboard setting (F-01).
  2. Tighten the database and storage rules so only the owner can change anything (F-01, F-03).
  3. Validate one kind of user-supplied value before it's saved and shown (F-02).

3 How to read this

Severity: Critical fix before real users, High before launch or in week one, Medium next few weeks, Low when you're in that code, Note no action now.

Confidence: Verified (confirmed directly), Likely (the code clearly allows it, but I didn't trigger it), Needs checking (couldn't confirm with the access I had; the finding says what would settle it). Only findings I could confirm from the code alone are Verified, because I had no test login. With a client's test accounts, most "Likely" items become "Verified".

4 Coverage

AreaStatusFindings
SecurityPartly checked: code and database rules read; live settings not seenF-01, F-02, F-03, F-08
Sign-in and accountsPartly checked: sign-in code read; account settings are in the dashboardF-01, F-11
Data handling and privacyChecked from code; backups not seenF-09, F-10
ReliabilityChecked from code; no logs seenF-05, F-06, F-07
DeploymentPartly checked: the builder publishes it; rollback not seenF-08, F-11
Cost risksChecked from code; plan and usage not seenF-04, F-05
Code healthCheckedF-11, F-12

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

#FindingSeverityConfidenceWhat the fix involves
F-01Access control. The database rules allow wider write access than the app's "owner only" design intends. How exposed the live app is depends on one dashboard setting that the code doesn't control.Critical if that setting is in the wrong state; Low if notNeeds checkingCheck the setting today; then rewrite the table and storage rules so they name the owner, and add a test that proves no other account can write.
F-02Unsafe handling of a user-supplied value. One field is saved without checking its format and then shown on a public page in a way that can run script in visitors' browsers, including the owner's while signed in. It only becomes reachable through F-01.High if F-01 is open; Low if notLikelyCheck the format in the database and when showing it.
F-03File storage limits. The public file bucket's size and type limits exist only in the browser, not on the server.Medium if F-01 is open; Low if notLikelySet the limits on the bucket itself, owner-only uploads.
F-04Paid-service abuse. The server functions that call a paid scraping service check that the caller is signed in, but not that it's the owner, and have no cap.Medium (High if F-01 is open)LikelyOwner-only check, a daily cap, input length limits, a spending alert.

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)

SeverityCritical if [setting] is on; Low if it's off
ConfidenceNeeds 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 foundThe exact rules, quoted, and why each one is broader than "owner only"
Why it mattersWhat a stranger could do to your public pages, storage and bill, in plain words
How to check it yourselfThe dashboard page and setting name, and what "safe" looks like there. No steps that touch the live app.
Recommended fixThe rule change, plus a prompt you can paste into Lovable
EffortSmall 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

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.

ItemFixesWhat "done" means (acceptance check)Price
Q-01F-01, F-03The dashboard setting is confirmed. A second test account gets a permission error on every change and upload, through the app and directly through the database. The owner still can. The bucket rejects oversize and non-image files.$300
Q-02F-02The database rejects unsafe values in that field, and the page never renders one.$100
Q-03F-04, F-07Only the owner can call the paid functions, up to a daily cap you choose. Oversized input is rejected. Outside calls give up after 15 seconds with a generic error.$250
Q-04F-05, F-06A 60-item bulk update finishes from one click with a correct progress count and no timeout. Durations on 5 sample pages match the labelled field.$250
Q-05F-08, F-11Settings file ignored and the builder still works; one lockfile; automatic checks run on every push; a test proves a second account can't write; owner buttons hidden from others.$200
Q-06F-09Backups confirmed in writing; one command exports all data to a dated file; deleting an item removes its image.$150

Suggested bundles

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.

7 What I did and didn't do

What a client would give me that I didn't have here: read-only dashboard access (account settings, live database rules, storage limits, backups, function logs), a screenshot of the paid service's usage page, and two test logins on a test copy. With those, F-01 and the other "Needs checking" items get a definite answer instead of a condition.

Want one of these for your app? Tell me what you're building and what's coming up. I'll reply within 2 business days.

Tell me about your project