Sajjad Mahessar Good Merch Group Free audit
Selected work

Operations & compliance

Resilience, governance, and the documentation that has to survive an inspection. Including what is still open, written down rather than buried.

Projects
Three
Tables audited
55
Documents
31
Databases backed up
Nine
3 migrations · zero downtime Operations & compliance

Database security audit & remediation

Audited the full production schema — 55 tables — and found around 40 carrying blanket access policies. The anonymous API key had read, write and delete reach over staff PINs, pay rates, salaries, guest records, timesheets, takings, petty cash and the audit log.

BEFORE · BLANKET POLICY ~40 TABLES OPEN TO THE ANON KEY PINS · PAY · GUESTS · TAKINGS · AUDIT LOG 3 MIGRATIONSZERO DOWNTIME AFTER · SCOPED 55 TABLES · SECURITY DEFINER
55 tables — blanket policy to scoped access
PostgreSQLRow-level securitySQL migrationsSECURITY DEFINER OpenClose

How it shipped

A four-stage remediation, sequenced explicitly so it could go out mid-service without locking staff out: additive scoped policies first, then an app release routing queries through authenticated clients, then confirmation of device rollout, then removal of the permissive policies.

Three migrations delivered — payroll, operations and rota, and financial, stock and document tables — all built on SECURITY DEFINER helper functions.

Documented honestly

  • An unrate-limited PIN endpoint.
  • Twelve-hour JWTs with no refresh.
  • Row-level security filters rows, not columns.
Remaining exposure was written up rather than quietly closed off, so the next piece of work starts from a real picture.

Schematics

Row-level security policies on one table, scoped per command and per role
Xcode showing the Supabase manager with an authenticated client added alongside the anon client
55 PRODUCTION TABLES · LIVE PAYROLL AND GUEST DATA STAGE 01STAGE 02STAGE 03STAGE 04 ADDITIVESCOPEDPOLICIES APPRELEASEAUTH CLIENT DEVICEROLLOUTCONFIRMED REMOVEPERMISSIVEPOLICIES ZERO DOWNTIME SERVICE UP THROUGHOUT · NOBODY LOCKED OUT
DOCUMENTED RESIDUAL EXPOSURE PIN endpointNOT RATE LIMITED 12-hour JWTsNO REFRESH CYCLE RLS filters rowsNOT COLUMNS OPENOPENBY DESIGN
Four stages, sequenced so service never stops
31 documents · six batches Operations & compliance

Compliance framework

A complete documentation set covering licensing, HR, health & safety, food safety, operational procedure and site-specific risk — written, issued and audited against.

A completed allergen matrix sheet showing fourteen allergens against menu items
Allergen sheets taped to a stainless kitchen fridge door
The compliance document set filed by category, with risk assessments listed
31 DOCUMENTS · SIX BATCHES LICENSINGHRH&SFOODOPSSITE SURVEY
Filed by category — COSHH, Legionella, young workers, near-miss, evacuation
HACCPLicensing Act s.42COSHHRisk assessment OpenClose

Scope

  • Licensing — premises licence transfer under Section 42, DPS variation, food business registration.
  • HR — contract templates, induction checklists, training records.
  • Health & safety — policy, risk assessment, cellar procedures, COSHH.
  • Food safety — HACCP system, a 14-allergen matrix across 100 menu lines, temperature monitoring, cleaning schedules.
  • Operational — Challenge 25, incident logging, CCTV policy, cash handling, fire safety log.
  • Site-specific — fire evacuation, young workers, Legionella, accident reporting, water safety, play equipment risk assessment, supplier due diligence.

From a site survey

The final batch came out of walking the sites rather than off a template — flagging hygiene-rating risks including surface deterioration in the wash-up area, chemical storage on food prep surfaces, and an unfenced water boundary next to a children's play area.

Built a master compliance checklist of 12 categories and 100+ line items, and ran internal mock EHO audits ahead of formal inspection.
Working 9 databases · 4 organisations Operations & compliance

Database backup system

Everything I build runs on one provider’s servers. Nine production databases across four organisations, and no copy of any of them anywhere else. One command now dumps every schema, every row and every role to plain SQL on my own machine, into a dated folder.

Terminal listing of the backup folder showing schema, data and roles files per project
HOSTED · SINGLE POINT OF FAILURE 7 DUMPED 2 PAUSED · REPORTED ONE COMMAND DOCKER · pg_dump roles.sqlschema.sqldata.sql RESTORE ORDER DATED FOLDERS · NOTHING OVERWRITTEN WK 31WK 32WK 33 WK 34 TWO DATED SCHEMAS DIFFED = A VERSION HISTORY OF THE DESIGN
Every project, three plain-SQL files, sizes visible — including the two that produced nothing
PostgreSQLpg_dumpSupabase CLIDockerBash OpenClose

The decisions

  • Plain SQL over the provider’s own backup format. The dashboard offers downloadable daily backups, but they restore into that provider. A .sql file restores into any PostgreSQL database anywhere — and it’s readable, so I can open it and check what’s actually in it.
  • Scriptable over manual. Nine databases clicked through by hand is twenty minutes, and a backup you have to remember to do is one you eventually stop doing.
  • Correctness over lightness. Calling pg_dump directly would have been a 50MB install rather than 1.5GB of Docker — but then I’d have to name the schemas to include myself, and the provider keeps its own internal schemas alongside mine. Get that list wrong and the backup looks complete and isn’t. The CLI already knows the right set, so I took the heavier install.
  • Three files, restored in order — roles, then schema, then data. You can’t grant a permission to a role that doesn’t exist, or insert a row into a table that doesn’t exist.

Written to survive its own failures

  • One project failing doesn’t stop the other eight. Each step checks its exit code and moves on rather than aborting the run.
  • Failures are collected and summarised at the end, not left in the scroll. Across 27 dump operations producing hundreds of lines of output, a single error in the middle is invisible; the same error alone at the bottom is not.
  • Undefined variables are fatal by design, so a typo in a path can’t quietly become an empty string in a command that deletes things.
  • Every run writes to a folder dated that day. Nothing overwrites anything — because a backup that overwrites the previous one only protects you against problems you notice immediately.
  • The run ends by printing total size on disk, as a sanity check that catches the case where nothing errored and nothing was written either.
First run: seven of nine succeeded, and the summary named the two that didn’t and the stage each failed at. Both were paused free-tier databases with nothing listening — correct behaviour, reported clearly, no edits needed to pick them up once resumed.

The side effect worth more than the backup

A dated series of plain-text schemas is a version history of the database design, obtained for free. Diffing two weeks shows exactly which columns, constraints and row-level security policies changed between them — on databases that were never under version control in the first place.

It also makes a schema greppable: CREATE TABLE tells you what a backup contains, and counting CREATE POLICY tells you how much of it is actually protected — without connecting to anything live.

Honestly, what’s still open

  • The copies are on one laptop. That covers a provider-side problem and does nothing about a dead or stolen machine. Off-machine sync is the next step and until it’s done the job is half finished.
  • The restore path has been written down but not exercised. An untested backup is a hope, not a backup — the test belongs in a scratch database, not in an emergency.
  • It runs on demand rather than on a schedule, and it covers the databases but not uploaded files.
Listed here for the same reason the security audit’s residual exposure is listed: the gap you’ve written down is the one that gets closed.
No charge

I’ll find the money before you pay me anything.

Send me your software subscriptions and I’ll come back with what’s replaceable and what it’s worth — free, and yours to keep either way. How it works →

Contact

Want the same done to your cost base?

Open to operations, automation and technical operations roles — and to talking with anyone running a multi-site business who suspects they're paying for software they could own instead.