Ownware
Home›Inspectora›Manual
Inspectora · Manual

Inspectora Manual, as shipped in the download

Inspectora — User Manual

Inspections, calibration and logbooks: every asset you inspect, test or calibrate, the checks it is subject to, when each was last done and when it next falls due. Platform release 3.1.0 [src: app/src/Domain.php:22].

About this manual

Every statement here was written by reading Inspectora's own source, and each one carries the file it came from in a bracketed src marker. Paths are relative to the folder this docs directory sits in. If a sentence disagrees with the application, the application is right and this manual has a bug.

Nothing is described that the code does not do. Where something is deliberately limited, or currently wrong, that is said plainly rather than left out.

What you are keeping

Six things, and the source names each one in a sentence [src: app/src/Domain.php:61]:

Assetseverything you inspect, test or calibrate — extinguishers, outlets, meters, vehicles [src: app/src/Domain.php:64]
Inspection typesthe checks an asset is subject to, and how long each one stays good for [src: app/src/Domain.php:69]
Logbookwhat was checked, when, and when it is next due [src: app/src/Domain.php:74]
Schedulesa planned round of inspections; marking one done writes the asset's record [src: app/src/Domain.php:79]
Resultswhich assets were on a round and which were actually done [src: app/src/Domain.php:85]
Evidencethe certificate, test sheet or photo behind a record [src: app/src/Domain.php:89]

Note the distinction the last two draw. A schedule says what was planned; results say what was actually done. A round with ten assets on it and six results is not six-tenths of a record — it is six records and four assets still due.

What the version number means

Inspectora reports 3.1.0 on every surface, from a single constant [src: app/src/Domain.php:22], so the ping, the OpenAPI document, the health check, the agent endpoint and the stamp inside a backup cannot drift apart.

The source is careful about what that number claims: it is the platform release the product ships on — the same number every product in the catalogue carries, so a buyer comparing two of them is comparing the same platform [src: app/src/Domain.php:18]. It is not a claim that Inspectora had a 1.x; this is its first release.

⭐ The grid, and the five states

Every cell is one asset against one inspection type, and it holds one of five states [src: app/src/Matrix.php:31]: valid, expiring, expired, none — meaning that asset has never had that check recorded at all — or failed, meaning the latest record says the check failed [src: app/src/Matrix.php:38].

They come back in the order a person should read them, worst first [src: app/src/Matrix.php:155]. Executed:

failed , expired , none , expiring , valid

A failed check heads the list because it is known to be wrong today; an expired one may simply not have been redone yet. "Never recorded" ranking above "expiring" is the right priority for a logbook: an extinguisher with no service history at all is a bigger problem than one whose certificate lapses next month.

⭐ The day a certificate runs out, it is still valid

The engine is emphatic about this. A calibration certificate that says "valid to 31 December" is valid on 31 December, and treating that day as expired is the kind of off-by-one that makes an operator distrust the whole grid [src: app/src/Matrix.php:109].

Executed, with today at 2026-09-05 and a warning window of thirty days:

next due 2026-12-31  ->  valid      valid, 117d left
next due 2026-10-05  ->  expiring   in 30d
next due 2026-10-04  ->  expiring   in 29d
next due 2026-09-05  ->  expiring   expires today      ← the due day itself
next due 2026-09-04  ->  expired    1d overdue
next due 2026-08-01  ->  expired    35d overdue

Three further behaviours, all executed:

A record with no expiry is valid forever [src: app/src/Matrix.php:109] — an inspection type that does not lapse comes back valid rather than looking like missing data.

An asset with no record at all is none, phrased "never recorded" [src: app/src/Matrix.php:130]. That is a different fact from an overdue one, and it is sorted and coloured differently.

A warning window of zero narrows "expiring" to the due day alone: 2026-09-05 is expiring, 2026-09-06 is valid.

The wording never invents a number it was not given — where no day count is available you get a bare "expired" or "expiring" rather than a fabricated figure [src: app/src/Matrix.php:141].

The engine does not know what it is inspecting

Matrix.php knows that a subject holds a requirement, that holding it has a date and may expire, that rounds are planned events producing outcomes, and that evidence attaches to a record. It does not know whether a subject is a person or a fire extinguisher [src: app/src/Matrix.php:14].

Every user-facing word and every table name arrives from Domain [src: app/src/Matrix.php:15] — here, assets, inspection types, schedules and results [src: app/src/Domain.php:31]. Even the URL segments come from there, so /assets reads like the domain while the router itself stays generic, and each segment is whitelisted before it reaches a route pattern [src: app/src/Domain.php:41].

If you are customising: add the word to Domain and read it from the view. A hardcoded "inspection" in a template is exactly how the vocabulary drifts [src: app/src/Domain.php:13].

The engine is shared with another product, and the suite enforces it

The source declares a canonical copy at tools/matrix-engine/Matrix.php, and says both products' suites md5-compare their copy against it so that editing one turns both suites red [src: app/src/Matrix.php:5]. Verified independently:

7cdb042d4b4bffb17328d182ee31b57b  tools/matrix-engine/Matrix.php
7cdb042d4b4bffb17328d182ee31b57b  44-inspectora/app/src/Matrix.php

The reason given is worth having: two codebases for one engine is an expensive mistake, and the hash check is the tripwire against making it by accident [src: app/src/Matrix.php:7].

SQL safety

Table names are the only identifiers interpolated into a query; everything else is a bound parameter [src: app/src/Matrix.php:17]. Those names come from a hardcoded map, never from input, and are whitelisted again before they reach a query, so a bad value fails in one place rather than producing a query nobody reads [src: app/src/Matrix.php:56].

API keys are shaped so a mistake fails cleanly

Every key carries a per-product prefix — ink here [src: app/src/Domain.php:95]. The reasoning is stated: a key pasted into the wrong installation is rejected by its shape rather than by a lookup that leaks whether it exists [src: app/src/Domain.php:93].

Users and roles

Three roles [src: app/controllers/v3.php:24]. A viewer reads the grid and the reports; a member can also record an inspection and run a scheduled round [src: app/controllers/v3.php:25]; admin holds everything [src: app/controllers/v3.php:26].

Backups are for administrators

Both backup downloads ask for the administrator role — the JSON export and the SQLite file [src: app/controllers/api.php, backup_json() and backup_sqlite()] — and so do the restore page and the scheduled-backup token. A viewer or member who opens either address is refused, and the Security page shows the backup buttons to administrators only [src: app/views/security.php].

A backup contains every table: the full inspection history of every asset, including which checks were overdue and for how long. The JSON export redacts credential hashes and the SMTP password; the SQLite file is the database itself, byte for byte. Before 3.1.3 a sign-in alone was enough to download either.

Webhooks: one event, fired from every door

The one event offered for subscription is record.created [src: app/src/Webhook.php], and it fires from every path that writes an inspection record: the board, a round being marked, the REST API and the agent tool. Before 3.1.3 the settings screen offered three leave-management events this product never fires, and record.created could not be ticked.

Reminders and the digest

Two switches under Settings → Email, both off on a fresh install, both sent only through the SMTP server you enter there:

  • "email me a digest of what is expiring" — one message a day, to your notification address, listing everything failed, expired or expiring within the warning window.
  • "tell them when something of theirs is expiring" — a note to the address on each asset (usually the responsible team) with something expired or expiring, never more often than the "remind … at most every N days" setting.

They go out when cron/reminders.php runs. Schedule it once a day, for example 15 7 * * * php /path/to/app/cron/reminders.php, and try --dry-run first: it lists who would be written to and sends nothing. On a host without cron, Settings → Run reminders now runs the same pass. Running it twice in a day sends nothing the second time: every note is claimed in a ledger before the mail server is contacted, and a send the server refuses gives its claim back so the next run retries [src: app/controllers/app.php, reminder_run()]. Before 3.1.3 the README named this script but it was not shipped, and the two switches did nothing.

Settings shows when the pass last ran and what it did. When a switch is on and nothing has run the pass for more than two days, the dashboard says so.

The API and agent access

Five tools [src: app/controllers/v3.php:64]: four read — the whole grid, what needs attention, one asset in detail and the inspection-type list — and exactly one write, recording a completed inspection [src: app/controllers/v3.php:155].

The instructions given to an agent carry a guarantee worth knowing yourself [src: app/controllers/v3.php:60]:

"Read the matrix before you write to it. Recording a completion is the only write here; it goes through the same engine call the screens use, so the refusals are identical."

There is no separate API validation to drift out of step with what the screens enforce.

What Inspectora does not do

It does not treat the due day as overdue [src: app/src/Matrix.php:109].

It does not confuse "never inspected" with "overdue" [src: app/src/Matrix.php:130].

It does not invent a day count it was not given [src: app/src/Matrix.php:141].

It does not let a template decide the vocabulary [src: app/src/Domain.php:13].

It does not accept a key from another installation on a lookup [src: app/src/Domain.php:93] — the shape is rejected first.

It does not let a fail start a clock. Every record carries a result: pass, pass with remarks, or fail [src: app/src/Matrix.php:46]. A fail is written to the logbook like any record, but with no next-due date [src: app/src/Matrix.php:371], and its cell reads "failed" until a later pass supersedes it; a pass dated before the fail does not clear it. A pass with remarks is a pass, with its next-due date; the remarks go in the note. Before 3.1.3 a record could only say that the inspection took place, so a check that failed showed as in date.

← Back to Inspectora · Quickstart · API · Test run

Affiliate program
Recommend tools people own — earn 35% on every sale. 90-day tracking, instant delivery, payouts by Lemon Squeezy.
Become an affiliate →