Inspections Manager SUITESpecial inspection operations
Trust & security

What we can prove.

Inspection records are legal documents. This page describes exactly how they are protected — and every item on it is something your IT team can verify, not something we are asking you to take on faith.

Last reviewed 25 July 2026
Isolation

Your data is separated in the database, not in the interface.

Access rules that live in application code can be bypassed by any path that forgets to call them. Ours live in the database, so every path is covered by default.

125 / 125tables with row-level security enabled
409access policies in force
97of those are restrictive backstops
1table the public browser key can reach

Row-level separation, everywhere

Every table carrying customer data has row-level security switched on — all 125 of them — governed by 409 individual policies. A query that forgets a tenant filter returns nothing rather than someone else's data.

A second layer that cannot be overridden

97 of those policies are restrictive. They combine with every other policy using AND, never OR. In plain terms: even a rule that said "allow everyone" could not open a door, because the restrictive layer still refuses to let one company's data cross into another's.

The key in your browser can reach almost nothing

Public web applications ship an API key to the browser. Ours holds direct table permissions on exactly one relation — and that one is a view which evaluates the signed-in person's own permissions rather than the owner's. Signed-in users have access to 861 by comparison.

Unknown workspaces are refused at the edge

Each customer gets their own address. A request for a workspace that was never provisioned is turned away before the application loads at all — not shown an empty login form.

Integrity

A released report cannot be quietly changed.

This is the one that matters most in our industry. If a report has gone to a client or a building department, it needs to still say what it said.

The database refuses the edit

Once a report is approved or released, the lock is enforced by the data layer itself — not by a button being hidden. Every field is compared individually, and the only change an ordinary user can still make is adding the client's countersignature.

An attempt to alter a locked report fails outright:

Approved or released reports are locked.
Create a revision or use reviewer/admin workflow.

Changes that matter are logged by the database

Database triggers — not application code that could be skipped — record report releases, signatures and PDF replacements; role changes; invoice status changes; billing credential rotations; billing access grants; and document deletions.

A document delete writes its audit record before the delete happens, so the evidence cannot be removed by the same action.

Every document carries a classification

Six levels, from internal through customer-confidential to restricted-financial and restricted-legal, enforced by a database constraint. New documents default to the protective value, not the permissive one.

Audit trail

A record of who did what — that nobody can edit.

These are live counts from the production system, not a description of what the design allows.

1,135document access events
300portal access attempts
134sign-in events
35administrative actions

Append-only, including for your own administrators

The administrative audit log, the sign-in log, the portal access log and the document access log have read permissions only. No signed-in account — yours, ours, or an administrator's — holds permission to write or delete a row. Only server-side processes append.

Reading the log is itself restricted

A company administrator sees their own company's administrative records and no one else's.

Document access uses a fixed vocabulary

Every access is recorded as one of: view, download, signed-URL issue, upload, update, delete, restore, release, signature, export. The list is enforced by a constraint, so an event cannot be logged under an invented label.

Access

Roles, money, and sessions.

Eight roles, enforced in the database

Administrator, dispatcher, coordinator, project manager, inspector, biller, business development, and contractor. Billing portal users sit on a separate axis entirely — someone who can see invoices does not thereby get project access, and the reverse is also true.

Money and payroll are gated separately

Seeing a project does not mean seeing what it is worth. Financial visibility can be granted per project, and payroll is administrator-only unless an administrator grants it to a named person — a biller does not get payroll by default.

Sessions end — the real numbers

Every session ends after 12 hours, without exception. Inactivity limits differ by surface because the work does:

  • Office console — 10 hours idle. It is an operations tool that stays open through a working day.
  • Sign-in and field apps — 45 minutes idle.
  • Client and contractor portal — 30 minutes idle.

Sign-in protection

Password sign-in locks for 15 minutes after 5 failed attempts. SAML single sign-on through your own identity provider is supported and configured per customer; no customer is using it today.

Client & contractor portal

The part of the system strangers can reach.

Your clients and contractors sign in here without an account on our platform, which makes it the surface most worth hardening.

Access codes are never stored

Only a PBKDF2-SHA256 hash at 210,000 iterations with a unique per-credential salt. If a client loses their code we issue a new one — we cannot look up the old one, because nobody can, including us.

Guessing is stopped before it starts

A bot check runs before any code is compared. After 5 failed attempts in 15 minutes, access pauses — counted per project and per network address, whichever is higher, so neither axis can be used to hide behind the other.

If the system cannot count failures, it treats that as being at the limit rather than below it. It fails closed.

Errors reveal nothing

A wrong code and a project number that does not exist produce the same message after the same deliberate delay. There is no way to use the login form to discover whether a project exists.

We store a hash of the visitor's address, not the address

Portal access attempts are recorded against a one-way SHA-256 hash of the network address. The address itself is never written down.

No card or bank details, ever

This platform does not collect payment credentials on any screen. That belongs on a payment processor's own hosted page. We store remit-to details for invoicing and nothing more.

Infrastructure

Check the headers yourself.

Everything in this section is visible from outside. You do not need our cooperation to confirm it.

Transport and browser hardening

HTTPS is enforced with HSTS including subdomains and preload. A full Content-Security-Policy restricts what the browser may load and forbids the site being framed. MIME-sniffing is off, referrer policy is restrictive, and camera, microphone, payment and USB access are switched off outright.

curl -I https://inspectionsmanager.com

Endpoints your monitoring can watch

A liveness endpoint at /healthz and a readiness endpoint at /readyz, which returns an error status when the data layer is unreachable. Every response carries a request ID for support correlation.

Private files are refused by rule, not by list

Internal data files cannot be fetched over HTTP. The rule works by path class with a short allow-list, so a new private file is protected the day it is added rather than the day someone remembers to add it to a list.

Third-party keys never reach the browser

Address validation and geocoding run server-side specifically so that the credentials for those services stay on our infrastructure and out of your users' browsers.

How changes ship

A deploy that fails a check does not go out.

14 automated checks on every release

Data integrity, access rules, document parity and asset addressing are all re-verified before anything reaches you. If any check fails, the deploy stops.

The last check asks the live site

A correct repository is not the same thing as a correct deployment. Our final gate reads what production is actually serving rather than trusting what the code says it should be.

Asset addresses are content-derived

Cached files are addressed by a hash of their contents, so a cached file can never turn out to be the wrong version of that file.

Portability

Your data is yours, and you can take it.

A complete export, on request

Projects, orders, reports, NCRs and RFIs, invoices, users, billing accounts, portal access history and audit history — as structured data with a manifest listing row counts and a SHA-256 checksum for every file. Attachments included.

Secrets are stripped automatically

Passwords, access codes, tokens and API keys are removed from the export by a filter that runs over every field, rather than by remembering to exclude them.

Encrypted delivery available

Exports can be delivered AES-256-GCM encrypted. Every export request is recorded.

Subprocessors

Who else touches your data.

The full list, including the optional services that are only contacted on particular screens, is maintained alongside the code and available on request.

Cloudflare

Hosting, edge delivery, DNS and TLS. All application traffic passes through it.

Supabase

Database, authentication and file storage. Your application data lives here.

Resend

Transactional email — assignment notices, portal links, invoice notifications.

USPS

Address validation. Contacted from our servers, never from your users' browsers.

Running a security review?

Send us the questionnaire. We answer them directly, and we can walk your IT team through any control on this page.

This page is maintained alongside the code, so it reflects what is actually running.

Get in touch