Don't launch yet. You're about two hours of prompting away. PixelPets is fun, fast to sign up for, and mostly solid. But there are two problems that could cost you real money and your players' trust: your OpenAI key is visible to anyone, and your users table (emails included) can be read by anyone with your public Supabase URL.
Fix the two criticals today, knock out the four warnings before you post it anywhere, and treat the heads-ups as polish. Every finding below has a prompt you can paste straight into Lovable.
| 🔐 Secrets & security | 30 | |
| 🔗 Broken pages & links | 70 | |
| ⚡ Performance | 55 | |
| 🧱 Missing basics | 68 | |
| 🚀 Deploy | 85 |
users and pets VS-02 · ~15 min/leaderboard crash VS-03 · ~10 minsk-proj-Xr7…a9Qx) is baked into the JavaScript every visitor downloads. It's in there because it's stored as VITE_OPENAI_API_KEY, and anything starting with VITE_ gets shipped to the browser./assets/index-4f2a91c.js, line 1, char 48,211. Also in src/lib/generatePet.ts.Move all OpenAI API calls out of the frontend. Create a Supabase Edge Function called "generate-pet" that:
1. Reads OPENAI_API_KEY from Supabase secrets (not from any VITE_ variable).
2. Requires the caller to be logged in (verify the Supabase auth JWT) and returns 401 otherwise.
3. Accepts { petName, vibe } in the request body, calls the OpenAI API server-side, and returns only the generated pet data.
Update src/lib/generatePet.ts to call this edge function with supabase.functions.invoke("generate-pet") instead of calling OpenAI directly. Then delete VITE_OPENAI_API_KEY from all .env files and from the code, and confirm no string starting with "sk-" remains anywhere in the src folder.users and pets tables. Using only the public anon key from your site, we pulled all 312 rows of users, including emails, and could have edited anyone's pet stats.xyzpets, tables public.users, public.pets.Enable Row Level Security on the Supabase tables "users" and "pets" and add these policies: - users: a logged-in user can SELECT and UPDATE only their own row (auth.uid() = id). No one can SELECT other users' emails. - pets: anyone can SELECT name, level, owner_display_name and avatar_url (for the public leaderboard), but only the owner (auth.uid() = owner_id) can INSERT, UPDATE or DELETE their pets. Create a database view "leaderboard" that exposes only pet name, level, xp and owner display name, and use it on the leaderboard page instead of querying users directly. Show me the SQL migration before applying it.
/leaderboard fails for everyone. The console says TypeError: Cannot read properties of null (reading 'display_name'). One pet has an owner that was deleted, and the code assumes every pet has an owner.src/pages/Leaderboard.tsx, line 38: pet.owner.display_nameThe /leaderboard page crashes with "Cannot read properties of null (reading 'display_name')" because some pets have no owner. In src/pages/Leaderboard.tsx, use optional chaining and show "Unknown trainer" when pet.owner is null. Also filter out pets with a null owner_id in the query, and add an ON DELETE CASCADE to the pets.owner_id foreign key so orphaned pets can't happen again. Add a loading state and an "Couldn't load the leaderboard, try again" message if the query fails.
src/App.tsx, plus the "Hatch my pet" button in src/components/HatchButton.tsx.Add a React error boundary around the routes in src/App.tsx that shows a friendly on-brand screen ("Your pet tripped over a cable 🙀") with a "Try again" button that reloads the current route and a "Back home" link. In HatchButton.tsx, wrap the generate call in try/catch, show a toast with the error and a retry button, and disable the button while a request is in flight so it can't be double-clicked. Add a 20-second timeout to the request.hero.png at 4.8 MB (2880×1800). Your JS bundle is 1.1 MB, mostly because all 40 pet sprite sheets are imported up front./public/hero.png, src/assets/sprites/index.tsSpeed up the homepage on mobile: 1. Convert /public/hero.png to WebP, max 1600px wide and under 200 KB, and serve a 800px version to small screens using srcset. Set explicit width and height, plus fetchpriority="high" on the hero image. 2. Add loading="lazy" to every other image. 3. In src/assets/sprites/index.ts, stop importing all sprite sheets up front. Lazy-load each pet's sprite only when that pet is shown, using dynamic import(). 4. Lazy-load the /battle and /leaderboard routes with React.lazy and Suspense.
/assets/index-4f2a91c.js.map is public and rebuilds your original, readable src/ folder, comments included.In vite.config.ts, set build.sourcemap to false for production builds (keep it on for development). Then rebuild and confirm that no .js.map files are produced in the dist/assets folder.
/privacy or /terms page, and nothing linked in the footer. You collect emails and use Google sign-in, and Google requires a privacy policy URL on your OAuth consent screen before it's verified for public use.Create /privacy and /terms pages in plain, friendly English for a small browser game called PixelPets. The privacy page should cover: we collect email and display name via Google sign-in, we store pets and game stats in Supabase, pet names and prompts are sent to OpenAI to generate pets, we don't sell data, and how to request account deletion by email at [YOUR EMAIL]. Link both pages in the site footer. Add a note at the top to have the text reviewed before relying on it.
Vite + React + TS. There's no meta description, no og:image and no Twitter card tags, and the favicon is the Vite logo.In index.html set the title to "PixelPets: raise and battle AI-generated pets" and add a meta description (under 155 characters). Add Open Graph and Twitter card tags (og:title, og:description, og:image, og:url, twitter:card="summary_large_image"). Create a 1200x630 og-image.png in /public showing the logo and three pets. Replace the Vite favicon with a PixelPets favicon, plus an apple-touch-icon.
Make the leaderboard mobile friendly: below 640px, switch the table to a stacked card layout (rank, pet avatar, pet name, level, trainer) with no horizontal scrolling. On the pet screen, make the Feed, Play and Battle buttons at least 44px tall with at least 8px between them. Check that no page scrolls horizontally at 360px width.
pixelpets.app works fine, but www.pixelpets.app points at your host without an SSL certificate, so browsers show "Your connection is not private."I host pixelpets.app on [Netlify / Vercel / Lovable hosting]. Walk me step by step through adding www.pixelpets.app as a domain alias with a valid SSL certificate and a permanent 301 redirect from www to the apex domain pixelpets.app. Tell me exactly which DNS record to add at my registrar.
.env is in .gitignorePaste the prompts in order, redeploy, then reply to this email with "resweep". Your Full Sweep includes one free re-sweep, so we'll confirm everything's green before you hit post. Want a fresh sweep automatically every time you deploy? Ask about Always-On.