02 What the Interface Was Hiding
Every screen was correct. The database underneath was wide open.
This is the part where not writing the code myself could have cost my team everything they had put into it.
In a security sweep before deploying to real users, we found that an earlier fix had set every table's row-level security policy to allow everything. It had been done months before to stop an "access denied" error, and it worked, in the sense that the error stopped.
What that actually meant
Any signed-in partner could read and edit every other partner's contacts, notes, goals and daily data. Any signed-in partner could also make themselves an administrator by changing one field on their own record.
Nobody would have noticed by looking, because the application only ever displayed your own data and every screen was correct the entire time. The exposure was one layer down, at the API, where the interface could not reach and therefore could not reveal. I did not ship it.
The lockdown rewrote every policy on all eleven user-data tables to owner-only, matched against the signed-in user rather than left open. Reading another partner's record stopped being a question of what the interface offered and became a question the database refused. A helper function running with defined privileges resolved the recursive policy errors that come with checking an administrator flag from inside the policy that governs administrators. A trigger blocked anyone who is not an administrator from changing a role, closing the self-promotion path directly. Promotions became readable by everyone and writable only by an administrator. A later migration added the narrow read access the team report needed, deliberately scoped so a leader can see activity totals without seeing anyone's contact list.
The lesson I would want a judge to take from this
A fix that makes an error message go away is not the same as a fix. What a screen shows you and what the API permits are two different questions, and only one of them is visible. Not writing the code myself does not reduce what I owe the people who depend on it. It raises what I have to check.
One related finding looks alarming and is not: the Supabase key sitting in the file is the anonymous key, which we decoded to confirm the role it carries. It is public by design, and every real protection lives in the policies described above. That is why those policies being open mattered so much.