Patrol
Reference
Public
Data & Screen Reference
A precise catalog of every ERPat Patrol screen and controller, the staff and public patrol-report URLs, all permission keys, the reference-number formats, database tables by area, and the scheduled jobs.
Guide version: r1
Module version: 2.0.0 Updated: 2026-07-22 Estimated time: 14 min 3 views
Reference Catalog
Data & Screen Reference
This is the lookup page for ERPat Patrol: a precise, code-grounded catalog of every screen and what it does, the URLs (including the public patrol-report links), the permission keys, the reference-number formats, the database tables behind each area, and the scheduled jobs. Use it when you need an exact answer — “what URL is the Incidents screen”, “which permission controls check-out”, “what does an RUN-… number mean”, “which table holds custody events”. The step-by-step how-to lives in Daily Operations; who configures each control lives in Administration.
How to read this page. Everything below reflects the shipped module (manifest slug patrol, version 2.0.0). Table and column names are the physical database names (all soft-deleted, all times stored in UTC and shown local). Route paths are relative to your ERPat site’s base URL. Permission names are the exact keys serialized into each user’s permissions — quote them verbatim in a support ticket.
Screens & controllers
Patrol adds one top menu item, Patrol (under Security), with a submenu per area. Each staff area is a controller that extends the authenticated base and self-gates on the module (module_patrol) plus the area permission below. The single public area (the patrol-report form) is sessionless.
Every Patrol screen — menu label, URL, controller, and the permission that opens it
| Area | Menu label | URL | Controller | Access permission |
| Dashboard | Dashboard | /patrol | Patrol | patrol_dashboard |
| Activity Log | Activity Log | /patrol_logbook | Patrol_logbook | patrol_log |
| Visitors | Visitors | /patrol_visitors | Patrol_visitors | patrol_visitor |
| Incidents | Incidents | /patrol_incidents | Patrol_incidents | patrol_incident |
| Shifts | Shifts | /patrol_shifts | Patrol_shifts | patrol_shift |
| Handover | Handover | /patrol_handovers | Patrol_handovers | patrol_handover |
| Rounds | Rounds | /patrol_rounds | Patrol_rounds | patrol_run |
| Routes | Routes | /patrol_routes | Patrol_routes | patrol_route |
| Assets | Assets | /patrol_assets | Patrol_assets | patrol_asset |
| Reports | Reports | /patrol_reports | Patrol_reports | patrol_report_export |
| Public Reports | Public Reports | /patrol_public_reports | Patrol_public_reports | patrol_public_report_triage |
| Locations | Locations | /patrol_settings | Patrol_settings | patrol_location |
| Governance | Governance | /patrol_governance | Patrol_governance | patrol_retention |
| AI Assist | AI (hidden unless on) | /patrol_ai | Patrol_ai | patrol_ai + setting module_patrol_ai |
| Public form | — (no menu; public) | /patrol-report | Patrol_report | Public — no login |
What each screen shows and does
Screen responsibilities at a glance
| Screen | Shows / does |
| Dashboard | Landing panel with quick-action buttons (Log Activity, Check In Visitor, Create Incident) and at-a-glance counters. |
| Activity Log | Searchable digital blotter of dated events. New/amend entries, attach photos, view an entry’s version history, escalate an entry to an incident. |
| Visitors | Check-in / check-out flow with live occupancy and overstay flags, deny-entry, host pre-registration invites (QR), and visitor passes. |
| Incidents | Formal register with an 8-state lifecycle, people involved, follow-up tasks, evidence under chain of custody, restricted & legal-hold controls. |
| Shifts | “On Duty Now” panel (from core attendance), shift instances, guard roster, and guard-license expiry tracking. |
| Handover | Append-only shift endorsements that auto-capture open incidents and visitors still inside; incoming guard acknowledges. |
| Rounds | Execute patrol rounds — start, scan each checkpoint, log observations, complete or abort. |
| Routes | Build routes and their checkpoints; each checkpoint gets a printable scan code and a server-side token hash. |
| Assets | Register security equipment and track issue → return custody with condition and overdue flags. |
| Reports | Read-only exports: Daily Activity Report (CSV) and Incident Register (PDF). |
| Public Reports | Staff triage queue for anonymous public submissions: correspond, set status, convert to an incident. |
| Locations | Tabbed admin for the physical hierarchy — Sites, Zones, Gates, Posts — that everything else hangs off. |
| Governance | Tabbed compliance layer — retention policies, legal holds, data-subject (privacy) requests, disclosure log. |
| AI Assist | Human-in-the-loop incident suggestions via the AkbAI proxy. Ships off; never writes incidents on its own. |
| Public form | Anonymous-capable report form + PII-free status tracker, reached with a one-time tracking code and no account. |
Routes
Every staff area follows the same shape: a base URL for the screen, then a catch-all (/<area>/<action>) that the controller resolves to its methods (list data, modal forms, save, view, delete, and area-specific actions). The public patrol-report routes are the exception — they are explicit, guest-facing endpoints.
Staff route prefixes
Base route prefixes and the notable actions behind each
| Prefix | Notable actions (as /prefix/<action>) |
patrol_logbook | list_data, modal_form, save, view, delete, file_viewer/{id}, upload_file, validate_file |
patrol_visitors | list_data, save, check_out/{id}, deny/{id}, view, invites_list_data, save_invite, issue_pass/{visit_id}, revoke_pass |
patrol_incidents | save, view, change_status/{id}, toggle_legal_hold/{id}, evidence_modal/{id}, save_custody/{evidence_id}, person_modal/{id}, task_modal/{id}, toggle_task/{task_id} |
patrol_shifts | on_duty_list_data, shifts_list_data, save_shift, assign_modal/{shift_id}, save_assignment, guards_list_data, save_guard, license_modal/{guard_id}, save_license |
patrol_handovers | list_data, modal_form, save, view, acknowledge/{id}, delete |
patrol_routes | list_data, save, view, checkpoint_modal/{route_id}, save_checkpoint, delete_checkpoint |
patrol_rounds | start_run, run_view/{id}, scan/{run_id}/{checkpoint_id}, complete_run/{id}, abort_run/{id}, save_observation/{run_id} |
patrol_assets | list_data, save, view, issued_list_data, issue_modal/{asset_id}, save_issue, return_modal/{assignment_id}, save_return |
patrol_reports | index, export_activity_csv, export_incidents_pdf |
patrol_public_reports | list_data, view, set_status/{id}, add_message/{id}, convert_to_incident/{id} |
patrol_settings | {sites|zones|gates|posts}_list_data, {site|zone|gate|post}_modal, save_*, delete_* |
patrol_governance | policies_list_data, save_policy, holds_list_data, save_hold, release_hold/{id}, dsar_list_data, save_dsar, disclosures_list_data, save_disclosure |
patrol_ai | index, accept_dpa, request, view/{job_id}, approve/{output_id}, apply_output/{output_id} |
patrol | index (dashboard) and its catch-all — declared last so specific prefixes match first. |
Public patrol-report routes
These endpoints need no login. The tenant is resolved from the {company_key} URL segment (an empty key or main uses the main database), the same way the kiosk and cron entry points work. If the tenant is not active or Patrol is switched off there, the endpoint returns a 404.
Public reporting URLs (no account required)
| Method | URL | Purpose |
| GET | /patrol-report | Report form (main database). |
| GET | /patrol-report/{company_key} | Report form for a specific tenant. |
| POST | /patrol-report/submit | Create a report; shows the one-time tracking code once. |
| GET | /patrol-report/track/{company_key} | Open the PII-free status tracker. |
| GET | /patrol-report/track/{company_key}/{code} | Look up a report’s status with its tracking code. |
| POST | /patrol-report/message/{company_key}/{code} | Reporter adds a message to their own report. |
Privacy in the public flow. The raw tracking token is shown to the reporter exactly once and is never stored — only its SHA-256 hash is kept, and lookups are constant-time verified. Anonymous submissions carry no reporter name or contact, the submitter’s IP is stored only as a hash for throttling, and the tracker never returns reporter identity or internal staff notes.
Permission keys
All keys live in the module and appear in the Roles editor under Security: Patrol while module_patrol is enabled. patrol is the module Enable toggle; administrators bypass every check. Area keys open a screen; the _create / _update / _delete children gate the actions within it.
Full Patrol permission catalog, grouped by area
| Group | Keys |
| Module & dashboard | patrol, patrol_dashboard |
| Activity Log | patrol_log, patrol_log_create, patrol_log_update, patrol_log_delete |
| Visitors | patrol_visitor, patrol_visitor_create, patrol_visitor_update, patrol_visitor_delete |
| Incidents | patrol_incident, patrol_incident_create, patrol_incident_update, patrol_incident_delete, patrol_incident_acknowledge, patrol_incident_close |
| Evidence & sensitive records | patrol_evidence_view, patrol_evidence_manage, patrol_legal_hold |
| Shifts & guards | patrol_shift, patrol_shift_create, patrol_shift_update, patrol_guard, patrol_guard_create, patrol_guard_update, patrol_guard_delete |
| Handover | patrol_handover, patrol_handover_acknowledge |
| Routes & rounds | patrol_route, patrol_route_create, patrol_route_update, patrol_route_delete, patrol_run, patrol_run_execute |
| Assets | patrol_asset, patrol_asset_create, patrol_asset_update, patrol_asset_delete, patrol_asset_assign |
| Locations & reports | patrol_location, patrol_location_create, patrol_location_update, patrol_location_delete, patrol_report_export |
| Public reporting | patrol_public_report, patrol_public_report_triage |
| Governance | patrol_retention, patrol_privacy_request, patrol_disclosure (legal holds reuse patrol_legal_hold) |
| AI Assist | patrol_ai, patrol_ai_approve |
Sensitive-action keys worth knowing. patrol_evidence_view is what reveals restricted incidents and evidence; patrol_evidence_manage adds evidence and records custody; patrol_incident_acknowledge / patrol_incident_close gate those specific lifecycle moves; patrol_legal_hold sets and releases holds. The public triage screen gates on patrol_public_report_triage (the plain patrol_public_report key exists but the triage controller uses the triage key). Applying an approved AI suggestion additionally needs patrol_incident_update.
Reference-number formats
Records that need a durable citation are stamped with a human reference the moment they are created. The year-numbered references share one format — PREFIX-YYYY-#### — where the four-digit counter runs within the current year. Two credential-style codes (visitor passes and checkpoint scan codes) use their own shape.
Reference-number prefixes and where they come from
| Prefix | Format | Applies to | Minted when |
EVT | EVT-YYYY-#### | Activity Log (blotter) entry | On submit (version 1) |
INC | INC-YYYY-#### | Incident | On create |
VIS | VIS-YYYY-#### | Visitor visit | On check-in / register |
HND | HND-YYYY-#### | Shift handover | On submit |
RUN | RUN-YYYY-#### | Patrol round (run) | On start |
PSR | PSR-YYYY-#### | Public security report | On public submit |
LGH | LGH-YYYY-#### | Legal hold | On create |
PRV | PRV-YYYY-#### | Privacy (data-subject) request | On create |
DSC | DSC-YYYY-#### | Disclosure log entry | On create |
PASS | PASS-XXXXXXXX | Visitor pass code (8 hex chars) | On issuing a pass |
CP | CP… (printable code) | Checkpoint scan code | On creating a checkpoint (with a hidden token hash) |
Why references never collide or shift. The year counter is derived from the count of logical (version 1) records for the year, and a database uniqueness constraint is the backstop. Amending a record keeps its original reference — a new version is created under the same PREFIX-YYYY-####, so a reference always points at one logical record no matter how many times it is corrected.
Status & lifecycle values
These are the exact status values you will see in list filters and on record detail pages.
Status vocabularies by record type
| Record | Values |
| Incident lifecycle | open → acknowledged → investigating → action_required → resolved → closed → archived |
| Incident severity | low, medium, high, critical |
| Visit | expected, checked_in, checked_out, denied, expired |
| Visitor invite | pending, used, cancelled, expired |
| Patrol run | in_progress, completed, missed, aborted, exception |
| Scan validation | valid, late, invalid, manual_exception |
| Evidence | held, released, disclosed, destroyed |
| Custody event | collected, transferred, checked_out, checked_in, disclosed, destroyed |
| Public report | new, triaged, linked, closed, spam |
| Asset | available, out, maintenance, retired |
| Asset assignment | out, returned |
| Shift | planned, active, completed, cancelled |
| Shift assignment | assigned, accepted, relieved, completed |
| Guard | active, inactive, suspended |
| Legal hold | active, released |
| Privacy request | open, in_progress, fulfilled, rejected |
| AI job | pending, completed, failed |
Database tables by area
Patrol ships 39 tables (all prefixed patrol_, all with the standard audit columns and a deleted soft-delete flag). They are created by the module’s own migrations and tracked in migrations_patrol. There is no tenant_id — each tenant database is self-contained, and site_id is the within-tenant location key. The tables below are grouped by area with a one-line purpose each.
Locations
| Table | Purpose |
patrol_sites | Top-level physical sites (a “Main Site” / MAIN is seeded); carries a unique code and timezone. |
patrol_zones | Zones within a site. |
patrol_gates | Gates within a site/zone (direction in / out / both). |
patrol_posts | Guard posts within a site/zone (fixed / roving / gate). |
Activity Log (blotter)
| Table | Purpose |
patrol_activity_logs | Append-only, hash-chained, versioned blotter entries (EVT-…) with photos and soft links. |
Visitors
| Table | Purpose |
patrol_visits | Visit records (VIS-…); privacy-safe — no ID number, ID image, or date of birth. |
patrol_visit_events | Append-only status-transition trail for each visit. |
patrol_visitor_invites | Host pre-registration invites, each with a unique QR token. |
patrol_visitor_passes | Issued passes (QR / badge / RFID) with a unique, revocable code. |
Incidents & evidence
| Table | Purpose |
patrol_incidents | Formal incident register (INC-…): severity, lifecycle, restricted / legal-hold flags, versioned + hash-chained. |
patrol_incident_people | People involved (reporter / witness / suspect / victim / responder / other) and statements. |
patrol_incident_actions | Append-only action & lifecycle timeline (notes, status changes, escalations, AI suggestions). |
patrol_incident_links | Soft links between an incident and related records (e.g. the source blotter entry). |
patrol_incident_tasks | Follow-up tasks with assignee, priority, due date, and done state. |
patrol_evidence | Evidence metadata + a SHA-256 content hash and seal number (bytes live in general files). |
patrol_evidence_custody | Append-only, per-item hash-chained chain-of-custody ledger. |
Shifts, guards & handover
| Table | Purpose |
patrol_guards | Guard roster (staff or external-agency guards) with a unique guard number. |
patrol_guard_licenses | Guard licenses with an expiry date and reminder flag. |
patrol_shifts | Shift instances (day / night / swing / custom) with supervisor and optional core-schedule link. |
patrol_shift_assignments | Guard-to-shift assignments; links to the guard’s live core attendance record. |
patrol_handovers | Append-only, hash-chained shift endorsements (HND-…) with acknowledgement. |
patrol_handover_items | Auto-captured / free-text checklist items on a handover (incident, visitor, equipment, instruction, note). |
Routes & rounds
| Table | Purpose |
patrol_routes | Patrol routes with an estimated duration and active flag. |
patrol_checkpoints | Ordered checkpoints per route; each holds a printable scan code and a token hash. |
patrol_route_schedules | Planned frequency/days/times for a route (schema only — no dedicated screen yet). |
patrol_runs | Round executions (RUN-…): expected vs. hit counts, outcome, overdue flag. |
patrol_scans | Individual checkpoint scans with method, validation status, and optional geo data. |
patrol_observations | Hazards/notes captured during a run, with severity and photos. |
patrol_devices | Optional scan-hardware registry (schema only — no dedicated screen yet). |
Assets & equipment
| Table | Purpose |
patrol_assets | Security equipment register (radios, flashlights, keys, vehicles, batons, other). |
patrol_asset_assignments | Issue → return custody with expected-return time, condition out/in, and overdue flag. |
Public reporting
| Table | Purpose |
patrol_public_reports | Public submissions (PSR-…): tracking-code hash, anonymity flag, urgency, IP hash, optional linked incident. |
patrol_public_report_messages | Correspondence on a report; internal notes are never returned to the public tracker. |
Governance / retention
| Table | Purpose |
patrol_retention_policies | Per-record-type retention rules (anonymize / soft_delete / purge). Ships with 4 placeholder policies, all inactive. |
patrol_legal_holds | Legal holds (LGH-…) over a record or a whole type/date range; blocks deletion and retention. |
patrol_privacy_requests | Data-subject requests (PRV-…): access / correction / erasure, with a due date and resolution. |
patrol_disclosures | Disclosure log (DSC-…): who received what, and the legal basis. |
AI Assist
| Table | Purpose |
patrol_ai_jobs | AI requests (draft / classify / briefing) with the redacted prompt summary and status. |
patrol_ai_outputs | AI outputs held pending human approval, then applied as an incident action note. |
Scheduled jobs (cron)
Patrol ships six per-tenant background jobs. They run through ERPat’s Advanced Cron, are on by default, and each self-gates on module_patrol — so when the module is off, nothing runs. Timings are shown in cron notation.
Patrol cron jobs
| Slug | Schedule | What it does |
patrol_escalate_incidents | */5 * * * * (every 5 min) | Escalates unacknowledged critical, still-open incidents older than patrol_escalation_minutes (15); de-dupes and fires the escalation alert. |
patrol_missed_rounds | */15 * * * * (every 15 min) | Flags in-progress runs overdue past their estimated time plus patrol_round_grace_minutes (15). |
patrol_asset_overdue | 0 * * * * (hourly) | Flags issued equipment still out past its expected return time. |
patrol_chain_verify | 30 2 * * * (daily 02:30) | Re-walks the hash chains of activity logs, incidents, and handovers; raises a CRITICAL alert on any break. |
patrol_license_expiry | 0 3 * * * (daily 03:00) | Flags guard licenses expiring within patrol_license_expiry_days (30). |
patrol_retention_sweep | 0 4 * * * (daily 04:00) | Applies active retention policies (anonymize / soft-delete / purge), respecting legal holds and evidence/disclosure guards, and writes a deletion certificate. |
Settings & toggles
Settings that change Patrol’s behavior
| Setting | Default | Effect |
module_patrol | — | Master on/off (Settings → Manage Modules). Gates the whole module and every cron job. |
module_patrol_ai | Off | Enables the AI Assist screen. Ships off; not seeded. |
patrol_ai_dpa | Off | One-time Data Privacy Act acknowledgement; an admin must accept it before AI can run. |
patrol_escalation_minutes | 15 | Minutes before an unacknowledged critical incident escalates. |
patrol_license_expiry_days | 30 | Look-ahead window for guard-license expiry reminders. |
patrol_round_grace_minutes | 15 | Grace added to a route’s estimated time before a round is flagged as missed. |
The three tuning values are read with a built-in fallback and are not pre-seeded, so the defaults apply until an administrator overrides them. Configuring who sets these is covered in Administration.
Notifications & the single core touch
Incident alerts are the one place Patrol reaches outside its own tables. A single core migration adds an incident link to the notifications system and seeds two notification settings — patrol_incident_raised and patrol_incident_escalated (category “Patrol”, web on, email off, no default recipients). The “raised” alert fires only when the person filing an incident ticks the Notify option; the “escalated” alert is fired by the escalation job.
No recipients means no notifications. Until an administrator assigns recipients under Settings → Notifications, these alerts reach no one — by design, to avoid spam. See Administration → incident alerts.
Where to go next
- Daily Operations — the numbered procedures for every screen listed above.
- Administration — enabling the module, granting these permission keys, setting alert recipients and cron timings, and configuring retention.
- Getting Started — first-run setup and the permission map explained for beginners.
- Research & Evidence — the source files behind every fact on this page.
- FAQ & Troubleshooting — quick answers keyed to the terms above.