The problem
Safety audits in the field were paper-driven. The people doing the work are often on a site with poor connectivity, wearing gloves, and working through a long structured checklist — a context that punishes any interface designed for a desk.
The mobile app
An Expo and React Native app organised with Expo Router, using a file-based route structure with an authenticated group separated from the public login flow. Sign-in goes through expo-auth-session against Microsoft Entra ID, and tokens are held in the device keystore via expo-secure-store rather than in async storage.
Modelling the domain properly
The audit domain is genuinely hierarchical, and flattening it would have made reporting impossible later. The schema models it directly.
- Identity and access as users, roles and a user-role join, rather than a role string on the user.
- Code-keyed reference tables for regions, observer roles, evaluation types and department practices, so lookups stay stable as labels change.
- SAFE Program categories and subcategories seeded via idempotent MERGE scripts, re-runnable without duplicating reference data.
- NETA equipment and forms kept schema-only until a real source of truth was available, rather than seeded with placeholder data that would later be mistaken for real.
The API
An ASP.NET Core API split into Api and Domain projects, using EF Core against SQL Server on AWS RDS. Structured logging runs through Serilog into CloudWatch, and the surface is documented with Swagger. The schema DDL is idempotent — it drops and recreates cleanly — so environments can be rebuilt from scratch without hand-holding.