Case study 02 / Quality systems

An internal audit system where the evidence survives the audit.

Audit scheduling, role-based reviews, evidence collection, scoring, and exports a director can read — built so that six months later you can still prove what was checked and who signed it off.

Role
Sole developer — data model, permissions, backend, frontend, reporting
Stack
Laravel (PHP) · MySQL · Blade · Tailwind
Type
Quality management / compliance system

The problem

Internal audits usually start life as a spreadsheet template, a shared folder of photos, and a chain of emails. Each of those works individually. Together, they lose the one thing an audit exists to produce: a defensible record that a specific person checked a specific thing on a specific date.

The failure shows up months later, when someone asks why a finding was closed and the answer is spread across three inboxes and a folder nobody can find.

What the system does

How it is built

Laravel with MySQL. This is exactly the kind of system Laravel is good at: heavy on relationships, heavy on permissions, and heavy on the boring correctness work that makes a compliance tool trustworthy.

Permissions as a first-class part of the data model

Role checks are attached to the data itself rather than scattered through the interface. Hiding a button is a user experience decision; it is not security. Every action verifies on the server that this user, in this role, may act on this specific audit — which also means a new role can be added later without auditing every screen for a missed check.

Findings are immutable once submitted

A submitted finding cannot be quietly edited. Changes happen through a documented revision that keeps the original visible. This is unpopular for about a week and then becomes the feature people trust the system for — an audit record that can be rewritten is not an audit record.

Reusable pattern. Any system where someone's sign-off carries weight — approvals, inspections, incident reports — needs the same property: the record of what was approved must be separable from the record as it exists today.

What I would change

The export layer was built for one report format and then extended for others, which made it harder to change than it needed to be. A template-driven approach, where the report structure is data rather than code, would have let the organisation adjust their own formats without a developer.

Need something similar?

Approval flows, evidence trails, and role-based review are common requirements well beyond auditing. The internal tools service covers this kind of build, and the POS Flask case study shows a related approach to keeping history intact.

Approvals living in email?

If your compliance record is a folder and a chain of replies, it is one staff change away from being unusable. Let's fix that.

Start a conversation ↗