Built a full-stack AI schema audit tool in two sittings. Solo. One day.
Not a side project. A real tool:
→ Fetches + renders any URL
→ Audits existing schema
→ Flags what's missing and why it matters
→ Generates the JSON-LD
→ Gives you CMS-specific implementation steps
Built for small business owners who don't speak developer.
First test site? My own. It found 3 real issues I hadn't fixed.
0-Tech Schema is live at bree-sharp.com/tools/schema-…
Free. No login. Just paste your URL.
`if key:` is not a key check.
"your_api_key_here" is truthy. A revoked key stored as a placeholder would have built a real client that 401'd on every call, instead of taking the clean "not configured" path.
Placeholders count as missing now. A fake key is worse than no key.
phpMyAdmin shows 25 rows at a time.
I listed a site's options table, didn't see the licence key, and briefly believed it wasn't there. It was, just past row 25.
A cut-off list looks exactly like a real absence. Check the row count first.
Some of the most useful work I found in August wasn't in a ticket.
Fixing other things, I kept running into problems on live sites. So I wrote them up as tickets for approval instead of mentioning them in passing. Fifteen in one batch.
Estimate while the site is still open.
I sort my own Search Console data into three piles every two weeks, before I decide anything.
The thresholds are boring. That's the point.
Each pile gets a different kind of work.
Rewriting the snippet on a pile C page is wasted effort. Building a brand new page for a pile A term usually is too.
Wrote a cycle test for new code. It crashed old code.
The page-type detector had its own recursive walk, no cycle guard. Feed it an Organization whose parentOrganization points back at itself and /analyze threw an unhandled RangeError.
Months in production. A WeakSet fixed it.
Claude Code tip: before you ship a vibe-coded site, have Opus 5.5 𝗽𝗹𝗮𝘆 𝘁𝗵𝗲 𝗯𝗮𝗱 𝗴𝘂𝘆. Send out 3 subagents with three test accounts (A, B and an admin) to actually run 𝘁𝗵𝗲𝘀𝗲 𝟭𝟰 𝗮𝘁𝘁𝗮𝗰𝗸𝘀, collect proof, then fix everything in one pass:
Impersonate other users
→ Without logging in, take the public key from your frontend and query every table in the database directly. See what comes back
→ Logged in as A, swap the id in a request for B's and try to read, edit and delete B's data
→ When A edits their profile, add role: admin to the request, then try editing the role in their own account data directly
→ Use a password reset link once, then click it again
Get around limits in the UI
→ For disabled buttons and hidden options, skip the page and send the request directly
→ Once the free uses run out, check whether calling the API directly still works
→ With only a little credit left, fire 20 requests at once and see whether more succeed than the credit allows
→ Fill forms with very long text, special characters, negative numbers and empty values
→ Change the post-login redirect (?next=) to another site, and also try values starting with // and @
Come in from outside
→ Put
in a username, a comment or Markdown, then open the page in a browser and see if an alert pops up
→ If the app fetches URLs (importing links, building previews), give it http://localhost and http://169.254.169.254 and check the server logs for an actual outgoing request. Skip this if there's no such feature
→ For pages and API responses A has seen, request the same address from another browser as B or logged out, and see whether A's content shows up
→ Open your hosting platform's preview links without logging in to the platform
→ Hide an instruction in an uploaded document or web page that tells your AI feature to read another user's data or call a tool it shouldn't, and see if it does
Collect proof
→ Every item has to actually run. If it was only read in the code and never run, it counts as "not proven"
→ After a fix, temporarily turn the protection off in local code and run it again. The attack must succeed. Turn it back on and it must be refused
→ Put the results in a table: how each attack was done, the request and response, and whether it was refused when it should have been
→ Save the tests as scripts in the repo and run them again before your next launch
→ When you're done, install Anthropic's official security-guidance plugin (/plugin install security-guidance@claude-plugins-official). After every turn of edits, and after each commit or push it makes, Opus reviews the changes again. Those reviews use extra usage
The default medium effort is enough. The impersonation group is the most expensive to get wrong, so raise that one to high.
Send this whole post to Claude Code. If you need to, add this line at the end 👇
"First check that the preview environment isn't connected to the production database. If it is, run everything locally only. Use test accounts and test data, with a separate set of accounts for each subagent. Don't touch real users, don't attack services I don't own, don't hammer any one endpoint, and only test payments in test mode. Only switch protections off temporarily in local code, and never change the database or dashboard settings. Keep test account passwords in .env, out of git, and mask tokens in the results table. Send one subagent per group to attack, recording without fixing. Run the impersonation subagent at high effort. Then fix everything yourself from their lists, rerun every test, and give me a before-and-after table. Delete the test accounts and data at the end. For installing the plugin or changing dashboard settings, give me the steps and I'll do it."
Claude Code tip: before you ship a vibe-coded site, have Opus 5.5 send out 𝟰 𝘀𝘂𝗯𝗮𝗴𝗲𝗻𝘁𝘀 to check 𝘁𝗵𝗲𝘀𝗲 𝟮𝟬 𝘁𝗵𝗶𝗻𝗴𝘀 𝘁𝗵𝗮𝘁 𝘀𝗹𝗼𝘄 𝗶𝘁 𝗱𝗼𝘄𝗻, then fix them all in one pass:
Images and fonts
→ Convert every image to WebP or AVIF, sized to how big it actually shows on the page
→ Serve big images from Supabase Storage through next/image at the right size. On the Pro plan, Supabase's own image transformations work too
→ Lazy-load images and videos below the fold, and load the big image at the top of the page first
→ Load fonts the way your framework does it (next/font in Next.js), and keep it to one or two fonts
→ Remove third-party scripts you don't use, and run analytics and chat widgets after the page has loaded
Frontend code
→ Run a bundle analyzer to find the biggest packages, and where a whole library gets imported, import only the parts you use, like single lodash functions
→ Load heavy components the first screen doesn't need, like charts, editors and maps, with dynamic import when they're needed
→ Fetch the homepage data on the server, so the page opens with content already in it
→ Stream AI answers as they're generated
→ Show skeletons while data is still loading
Database and APIs
→ Index the columns you filter and sort by, including the ones your RLS policies use, like user_id
→ In RLS policies, write auth.uid() as (select auth.uid()) so it runs once per query
→ Find N+1 queries and turn them into a single query
→ Paginate long lists
→ Cache API responses that are the same for everyone, and never cache anything tied to a logged-in user
→ Move heavy work like sending emails, processing images and building reports to background jobs
Servers and network
→ Put your server functions in the same region as your database. New Vercel projects run functions in US East by default
→ Turn pages whose content rarely changes into static pages or ISR
→ When a page calls APIs one after another, run them in parallel or merge them into one
→ In Chrome, emulate a low-end Android phone on slow 4G and click through the main flows
The default medium effort is enough. The database group has to read queries and decide which indexes to add, so raise that one to high.
Send this whole post to Claude Code. If you need to, add this line at the end 👇
"Send one subagent per group to check it without editing anything, and note which file each issue is in and which page it affects. Run the database subagent at high effort. Before changing anything, run a production build (next build && next start in Next.js) or use a preview link, then run Lighthouse three times in mobile mode on the homepage and the two or three slowest pages and note the median. Then fix everything yourself from their lists, measure again the same way, and give me the before-and-after numbers. Don't remove features to gain speed. Ask me before removing dependencies, changing the deploy region or changing the database."
The old server treated Photo.webp and photo.webp as one file. Cloudflare won't.
One image on a site I moved was linked in the wrong case and only worked by accident. Fixed the links, redirected the lowercase URL old pins still use, and added an exact-case image check.
A ticket said a site scored 0 out of 100 on mobile.
Ten runs gave medians of 44 mobile, 93 desktop. Google's field data, from real visitors, passed all three of Google's speed checks, on phone and desktop.
Before fixing a number, find out which number you're being asked to fix.
Bree Sharp | Web Developer & Tech SEO Consultant retweeted
Every week someone tells me they vibe-coded their app over the weekend and don't need developers anymore.
Before it touches a paying customer, make sure it includes:
> a schema someone designed, instead of one the AI improvised table by table
> login that still works when someone puts a plus sign in their email
> password reset links that expire and work once
> MFA, plus a recovery path for the user who lost their phone
> sessions that time out, and a way to kill every session for one user
> SSO for the enterprise customer who won't sign without it
> SAML, because that customer's IT team doesn't do magic links
> SCIM, so a fired employee loses access the moment IT offboards them
> roles and permissions deeper than "admin" and "everyone else"
> checks that stop user A from reading user B's data by changing one number in the URL
> tenant isolation, so one customer's bug never shows another customer's records
> an admin "log in as this user" button for support, with an audit trail on every use
> rate limits on login, so nobody can guess passwords at scale
> lockouts that stop attackers without locking out your CFO the night before the board meeting
> database migrations that run forward and roll back
> migrations that don't lock the main table at 2pm on a Tuesday
> indexes, because the query that was instant on 50 test rows times out on 5 million real ones
> connection pooling, so a traffic spike doesn't exhaust the database
> backups every night
> a restore from those backups, tested, because a backup you've never restored is a hope
> point-in-time recovery for the day someone runs a delete without a where clause
> soft deletes, so "I deleted it by accident" is a support ticket and not an incident
> validation on the server, not just in the form
> timezones stored right, so the 9am reminder doesn't fire at 4am
> the customer with an apostrophe in their last name
> emoji, accents and right-to-left text in every field
> money stored as integers, because 0.1 + 0.2 doesn't equal 0.3 in floating point
> currency, rounding and tax rules for every country you sell into
> a data model that survives your second customer asking for "one small change"
> idempotency keys, so a retried payment doesn't charge the card twice
> deduplication for the user who clicks submit four times
> pagination that still works on page 400
> exports, because sooner or later every customer wants their data in a spreadsheet
> imports that survive the CSV someone saved in 2009
> retention rules, and code that deletes what your contract says you'll delete
> secrets out of the code, out of the repo and out of the AI chat history
> rotating every key the AI pasted into a config file last month
> confirming every package the AI installed exists and is the one you meant
> dependency scanning, because the AI pulled in libraries nobody reviewed
> input sanitization everywhere a user can type
> protection against SQL injection, XSS, CSRF and the rest of the OWASP list
> file uploads that get scanned, size-limited and stored where they can't execute
> CORS rules that aren't "allow everything"
> security headers on every response
> encryption at rest and in transit
> least-privilege access for everyone, including the AI agent holding production credentials
> logs that record who did what, without recording passwords, tokens or card numbers
> a penetration test before your enterprise customer's security team runs their own
> answers to the security questionnaire every enterprise buyer sends, with evidence behind each one
> a disclosure process for the day a stranger emails you a vulnerability
> a plan for the day a laptop with production access gets stolen
> SOC 2, which means policies, evidence and an auditor, not a checkbox
> HIPAA, the moment a single patient record touches your system
> a BAA with every vendor that touches that data, including your AI model provider
> audit trails that show who viewed a record, not just who changed it
> PCI scope, and card numbers kept out of your database
> GDPR deletion requests that reach every table, backup and log
> data residency for the customer whose contract says EU only
> quarterly access reviews someone signs off on
> dev, staging and production environments that match each other
> infrastructure written as code, so the setup lives somewhere other than one person's memory
> a deploy pipeline that runs the tests before anything reaches customers
> one-click rollbacks, because Friday deploys happen
> zero-downtime deploys, because your customers don't have maintenance windows
> feature flags, so you can ship the code without shipping the feature
> autoscaling for the Monday morning spike
> a CDN, so the app loads fast in Singapore too
> DNS, SSL certificates, and renewals that don't expire on a Sunday
> background job queues, so slow work doesn't freeze the page
> retries with backoff, so one flaky API call doesn't become a lost order
> a dead-letter queue for the jobs that fail every retry
> cron jobs that don't run twice the day you add a second server
> caching, and clearing that cache when the data changes
> SPF, DKIM and DMARC, so your password resets don't land in spam
> bounce and complaint handling on every transactional email
> storage rules, so you stop paying to keep 2021's temp files
> cost alerts, so a runaway agent loop shows up the same day and not on the invoice (we learned this one for $1,382.59)
> a disaster recovery plan, written down and tested once a year
> a second region, if your contract promises uptime one region can't deliver
> structured logs you can search at 3am
> error tracking that groups the same bug instead of sending you 4,000 emails
> uptime checks from outside your own network
> alerts that page a human, tuned until they stop paging for nothing
> dashboards for latency, error rate and throughput
> tracing for one slow request across every service it touches
> an on-call rotation, and a person who picks up
> runbooks, so the engineer on call knows what "queue depth critical" means
> postmortems that change something
> a status page customers check before they email you
> unit tests written by someone who knows what the logic should do
> integration tests for every third-party API you depend on
> end-to-end tests for signup, checkout and the other flows that make you money
> load testing before the launch email goes out
> test data that looks like production without being production data
> regression tests, so fixing bug 41 doesn't bring back bug 12
> testing on the five-year-old laptop your biggest customer's ops team still uses
> accessibility compliance, because the enterprise contract requires it
> subscriptions, upgrades, downgrades and proration
> failed-payment retries and dunning emails
> invoices with the customer's PO number on them, because procurement won't pay without it
> sales tax and VAT
> refunds, credits and partial refunds
> usage metering that matches what you bill, to the cent
> annual contracts with custom terms your billing logic never planned for
> revenue reports your finance team can reconcile
> webhooks that verify signatures
> webhooks that retry, with a log of every failed delivery
> a versioned API, so you can change it without breaking your customers' integrations
> API keys customers can create and revoke
> API rate limits that protect you without blocking real integrations
> a plan for the day a third-party API changes its response format without telling you
> OAuth token refresh, because tokens expire at the worst possible moment
> a sandbox where customers can test their integration
> protection against prompt injection in every field that reaches the model
> customer and patient data kept out of prompts that leave your network
> a model spend cap per customer, so one heavy user can't run up your bill
> evals, so you find out when a model update makes your answers worse
> a fallback for the afternoon your model provider goes down
> a migration plan for the day your model gets deprecated
> prompt and output logs for debugging, minus whatever you're not allowed to keep
> a human approval step for anything the AI does that can't be undone
> pages that load on hotel wifi
> empty states, loading states and error states on every screen
> error messages a customer can act on, instead of "something went wrong"
> forms that keep what people typed when one field fails validation
> emails that render in every mail client your customers use
> notifications people can turn off
> undo
> keyboard navigation and screen reader support
> translations, with dates and numbers formatted for each locale
> a back button that does what people expect
> code a human can read
> code review on every change
> a branching strategy, so two people can work without overwriting each other
> monthly dependency upgrades, so you're never two major versions behind
> framework upgrades before the old version stops getting security patches
> deleting the dead code the AI left behind from its first three attempts
> splitting up the 2,000-line file the AI kept appending to
> architecture decisions written down, with the reasons
> a README that gets a new engineer running locally in under an hour
> documentation for whoever inherits this
> an admin panel for your ops team
> support tooling, so customer success can answer questions without pinging engineering
> a changelog customers can read
> terms and a privacy policy that match what the code does
> every account, domain and repo in the company's name, not the name of whoever built the prototype
> a bus factor higher than one
Oh, and besides keeping all of this working every day, forever… your vibe-coded app will still need people who know what they're doing:
> reading every line the AI wrote before it ships (a senior engineer)
> designing the data model before your second customer breaks it (a backend engineer)
> explaining why the AI's fix for one bug created two new ones (a senior engineer, again)
> deploys, rollbacks, servers and the cloud bill (a DevOps engineer)
> answering the page at 3am when payments stop (whoever's on call)
> patching the framework the week a vulnerability goes public (security)
> walking an auditor through how patient data moves (security and compliance)
> testing what the AI says it tested (QA)
> running a migration on a live database without losing a row (a backend engineer)
> saying no to the feature that breaks three others (a tech lead)
> turning "works on my laptop" into "works for every customer at once" (an architect)
> debugging the code when the AI that wrote it can't (a senior engineer)
> remembering why it's built this way, a year from now (someone who was there)
…wishing them the best 🫡
A rule in my notes: Winchester impressions are ~2/3 UK noise, dropping impressions there = success.
It had survived one review. Wrong both ways. And "two-thirds" wasn't close: one page carried 2,473 of 2,492.
Rules that define good news in advance are the ones I trust least.
My rank tracker said I was position 1 for a term I care about.
I checked Google directly. Position 8.
So two opposite things were true at once. AI Overviews were the least gated surface I had. They were also what pushed my organic results off the visible page.
Rankings have shifted since Google's August spam update, and they'll shift again.



