Launch risk: medium-high
The app can be demoed, but payment and user-data boundaries need fixes before sending traffic.
Sample deliverable
Example report for a fictional AI-built booking app. This shows the format, not a real client finding.
The app can be demoed, but payment and user-data boundaries need fixes before sending traffic.
Public app, read-only repo access, Vercel logs, Supabase config screenshots, and Stripe test-mode settings.
Do not spend on design or ads until cross-user reads and webhook trust boundaries are cleaned up.
Findings
Evidence: The dashboard fetch uses a client-side filter after selecting recent bookings. The database rule does not enforce owner filtering.
Impact: A logged-in customer could see another customer's appointment metadata if the route loads enough rows.
Fix: Add an owner check in the database policy and make the query require the authenticated user ID server-side.
Evidence: The webhook route parses the body and updates subscription status before verifying the Stripe signature.
Impact: Subscription access can drift from payment state, especially when moving from preview to production.
Fix: Verify the webhook signature before any mutation and store idempotency/event IDs.
Evidence: Vercel logs show fallback behavior for the mailer key and webhook secret.
Impact: Confirmation emails fail silently and payment events cannot be trusted.
Fix: Add production env vars, remove preview fallbacks, and fail closed when a required secret is absent.
Evidence: The route is not linked from nav, but direct navigation loads the admin shell for any logged-in user.
Impact: Hidden routes are discoverable and should not be used as permission boundaries.
Fix: Add server-side role checks and return a hard 403 for non-admin users.
Fix order
Add database owner checks, server-side user scoping, and direct-route tests for customer/admin views.
Move webhook verification before mutation, add event idempotency, and test checkout/subscription transitions.
Set required production variables and remove preview fallbacks that hide broken integrations.
Want this format for your app?