Patrol Reference Public

Administration

Administer the ERPat Patrol module: the permissions matrix, module and AI toggles, Locations, CSV and PDF reports, the six cron jobs, incident alerts, public security reporting, governance and retention, and how to enable AI-assist responsibly.

Guide version: r1 Module version: 2.0.0 Updated: 2026-07-22 Estimated time: 13 min 1 views
For administrators & data protection officers

Administration

This page is the control panel for the people who set up, secure, and govern Patrol — system administrators, security managers, Data Protection Officers (DPOs), and support leads. It covers the permissions matrix, the module and AI toggles, Locations, the CSV/PDF reports, the background jobs, incident alerts, the public reporting channel, the governance/retention layer, and how to switch on AI-assist responsibly. Day-to-day guard tasks live on the Daily Operations page; exact fields, tables, and screens are on the Data & Screen Reference.

Design law you will see everywhere. Patrol records are append-only and tamper-evident. Nobody — not even an administrator — can quietly rewrite a submitted blotter entry, incident, or handover; corrections create a new version and the original is kept and hash-chained. Governance is safe by default: retention deletes nothing, and AI-assist is switched off, until an authorised person deliberately turns them on.

Audience & prerequisites

Three roles do the work described here:

  • System administrator — enables the module, runs migrations, grants permissions, wires up alerts, and manages the scheduler that runs the cron jobs.
  • Security manager / supervisor — owns Locations, Reports, the public-report triage queue, and the operational settings.
  • Data Protection Officer (DPO) / privacy officer — owns Governance: retention policies, legal holds, data-subject requests, the disclosure log, and the decision to enable AI-assist.

The setup order is always the same: enable the module → grant permissions → create your Locations → configure alerts and (optionally) governance/AI. Full-account admins bypass every permission check, so grant scoped roles to everyone else rather than making people admins.

Enabling the module

  1. Open Settings → Manage Modules and switch on Patrol. This flips the module_patrol setting to 1. Every controller, sidebar entry, public endpoint, and cron job checks this flag first — when it is off, the whole module goes dark and the six jobs skip themselves.
  2. Apply the module database tables with php erpat migrate:modules (tracked in the per-module migrations_patrol table). The first migration seeds one default site — Main Site (code MAIN) — so you have somewhere to log against immediately.
  3. Apply the single core migration with php erpat migrate:latest. It adds notifications.patrol_incident_id (so an alert can deep-link straight to an incident) and registers the two Patrol notification events. This is Patrol's only touch on core tables.
  4. Grant permissions (below), then have a supervisor build out Locations.
Multi-tenant note. Each tenant database is self-contained — there is no cross-tenant tenant_id; site_id is the intra-tenant location key. Run php erpat migrate:modules and migrate:latest against every tenant that should have Patrol, and enable module_patrol per tenant.

Permissions matrix

Patrol owns its own RBAC keys (category “Security: Patrol” in the Roles editor); they appear only while the module is enabled. Keys are stored by name, so once shipped they are frozen. patrol is the module Enable toggle; the remaining keys gate each area, with the usual _create / _update / _delete family per area. A handful of keys are deliberately separate because they guard sensitive powers — grant them narrowly.

Patrol permission keys grouped by functional area
Permission keyWhat it grants
Module & dashboard
patrolModule access (the Enable toggle). Required for every Patrol screen.
patrol_dashboardView the Patrol dashboard.
Activity Log (blotter)
patrol_log · _create · _update · _deleteView, add, amend (creates a new version), and delete blotter entries.
Visitor management
patrol_visitor · _create · _update · _deleteView; register/check-in, invites and pass issue; check-out/deny/pass-revoke; delete.
Incident register
patrol_incident · _create · _update · _deleteView, create, update (people, tasks, amendments), and delete incidents.
patrol_incident_acknowledgeMove an incident to acknowledged.
patrol_incident_closeClose / reopen (and archive) an incident.
Evidence & sensitive controls
patrol_evidence_viewSee restricted incidents and evidence. Without it, restricted records are hidden from lists, views, reports, and AI.
patrol_evidence_manageAdd evidence and record chain-of-custody events.
patrol_legal_holdPlace and release legal holds (also used by Governance).
Shifts, guards & handover
patrol_shift · _create · _updateShifts, the On-Duty panel, and guard assignments.
patrol_guard · _create · _update · _deleteGuard roster and license tracking (update also gates licenses).
patrol_handover · patrol_handover_acknowledgeSubmit shift handovers; acknowledge an incoming handover.
Rounds & routes
patrol_route · _create · _update · _deleteBuild routes and checkpoints (update also gates checkpoints).
patrol_run · patrol_run_executeView rounds; start / scan / complete / abort a round.
Assets & equipment
patrol_asset · _create · _update · _deleteRegister and manage equipment.
patrol_asset_assignIssue and return equipment.
Locations & reports
patrol_location · _create · _update · _deleteManage Sites / Zones / Gates / Posts.
patrol_report_exportOpen the Reports page and run the CSV / PDF exports.
Public reporting
patrol_public_reportView public reports (defined for reference).
patrol_public_report_triageWork the triage queue: set status, correspond, and convert to an incident.
Governance / retention / DSAR
patrol_retentionGovernance page + retention policies. Also the area gate for the whole Governance page.
patrol_privacy_requestLog and manage data-subject (privacy) requests.
patrol_disclosureRecord entries in the disclosure log.
AI-assist
patrol_aiRequest AI suggestions (only works when AI-assist is switched on).
patrol_ai_approveApprove an AI suggestion before it can be applied.

Applying an approved AI suggestion additionally requires patrol_incident_update. Converting a public report into an incident additionally requires patrol_incident_create.

Module settings & toggles

Three named toggles govern the whole module, plus three timing knobs:

SettingDefaultEffect
module_patrolSet by Manage ModulesMaster on/off. Gates every screen, public endpoint, and cron job.
module_patrol_aiOff (not seeded)Switches on the AI-assist surface. See AI-assist.
patrol_ai_dpaOff (not seeded)One-time DPA acknowledgement required before any AI request. Only an admin can accept it.
patrol_escalation_minutes15Minutes an unacknowledged critical incident may sit before the escalation job alerts.
patrol_license_expiry_days30How far ahead the license job flags guard licenses due to expire.
patrol_round_grace_minutes15Grace added to a route’s estimated time before a round counts as overdue.
The three timing settings are read with built-in fallbacks and are not seeded. Patrol works out of the box on 15 / 30 / 15. To change one, add it as a system setting with your value; the module picks it up on the next run. No migration re-run is needed.

Locations admin

Locations are the physical hierarchy — Sites → Zones → Gates → Posts — that Routes, Checkpoints, Shifts, and Rounds hang off. They live on one page (patrol_settings) with a tab per entity, gated by patrol_location (plus _create / _update / _delete).

  • Sites — a building, compound, or property. Main Site (MAIN) is seeded; each site has a unique code and timezone.
  • Zones — areas inside a site (lobby, basement, perimeter).
  • Gates — entry/exit points, direction in / out / both.
  • Posts — guard positions: fixed, roving, or gate.

Set these up before building routes or scheduling shifts — checkpoints, guards, and runs all reference a site.

Reports & exports

The Reports page (patrol_reports, gated by patrol_report_export) produces two server-side exports. Both reuse the live activity and incident data — they never fork the queries — and default to the last 7 days; you can pass a start date, end date, and site.

  • Daily Activity Report — CSV (export_activity_csv). Reference, time, category, location/post, summary, narrative, action taken, and reporter. The CSV is formula-injection safe: any cell that could be read as a spreadsheet formula is neutralised, so opening the file in Excel is safe.
  • Incident Register — PDF (export_incidents_pdf, A4). Restricted incidents are excluded unless the person running the export holds patrol_evidence_view.

The list screens also carry the standard on-screen table export (copy / spreadsheet columns) for quick pulls; the two exports above are the governed, server-side reports.

Incident alerts (notifications)

Patrol registers two notification events (category Patrol): patrol_incident_raised (fired on incident creation when the “notify” box is ticked) and patrol_incident_escalated (fired by the escalation job). Both deep-link straight to the incident and default to in-app on, email off.

They ship with no recipients — on purpose, so nobody is spammed. Until you open Settings → Notifications and assign recipients (team members and/or teams) for the two Patrol events, no alert reaches anyone. Assigning recipients is a required setup step if you want incident alerts.

Cron jobs

Patrol ships six background jobs. All run per tenant, are enabled by default, and self-gate on module_patrol (they do nothing while the module is off). They only fire if your ERPat scheduler is calling the Advanced Cron runtime — inspect them with php erpat cron:list, tick the scheduler with php erpat cron:tick, and run one on demand with php erpat cron:run <slug>.

Job slugCadenceWhat it does
patrol_escalate_incidentsEvery 5 min */5 * * * *Escalates a critical, still-open incident left unacknowledged past patrol_escalation_minutes (15). Records an escalation action and fires patrol_incident_escalated. De-dupes so it only escalates once.
patrol_missed_roundsEvery 15 min */15 * * * *Flags an in-progress round overdue past its route estimate + patrol_round_grace_minutes (15). Logs an overdue warning once.
patrol_asset_overdueHourly 0 * * * *Flags issued equipment past its expected-return time. Logs an overdue warning once.
patrol_chain_verifyDaily 02:30 30 2 * * *Read-only re-walk of the daily hash chains for blotter entries, incidents, and handovers. Any break (deleted, reordered, or altered row) writes a CRITICAL chain_break log.
patrol_license_expiryDaily 03:00 0 3 * * *Flags guard licenses expiring within patrol_license_expiry_days (30), once per license.
patrol_retention_sweepDaily 04:00 0 4 * * *Applies active retention policies (see Governance). Does nothing until a DPO configures one.

Public security reporting

Patrol includes an account-free channel where residents or the public report a concern and track it with a one-time code. It is served by a public, sessionless endpoint and is anonymity-capable and PII-minimised by design.

The public URL

  • The form lives at /patrol-report and, for a specific tenant, /patrol-report/{company_key} (the tenant’s company key resolves the right database, the same way the kiosk and cron URLs do). Publish that link on your community site, a QR poster, or a gate sign.
  • Reporters check status at /patrol-report/track/{company_key}/{code} — a PII-free page that never shows reporter details or internal staff notes.
  • The endpoint returns a generic “not found” for a bad or disabled tenant, so it cannot be used to probe which tenants exist.

Anonymity & anti-abuse

  • One-time tracking code. The raw code is shown to the reporter once and never stored — only its SHA-256 hash is kept, and lookups are constant-time. If a reporter loses the code, it cannot be recovered.
  • Anonymous mode nulls the reporter name and contact. The reporter’s IP is never stored in the clear — only a SHA-256 hash, used solely for throttling.
  • Throttling. Submissions are capped per IP: 5 per hour (session-backed) with a database backstop that blocks an IP after 10 submissions in 60 minutes.

Triage

Staff work incoming reports on the Public Reports page (patrol_public_reports, gated by patrol_public_report_triage): read the queue (with a “new” count), reply to the reporter (public message) or add internal-only notes, and set status new / triaged / closed / spam. Convert to incident (which also needs patrol_incident_create) maps urgency to severity — low→low, normal→medium, high→high, emergency→critical — creates an incident with source public, links the two, and marks the report linked.

Governance, retention & disclosure

The Governance page (patrol_governance) is the DPO’s compliance layer, with four tabs. The area gate is patrol_retention; each tab has its own key.

  • Retention policies (patrol_retention) — one rule per record type (activity log, incident, visit, public report), an action (anonymize, soft delete, or purge), and a retention period in days.
  • Legal holds (patrol_legal_hold) — freeze a specific record, or a whole record type within a date range, so the retention sweep can never touch it. Legal-hold incidents also cannot be deleted.
  • Data-subject requests / DSAR (patrol_privacy_request) — log access, correction, and erasure requests with a due date, and track them to fulfilled or rejected.
  • Disclosure log (patrol_disclosure) — record every release of records to a third party and its legal basis (subpoena, law enforcement, consent, legal obligation, other).
Retention deletes nothing until you configure it. Patrol seeds four placeholder policies inactive and with a blank retention period. The daily patrol_retention_sweep job only acts on a policy that a DPO has both set a period on and switched to active. This is deliberate — no data is ever aged out by accident.

When a policy runs, the sweep respects strong safety rails: it excludes anything under an active legal hold, it never purges a record that has a logged disclosure or (for incidents) still has evidence, and it caps each run. Every run writes a deletion certificate to the audit log and stamps the policy’s last-run time. Alongside it, the daily patrol_chain_verify job re-checks the tamper-evident hash chains and raises a CRITICAL log on any break.

Activating a retention policy responsibly

  1. Agree the retention period for each record type with your legal/compliance owner (e.g. keep visitor logs N days).
  2. On the Retention policies tab, edit the placeholder for that record type: choose the action (start with anonymize or soft delete before ever using purge), set the days, and switch it active.
  3. Place any needed legal holds first so litigation-relevant records are frozen before the sweep runs.
  4. Let the daily sweep run, then check the deletion certificate in the audit log to confirm what was acted on.

AI-assist (ships disabled)

Patrol can draft an incident narrative, suggest a classification, or write a handover briefing using the existing AkbAI proxy — but it is human-in-the-loop and switched off by default. AI never writes an incident: output is held pending explicit human approval, and applying it only ever adds an action note to the incident.

Three gates must all pass before a single request can be made:

  1. Module & permissionmodule_patrol on and the user holds patrol_ai.
  2. module_patrol_ai = 1 — while off, the page shows a “disabled” notice.
  3. patrol_ai_dpa = 1 — a one-time Data Processing Agreement acknowledgement that only an administrator can accept.

Before any text leaves the tenant it is PII-redacted — emails, phone numbers, long ID numbers, and named individuals are masked. Requests run only against non-restricted incidents (using a restricted incident additionally needs patrol_evidence_view). A reviewer with patrol_ai_approve approves an output; a user with patrol_incident_update then applies the approved text as an ai_suggestion action. Every step is audited, and if AkbAI is not configured the request fails gracefully.

Enabling AI-assist responsibly

  1. Confirm your organisation’s data-processing position with your DPO, and that AkbAI is configured for the tenant.
  2. Switch on module_patrol_ai.
  3. Have an administrator open the AI page and accept the DPA (sets patrol_ai_dpa).
  4. Grant patrol_ai to the officers who may request suggestions, and patrol_ai_approve to the reviewers who may approve them — keep those two roles separate.
  5. Treat every suggestion as a draft: review, edit, and only then apply it as an incident note.

Audit & integrity notes

Every mutation across the module writes an audit entry (system-log category Security), times are stored in UTC and shown local, and everything is soft-deleted. Reference numbers (EVT-, INC-, VIS-, HND-, RUN-, PSR-, LGH-, PRV-, DSC-) are minted once and never reused; amendments create a new version rather than editing in place. Administrators do not need to manage any of this — it is automatic — but it is why some records cannot be edited or hard-deleted. The tables, columns, and log components behind each area are catalogued on the Data & Screen Reference.

Related pages

Was this guide helpful?

Report a content problem