diff --git a/docs/apps/dispatch.md b/docs/apps/dispatch.md
index 7c1b3f5..30ec8a8 100644
--- a/docs/apps/dispatch.md
+++ b/docs/apps/dispatch.md
@@ -152,6 +152,18 @@ Real-time statistics banner displaying:
- Auto-reconnect with background resume refresh
- Events trigger automatic data refresh across all console panels
+### Run cards and recommendations
+
+When the department uses [Run Cards](../web-app/run-cards), the New Call screen shows the recommended units and personnel for the call's priority and type (or dispatches them automatically), lets the dispatcher escalate alarm levels, and surfaces move-up recommendations.
+
+### Chat, moderation and the Assistant
+
+Dispatch is the reference chat client: all channels, incident channels per call, urgent messages and the Assistant. See [Chat & Assistant](../web-app/chat).
+
+### Field Records
+
+With `Records.Field.Dispatch` enabled, dispatchers can start the NERIS incident report or a run record directly from the call. See [Records](../web-app/records/overview).
+
## Settings & Configuration
| Setting | Description |
diff --git a/docs/apps/responder.md b/docs/apps/responder.md
index 17d881f..a029ab1 100644
--- a/docs/apps/responder.md
+++ b/docs/apps/responder.md
@@ -102,6 +102,18 @@ Resgrid Responder is a cross-platform application designed for **individual firs
- **Geolocation Hub**: live personnel and unit location updates
- Auto-reconnect with token refresh
+### Chat & Assistant
+
+Department, station, group and incident channels, direct messages (to people or to a unit's crew), threads, reactions, urgent messages with acknowledgement, and the **Assistant** for plain-language commands. Push notifications follow the web routing matrix (mentions, DMs and urgent messages push; open channels do not). Requires the `Chat.System` feature flag. See [Chat & Assistant](../web-app/chat).
+
+### Checklists
+
+Personal and assigned checks (start-of-shift, personal gear, station duties) run from the app with photos, signatures, N/A reasons and offline progress; due checks appear on the home screen. See [Checklists](../web-app/checklists).
+
+### Field Records
+
+When `Records.Field.Responder` is enabled, members author Records in the field (run reports, training records, department definitions such as SAR clue reports or damage assessments) with offline drafts, attachments and sync; finalisation can be handed to the web app. See [Records](../web-app/records/overview).
+
## Settings & Configuration
| Setting | Description |
diff --git a/docs/apps/unit.md b/docs/apps/unit.md
index 9aa0135..631c98e 100644
--- a/docs/apps/unit.md
+++ b/docs/apps/unit.md
@@ -139,6 +139,22 @@ The app uses a sidebar/drawer layout that adapts to orientation:
**Modal screens**: Create New Call, Call Detail, Edit Call
+### Chat
+
+Unit identity chat: messages sent from the app are attributed to the unit (with the human sender recorded), incident channels open automatically for dispatched calls, and DMs addressed to the unit reach the whole crew. See [Chat & Assistant](../web-app/chat).
+
+### Checklists and equipment
+
+Unit-targeted checklists (apparatus daily / weekly, SCBA, equipment checks) run from the tablet with witness hand-off, photos and evidence; failed critical items can place the unit out of service and raise a work order (Readiness Pro). The equipment issued to the unit from [Inventory](../web-app/inventory) is listed for reference and consumption. See [Checklists](../web-app/checklists).
+
+### Field Records
+
+With `Records.Field.Unit` enabled the crew authors **Unit activity** and run records from the app, with the unit's times prefilled from status changes. See [Records](../web-app/records/overview).
+
+### Hardware GPS trackers
+
+Vehicles with a hardware tracker report position alongside (or instead of) the app; the web administrator sets the source priority. See [Hardware GPS Tracking](../web-app/unit-tracking).
+
## Settings & Configuration
| Setting | Description |
diff --git a/docs/configuration/inventory-types.md b/docs/configuration/inventory-types.md
index e2aa698..73d3c46 100644
--- a/docs/configuration/inventory-types.md
+++ b/docs/configuration/inventory-types.md
@@ -4,6 +4,10 @@ sidebar_position: 20
# Inventory Types
+:::caution Legacy page
+This page describes the original inventory *types* screen. Since the 2026 inventory modernization the **Inventory** module is a full workspace — items with bulk or serialized tracking, locations, lots with expiry, assets, kits, issuance, counts, alerts, purchasing and reports. The old *Manage Types* link now opens the **Items** tab of that workspace, and existing types and balances are imported the first time an administrator presses **Initialize inventory**. Read [Web application → Inventory](../web-app/inventory) for the current module; the notes below remain for departments still on the legacy screens.
+:::
+
Inventory Types in Resgrid define the categories of items your department tracks in the inventory system. Each type represents a class of supply or equipment — such as "SCBA Bottles", "Medical Supplies", "Hose Sections", or "Batteries" — and includes configuration for units of measure and expiration tracking.
## Why Inventory Types Matter
diff --git a/docs/how-tos/setup-department.md b/docs/how-tos/setup-department.md
index 38eb466..150afd6 100644
--- a/docs/how-tos/setup-department.md
+++ b/docs/how-tos/setup-department.md
@@ -4,6 +4,10 @@ sidebar_position: 2
# Setup Department
+:::tip Recipes by organization type
+This page is the generic, screen-by-screen walk-through. For concrete values — which unit types, call types, roles, statuses, run cards, checklists and records to create for a **fire department, EMS agency, SAR team, emergency management office, incident management team, CERT program, security company, industrial ERT, delivery/transit operator or multi-agency dispatch centre** — see the [Setup guides by organization](../setup-guides/overview).
+:::
+
This guide walks you through every step needed to get your Resgrid department configured and ready for day-to-day use. Work through the sections in order — each one builds on the previous.
## Before You Begin
diff --git a/docs/intro.md b/docs/intro.md
index 7bd0253..6aabf74 100644
--- a/docs/intro.md
+++ b/docs/intro.md
@@ -4,40 +4,62 @@ sidebar_position: 1
# Introduction
-**Resgrid: The Complete Open Source Computer Aided Dispatch & Emergency Management System**
+**Resgrid: the complete open-source computer-aided dispatch, records and readiness platform**
-Resgrid is a computer aided dispatch, management and logistics for first responders, disaster response, emergency management and companies.
+Resgrid is computer-aided dispatch, personnel and unit management, records management and logistics for first responders, disaster response, emergency management — and for the businesses and industrial teams that dispatch people and vehicles to jobs.
-Originally started as a hosted only solution in 2014, the Resgrid system as processed hundreds of thousands of calls, messages, statuses and staffing updates and much more. With over 4,000 departments signed up Resgrid is the only open source computer aided dispatch system able to run at scale.
+Started as a hosted service in 2014, Resgrid has processed millions of calls, messages, statuses and staffing updates for thousands of departments. It is the only open-source CAD able to run at that scale, and the same code runs the hosted service and self-hosted installations.
-Resgrid is written on the Microsoft .Net and .Net Core Frameworks utilizing Microsoft SQL Server as the primary data repository.
+Resgrid is written in C# on .NET with SQL Server or PostgreSQL as the primary store, Redis for caching, RabbitMQ (or Azure Service Bus) for messaging, and React Native / Expo mobile apps.
-:::danger Work In Progress
-This documentation is an on-going Work-In-Progress (WIP) and is not complete. There many sections that are empty to help organize, give landing areas and structure for documentation. Documentation is usually added when we address issues or get questions. If you need information and the area of the documentation is missing or incomplete, please create a Github issue
-with the question and we will address it.
+:::tip Where to start
+- **Using the web app?** Start with the [Web application overview](web-app/overview) and [Navigation](web-app/navigation).
+- **Setting up a department?** Pick the recipe for your organisation under [Setup guides](setup-guides/overview).
+- **Hosting it yourself?** See [Self-hosted](self-hosted/quick-start).
+- **Integrating?** See the [API](api/authentication) and [Workflows](web-app/workflows).
:::
-:::tip User Interface Changes
-We update our User Interfaces for our websites and applications every couple of years. As such the UI shown in Pictures in this documentation may not match what is currently in production. Functionality should remain the same but may be presented differently. We don't update the pictures/documentation unless there is a major overhaul of the functionality.
+:::info Screenshots
+Screenshots in this documentation were taken from the current web application with sample data. The interface is updated over time; functionality stays the same even when a screen looks a little different.
:::
-## Features
-
-- **Personnel Management**: Define personnel, contact information, details, certification, roles, status and availability for all personnel
-- **Unit Support**: Support for apparatuses and groups of personnel working as a single unit (i.e. a USAR team) with AVL, accountability and logging
-- **Groups and Locations**: Create groups and locations and assign personnel or units underneath for management of large or disperse organizations
-- **Computer Aided Dispatch**: Create CallsIncidents and dispatch personnel, units, roles or groups to respond to those incidents both manual and automatic dispatches are supported
-- **Messaging**: Built in message system to allow for targeted and dynamic communications to personnel
-- **Chat**: Embedded P2P, Groups, Dispatch to Unit and Command chat system to enable very quick text based communications
-- **Duty Shift System**: Create both Assigned Shifts and Signup Shifts to manage a static or dynamic workforce, switch swapping and trading support with attendance validation
-- **Learning Management**: Design Trainings with text based materials, attach documents or presentations or link to external videos and assign questions to validate understanding of material
-- **Run Logs and Logging**: Record actions of a call, training and meetings to keep tract of actions and events, hours, personnel and units involved
-- **Reporting**: Generate reports for run logs, calls, training, meetings and more. Ability to use Reporting to create exports to integrate with 3rd party systems
-- **Calendar System**: Create calendar entries and setup RSVP style events to keep personnel engaged and informed about activities and events
-- **Inventory Management**: Track any kind of inventory both perishable (like medicine) and durable (like hand tools) equipped on apparatus, issued to personnel or stored at locations
-- **Document Storage**: Upload and serve documents at a department or group level to members of your organization allowing a centralized place to serve documents from
-- **Notifications Service**: Flexible notification system to alert of low personnel role or unit availability, staffing or status changes or any other system generated event
-- **Department Linking**: Create powerful department links to allow for multiple independent organizations (i.e. mutual aid agreements or centralized dispatch center) to cooperate
-- **Mobile Apps**: Apps available on Google Play and Apple App Store that can work with any standard installation. For Personnel, Units, Stations and Commanders.
-- **API**: Included API with information about calls allow for easy extension and interaction without having to change code in the Resgrid Core codebase
+## What is in the box
+### Operations
+
+- **Computer-aided dispatch** — create calls by hand, from email/SMS pages, from the API or the Assistant; dispatch personnel, groups, roles and units; push, SMS, email and voice alerting; check-in timers; scheduled calls. [Dispatch & Calls](web-app/dispatch-calls)
+- **Run cards and automatic dispatch** — pre-planned assignments by priority and type, station-based or closest-unit selection, alarm levels, move-ups. [Run Cards](web-app/run-cards)
+- **Personnel, units, groups and statuses** — the roster, apparatus, stations with geofences, and fully customisable status and staffing vocabularies. [Personnel](web-app/personnel) · [Units](web-app/units) · [Groups & Stations](web-app/groups-stations) · [Custom Statuses](web-app/custom-statuses)
+- **Mapping** — live map with layers, points of interest, custom raster/region maps, indoor floor plans, routing, hardware GPS trackers. [Mapping](web-app/mapping) · [Custom Maps](web-app/custom-maps) · [Indoor Maps](web-app/indoor-maps) · [Hardware GPS Tracking](web-app/unit-tracking)
+- **Routes** — planned multi-stop routes for hydrant checks, patrols, deliveries and transit. [Routes](web-app/routes)
+- **Shifts and workshifts** — assigned and signup shifts, trades, staffing views. [Shifts](web-app/shifts)
+- **Chat and Assistant** — realtime channels, DMs, incident channels, moderation, and a conversational assistant that takes commands. [Chat](web-app/chat)
+- **Voice** — push-to-talk channels and audio streams. [Voice & Audio](web-app/voice-audio)
+
+### Records and reporting
+
+- **Records (RMS)** — typed operational records, NERIS incident reporting, department-designed forms from template packs (SAR, CERT, EOC, HAZMAT, industrial, security, delivery, transit, ICS forms), prevention (occupancies, inspections, hydrants, permits, CRR), investigations, analytics, quality review, legal holds and public-records disclosure. [Records](web-app/records/overview)
+- **Reports** — printable and scheduled reports across every module. [Reports](web-app/reports)
+- **Documents, notes, calendar, trainings** — the department's shared knowledge and learning. [Documents](web-app/documents) · [Notes](web-app/notes) · [Calendar](web-app/calendar) · [Trainings](web-app/trainings)
+
+### Readiness and logistics
+
+- **Checklists** — apparatus, equipment, facility and personal checks with schedules, reminders, witnesses, evidence and compliance reporting. [Checklists](web-app/checklists)
+- **Work orders and preventive maintenance** — repairs, safety holds, meter- and calendar-based schedules, costs and service levels (Readiness Pro). [Work Orders](web-app/work-orders)
+- **Inventory** — bulk and serialized stock, lots and expiry, issuance, kits, counts, alerts, purchasing and controlled-substance witnessing. [Inventory](web-app/inventory)
+- **Resource orders and department links** — mutual aid between departments. [Resource Orders](web-app/resource-orders) · [Department Links](web-app/department-links)
+
+### Automation, security and integration
+
+- **Workflows** — event-driven automation with email, SMS, chat, webhook, API and file actions. [Workflows](web-app/workflows)
+- **Notifications** — readiness alerts on availability, status and inventory. [Notifications](web-app/notifications)
+- **Security** — granular permissions, audit log, 2FA, security policy, SSO/SCIM, and Advanced Data Protection with department-owned encryption keys. [Security & Permissions](web-app/security-permissions) · [Advanced Data Protection](web-app/data-protection) · [Enterprise SSO](enterprise/sso-overview)
+- **API and apps** — a documented REST API and the Responder, Unit, Dispatch, Incident Command, Big Board and Relay apps. [API](api/authentication) · [Apps](apps/responder)
+
+## Who uses it
+
+Fire departments (volunteer, combination, career), EMS agencies, search and rescue teams, emergency management agencies and EOCs, incident management teams, CERT and community response programs, private security and campus security, industrial fire brigades and plant ERTs, delivery, transit and field-service operators, and the dispatch centres that serve several of them. Each has a [setup guide](setup-guides/overview).
+
+## Contributing to the documentation
+
+This documentation is open source at [github.com/Resgrid/docs](https://github.com/Resgrid/docs). If something is missing or wrong, open an issue or a pull request.
diff --git a/docs/reference/feature-flags.md b/docs/reference/feature-flags.md
new file mode 100644
index 0000000..57ecfb2
--- /dev/null
+++ b/docs/reference/feature-flags.md
@@ -0,0 +1,65 @@
+---
+sidebar_position: 8
+title: Feature Flags & Module Gates
+---
+
+# Feature Flags & Module Gates
+
+Some Resgrid modules are behind **feature flags** so they can be rolled out gradually. On the hosted service Resgrid staff switch them on; on a self-hosted installation the operator does it with the tools console. Flags are stored in the database (`FeatureFlags`, `FeatureFlagOverrides`, `FeatureFlagTargetingRules`, `FeatureFlagPrerequisites`), cached, and evaluated per department: a **department override** wins over a **percentage rollout** and **targeting rules**, which win over the **global default**.
+
+## Managing flags (self-hosted)
+
+```bash
+# list flags and what a department resolves to
+dotnet Resgrid.Console.dll --FeatureFlags --DepartmentId=1
+
+# turn a flag on for one department (department override)
+dotnet Resgrid.Console.dll --FeatureFlags --Key=Records.System --DepartmentId=1 --On
+
+# turn a flag on globally (default for every department without an override)
+dotnet Resgrid.Console.dll --FeatureFlags --Key=Checklists.System --On
+
+# remove an override, staged rollout, list keys the code gates on
+dotnet Resgrid.Console.dll --FeatureFlags --Key=Chat.System --DepartmentId=1 --Clear
+dotnet Resgrid.Console.dll --FeatureFlags --Key=Chat.System --Rollout=25
+dotnet Resgrid.Console.dll --FeatureFlags --Keys
+```
+
+Writes go through the feature-toggle service, so caches are invalidated and an audit event is written; web, API and workers pick up the change on their next read. `FeatureFlagsConfig.FeatureFlagsEnabled=false` turns the whole subsystem off (every flag reads as disabled).
+
+## Flags
+
+| Key | Gates | Depends on | Seeded |
+|---|---|---|---|
+| `Chat.System` | Realtime chat, incident channels, Assistant conversation, moderation (web + apps). Free for all plans. | — | M0108 |
+| `Chatbot.TwilioTextIntegration` | Routes inbound SMS through the Assistant pipeline instead of the legacy text commands. | — | — |
+| `Dispatch.RunCards` | Run cards, station-based / closest-unit selection, move-ups, alarm levels. | — | M0116 |
+| `Checklists.System` | Checklists module (free). | — | M0189 (off) |
+| `Maintenance.WorkOrders` | Work orders and preventive maintenance. Also needs the Readiness Pro add-on and the Maintenance module switch. | — | M0189 (off) |
+| `Records.System` | The Records module; replaces Logs in the sidebar. A department must also **activate** Records. | — | M0152 (off) |
+| `Records.Field.Responder` / `.Unit` / `.IncidentCommand` / `.Dispatch` | Field Records surfaces in each app. | `Records.System` | M0152 |
+| `Records.Prevention.Occupancy` | Occupancies and the pre-plan crosswalk. | `Records.System` | M0186 |
+| `Records.Prevention.Inspections` | Inspection programs, code sets, inspections, violations. | `Records.Prevention.Occupancy` | M0186 |
+| `Records.Prevention.Hydrants` | Hydrants and water sources. | `Records.System` | M0186 |
+| `Records.Prevention.Permits` | Permits and plan review. | `Records.Prevention.Occupancy` | M0186 |
+| `Records.Prevention.Crr` | Community risk reduction activities. | `Records.System` | M0186 |
+| `Records.Investigations` | Investigation cases. | `Records.System` | M0186 |
+| `Records.QualityReview` | Quality review rubrics and sampling. | `Records.System` | M0186 |
+| `Records.Analytics` | Records analytics dashboards. | `Records.System` | M0187 |
+| `Security.DepartmentProtectedDataEnrollment` | Platform-wide admission gate for **new** Advanced Data Protection enrollments (operator-managed; never affects departments already enrolled). | — | M0126 |
+
+## Other gates
+
+Besides flags, a page can be hidden by:
+
+| Gate | Where |
+|---|---|
+| **Module switches** (Messaging, Mapping, Shifts, Logs/Records, Reports, Documents, Calendar, Notes, Training, Inventory, Checklists, Maintenance) | Department Settings → Module Settings (`DepartmentModuleSettings`) |
+| **Plan and add-ons** (PTT, ADP, Readiness Pro, Enterprise SSO) | Subscription & Billing; entitlement checked against the billing API (`SubscriptionsService`, `ReadinessAccessService`) |
+| **Permissions** | Security & Permissions |
+| **Records activation** | Records → Activate (`RmsDepartmentCutover`) |
+| **Installation config** | e.g. NERIS submission switched off system-wide, external connectors off, tracker gateway disabled |
+
+## Environments
+
+A flag can be restricted to an environment (`SystemBehaviorConfig.Environment`: Dev, QA, Staging, Production); a flag pinned to another environment evaluates as its off value.
diff --git a/docs/reference/overview.md b/docs/reference/overview.md
index 53e1985..055eace 100644
--- a/docs/reference/overview.md
+++ b/docs/reference/overview.md
@@ -22,16 +22,20 @@ Resgrid has many components that interact with each other at a high level.
Resgrid is split into many discrete components. These can then be installed on one or many systems depending on your load or uptime requirements.
-- **Web Core**: The primary web application
-- **Web Services**: The backend API
-- **Web Events**:SignalR web socket application for real-time updating of UI's
-- **Worker Console**: CLI application that runs scheduled tasks and processes backend real-time events
-- **Tools Console**: CLI application that admins can run to update the database version or run other commands
-- **Microsoft SQL Server**: Primary relational database (3rd Party)
-- **MongoDB**: Document database for storing real-time GPS events for Units and User and Audit events (3rd Party)
-- **Redis**: In Memory Caching Service (3rd Party)
-- **RabbitMQ**: Message Queuing and Distribution Service, used to keep the distributed system components in sync (3rd Party)
-- **ElasticSearch**: ELK server for system logging output (3rd Party)
+- **Web Core** (`Resgrid.Web`): the primary web application; also hosts the same-origin **BFF** proxy (`/api/web-bff/*`) that the React surfaces (chat, map, assistant, moderation) use to reach the API with short-lived tokens
+- **Web Services** (`Resgrid.Web.Services`): the backend REST API (`api/v4`) used by the mobile apps, integrations and the BFF
+- **Web Events** (`Resgrid.Web.Eventing`): SignalR web-socket application for real-time updating of UIs and chat
+- **Web MCP** (`Resgrid.Web.Mcp`): Model Context Protocol endpoint for AI assistants
+- **Web TTS** (`Resgrid.Web.Tts`): text-to-speech service for voice dispatch prompts (persistent Piper worker pool)
+- **Tracker Gateway** (`Resgrid.TrackerGateway`): optional TCP/UDP listener process for hardware GPS trackers (Teltonika Codec 8 …); HTTPS trackers post to the API directly
+- **Worker Console** (`Resgrid.Workers.Console`): runs scheduled tasks and queue consumers — call broadcast, notifications, workflows, chatbot, NERIS submission, retention purge, ADP migration, checklists/work-order schedules, search indexing
+- **Tools Console** (`Resgrid.Console`): CLI for database updates (`--DbUpdate`), feature flags (`--FeatureFlags`), cache clearing, password resets, OIDC certificates and other administration
+- **Microsoft SQL Server or PostgreSQL**: primary relational database (3rd party). RMS queries require SQL Server compatibility level 130 or higher
+- **MongoDB**: document database for real-time GPS events and audit events (3rd party; optional in newer deployments)
+- **Redis**: in-memory cache and session store (3rd party)
+- **RabbitMQ** (or Azure Service Bus): message queuing between components (3rd party). Chat and incident-command realtime relay require the RabbitMQ topic
+- **Object scanning, key service, LLM, mapping, SMS, email, push and billing providers**: pluggable external services configured in `ResgridConfig.json` / `RESGRID__*` environment variables
+- **ElasticSearch / Sentry**: optional logging and error reporting (3rd party)
Not mentioned here as this is 100% user choice but for any Highly Available (HA) configuration you need to have multiple __Web Core__, __Web Services__ and __Web Events__ servers setup in a load balanced configuration. That allows the system to respond either via the Web App or API to user interactions even if one of the boxes is having issues.
diff --git a/docs/self-hosted/installation.md b/docs/self-hosted/installation.md
index c12e69a..957f212 100644
--- a/docs/self-hosted/installation.md
+++ b/docs/self-hosted/installation.md
@@ -2,130 +2,150 @@
sidebar_position: 2
---
-# Installation
+# Self-hosted installation
-The overall installation of Resgrid is tailored to your specific usage scenarios and will require first procuring the required numbers of servers or VM's and continuing the installation process. If your department will have 50 or less users and units utilizing it at one time, we recommend using the Quick Start.
+Resgrid Core has four maintained deployment layouts in the [resgrid-setup repository](https://github.com/Resgrid/resgrid-setup). Choose the layout that matches the environment; the branches are intentionally different and are not interchangeable.
-:::danger Warranty
-Resgrid's self hosted version is provided with no warranty, no guarantee of suitability and limited free support (Github Issues and Discussions only).
-Updates for our self hosted version are infrequent compared to our hosted version due to the additional cost in time to create those releases. We try
-our best to ensure an easy and working system that doesn't require a lot of tweaking, but due to it's complexity that is difficult.
-:::
+| Branch | Use case | Orchestrator | Hosts |
+|---|---|---|---|
+| `master` | General self-hosted evaluation or small single-server install | Docker Compose | One 64-bit Linux server (Windows/macOS through WSL2 is also supported) |
+| `laptop` | Local Windows development, training, or single-computer field use | Docker Desktop Compose | One Windows 10/11 computer |
+| `rick` | Portable Resgrid Incident Command Kit | Compose split into database, infrastructure, and application roles | Three 64-bit Raspberry Pi-class nodes; current app images use AMD64 emulation on the web Pi |
+| `multi` | Kubernetes or k3s | Kustomize (`kubectl apply -k`) | A cluster with persistent storage, ingress, and at least one AMD64 worker |
-## Prerequisites
+See [Windows laptop](./laptop), [RICK](./rick), or [Kubernetes/k3s](./multi) for those specialized layouts. The rest of this page covers `master`.
-Resgrid's recommended install is on Ubuntu 24.04 with Docker to meet the Small sizing install requirements you will need a minimum of 5 servers:
+:::danger Warranty and operational responsibility
+The self-hosted version is provided without warranty or a guarantee of suitability. The supplied manifests are a starting point, not a substitute for capacity planning, security review, monitoring, tested backups, or a disaster-recovery plan. Do not use template credentials in a real deployment.
+:::
- - 1 Web Server
- - 1 Api Server
- - 1 Event Hub Server
- - 1 Server for MS SQL, Mongodb
- - 1 Server for Rabbit, Redis & Resgrid Worker Container
+## What the single-server stack runs
-For contrast a mission-critical production environment will require a minimum of 18 servers (or vm's).
+The current stack includes the web application, API, events hub, background worker and database migrations, text-to-speech service, MCP server, PostgreSQL, Redis, RabbitMQ, RustFS object storage, and Caddy ingress. Hardware GPS tracking and inbound-email dispatch are optional Compose profiles.
-- 2 Load Balanced Web servers
-- 2 Load Balanced API servers
-- 2 Load Balanced Event Hub servers
-- 1 Microsoft SQL Server (HA Cluster for Mission Critical applications)
-- 1 Worker server
-- 2 Event Worker servers
-- 3 Redis servers in a cluster
-- 3 RabbitMQ servers in a cluster
-- 1 Elasticsearch server (ELK)
-- 1 MongoDb server (HA Cluster for Mission Critical applications)
-- An Ingress Load-Balancer
+MongoDB and Microsoft SQL Server are no longer part of the standard stack. The main, OIDC, worker, and document databases all use PostgreSQL.
+## Requirements
- :::tip Note
-Some services installed as part of this process; MSSQL, RabbitMQ, Redis and MongoDb are configured as single instances. This is not the ideal configuration if you are trying to get a high availability system. All of those services can be setup in HA configurations, but it is outside of the scope of this guide.
-:::
+- A 64-bit Linux server. Ubuntu Server 24.04 LTS is a practical baseline.
+- Docker Engine and Docker Compose v2.
+- OpenSSL, Git or curl, and outbound registry access during installation.
+- At least 4 CPU cores, 16 GB RAM, and 40 GB storage for evaluation. Size production systems from measured workload and retention needs.
+- Three hostnames that resolve to the server: web, API, and events.
+- TCP 80/443 to the server or an upstream load balancer/reverse proxy.
+- An SMTP or Postmark account if the installation must send email.
-- Open Ports 80 and 443 and pass to the server (or utilize your firewall/load balancer or proxy server)
-- SMTP Server for sending email
-- 3 Urls provisioned (externally available, internal DNS, etc)
- - Main Web App (i.e. rg.mycompany.com)
- - API (i.e. rgapi.mycompany.com)
- - Events (i.e. rgevents.mycompany.com)
+The stack uses Docker Hardened Images from `dhi.io`. If a pull reports an authorization error, authenticate with a Docker account entitled to those images before continuing:
-## Dependency Setup
+```bash
+docker login dhi.io
+```
-You will need to get the required dependencies servers setup and online. You can utilize Docker versions, bare metal installs or even cloud hosted versions of these services for your installation.
+## Automated install
-### Microsoft SQL Server
+With Docker running:
-Install and configure Microsoft SQL Server 2022 on the server of your choice or if you are on a Cloud provider use their MS-SQL implementation. You will need to create 3 databases and 3 accounts. Use server defaults for collation.
+```bash
+curl -fsSL https://raw.githubusercontent.com/Resgrid/resgrid-setup/master/setup.sh | bash
+```
- - **Resgrid** database and user with DB Owner for that database
- - **ResgridWorkers** database and user with DB Owner for that database
- - **ResgridOIDC** database and user with DB Owner for that database
+The installer downloads the `master` branch, asks for the three hostnames and TLS mode, creates unique infrastructure/application secrets, generates new OpenIddict signing and encryption certificates, writes `.env`, and starts the stack.
-### MongoDb
+For a LAN-only evaluation, accept the defaults (`rg.mylocal`, `rgapi.mylocal`, `rgevents.mylocal`, and `internal`). Add all three names to every client's hosts file, pointing at the server address:
-Install and configure MongoDb on the server of your choice or if you are on a Cloud provider use their Mongo implementation. You will need to create 1 databases and 1 login.
+```text
+192.168.1.50 rg.mylocal rgapi.mylocal rgevents.mylocal
+```
- - **resgrid** database and user credentials for that db
+For an internet-reachable install, use real DNS records and provide an email address so Caddy can request certificates. Ports 80 and 443 must reach Caddy.
-### Redis
+Non-interactive example:
-Install and configure Redis on the server of your choice or if you are on a Cloud provider use their Redis implementation.
+```bash
+RESGRID_WEB_URL=dispatch.example.com \
+RESGRID_API_URL=dispatchapi.example.com \
+RESGRID_EVENTS_URL=dispatchevents.example.com \
+RESGRID_LETSENCRYPT_EMAIL=admin@example.com \
+bash setup.sh
+```
+Set `RESGRID_NO_START=1` to generate configuration without pulling or starting containers.
-### RabbitMQ
+## First-start verification
-Install and configure RabbitMQ on the server of your choice or if you are on a Cloud provider use their RabbitMQ implementation. You will need to create a login for rabbit that allows the creation of exchanges, topics and queues.
+The worker creates and migrates four databases. First start may take several minutes:
+```bash
+cd ~/resgrid
+docker compose ps
+docker compose logs -f worker
+```
-### Proxy
+For an internal certificate, open and accept the certificate for the web, API, and events hostnames. The web client cannot log in if the API/events certificates are still rejected by the browser.
-Resgrid requires SSL and our containers are built with SSL Termination/Offloading in mind. You will need to setup a Proxy server that supports SSL Termination/Offloading to forward traffic to the 3 web accessible Resgrid containers. We use Caddy v2 in our system but you can use any proxy that supports the features (NGINX, HAProxy, Trafik, etc).
+When migrations settle, open the web hostname and use **Sign Up** to create the first account and department. Current releases do not use a shared default administrator login.
-### Mail Server
+Useful endpoints with the template ports:
-Resgrid sends out emails to users to inform them of events and correspondence. Have a dedicated (DO-NOT-RESPOND) style email and login to allow Resgrid to send emails.
+| Purpose | Endpoint |
+|---|---|
+| Web through Caddy | `https://rg.mylocal` |
+| API health | `https://rgapi.mylocal/api/health/getcurrent` |
+| Web direct diagnostic port | `http://SERVER:5151` |
+| API direct diagnostic port | `http://SERVER:5152` |
+| Events direct diagnostic port | `http://SERVER:5153` |
+| RabbitMQ management | `http://SERVER:5160` |
-### Sentry
+MCP's HTTP transport is unauthenticated and published on port 5155 for LAN use. Do not expose it directly to the internet.
-This step is optional but we recommending using the https://sentry.io cloud service or their open-source on-prem version https://develop.sentry.dev/self-hosted/. This would replace Elk for all logging, error and session tracking.
+## Optional services
-You should now have your Proxy setup for handling SSL traffic, a Microsoft SQL Server setup with 3 databases and 3 db owner logins, MongoDb setup with 1 database and 1 login, Redis and RabbitMQ with a login that can create exchanges, topics and queues. Now you can work on setting up the Resgrid containers.
+After configuring `RESGRID__UnitTrackingConfig__*` in `.env`:
-## Resgrid Container Setup
+```bash
+docker compose --profile tracking up -d
+```
-You will need a good text editor, Notepad++ on Windows or Nano if your doing this from the Linux CLI.
+The profile opens the Queclink, GT06, and Teltonika TCP/UDP ports. Restrict them to expected tracker source networks.
-1. Clone the setup scripts for the multi install:
+After configuring the relay's department and mail-domain settings:
```bash
-git clone --branch multi https://github.com/Resgrid/resgrid-setup.git resgrid
+docker compose --profile relay up -d
```
-You should now have a folder called resgrid in your current directory.
+The relay opens SMTP port 25 and has no SMTP authentication or TLS. Put a filtering MTA or firewall in front of it.
-2. Open the resgrid directory:
+## Operations
```bash
-cd resgrid
+docker compose ps
+docker compose logs -f SERVICE
+docker compose down
+docker compose pull
+docker compose up -d
```
-3. Docker Hub Authentication
+An upgrade is `pull` followed by `up -d`; do not delete every Docker image on the host. The worker applies database migrations during startup.
-Resgrid container images are hosted on Docker Hub under the `dhi.io` repository. You will need a Docker Hub account (free) to pull the images. If you don't have one, create a free account at [https://hub.docker.com](https://hub.docker.com).
+## Backup and rollback
-Once you have an account, log in from your terminal before running the containers:
+Back up `.env` and keep it encrypted. It contains keys required to decrypt existing data/tokens and to validate OIDC credentials. Take a consistent PostgreSQL dump rather than copying the live database directory:
```bash
-docker login dhi.io
+docker compose exec -T db pg_dumpall -U resgrid > "resgrid-$(date +%F).sql"
```
-Enter your Docker Hub username and password when prompted.
-
-You will need to clone this repo into all the servers running the Resgrid containers. But we are going to edit the .env file here and it'll need to be copied to every server running the Resgrid containers, this keeps the Resgrid settings consistent for every server.
+Also back up RustFS and Caddy data according to your storage and certificate requirements.
+Before upgrading, retain the previous image digests and a pre-upgrade database dump. Rolling application containers back does not reverse schema migrations. If an older release is incompatible with the migrated schema, restore the database backup and matching `.env` before starting the older images.
-Edit the environment file with Nano (or if you cloned in a Desktop environment with your text editor of choice):
+## Configuration reference
-```bash
-nano .env
-```
+Container settings use double-underscore environment names such as `RESGRID__DataConfig__DatabaseType`. See [Docker configuration](../reference/docker) for the complete reference. Common pitfalls:
+- Enum values are numeric.
+- `CoreConnectionString` is required and normally matches `ConnectionString`.
+- `DocDatabaseType=1` selects PostgreSQL.
+- `DODBUPGRADE=true` belongs on the worker.
+- Some historical field names intentionally contain spelling errors, including `RabbbitPassword` and `ExternalAudioUrlParamPasshprase`; match them exactly.
diff --git a/docs/self-hosted/laptop.md b/docs/self-hosted/laptop.md
index 4fb3c4a..e9f401d 100644
--- a/docs/self-hosted/laptop.md
+++ b/docs/self-hosted/laptop.md
@@ -2,147 +2,137 @@
sidebar_position: 3
---
-# Offline Laptop
+# Windows laptop or desktop
-In this guide we will get Resgrid up in running via Docker Compose for local (single user) use on a Windows computer.
+The `laptop` branch runs the current Resgrid Core stack on one Windows computer with Docker Desktop. Use it for local development, evaluation, training, or a single-computer field deployment. It is not a redundant or multi-user production architecture.
-:::danger Warranty
-Resgrid's self hosted version is provided with no warranty, no guarantee of suitability and limited free support (Github Issues and Discussions only).
-Updates for our self hosted version are infrequent compared to our hosted version due to the additional cost in time to create those releases. We try
-our best to ensure an easy and working system that doesn't require a lot of tweaking, but due to it's complexity that is difficult.
-:::
+Default published ports bind to `127.0.0.1`, so other computers cannot connect unless you intentionally change the Compose bindings and Windows firewall rules.
-## Use Case
+## Requirements
-This setup is intended to get Resgrid up and running on a single-user environment, like a laptop that will not be connected to or have internet access. No external users (i.e. from another machine or mobile device) will be connecting to this installation. For example you are coordinate rescue and recovery efforts for a hurricane from a location on your laptop, you are communicate with your field teams only via a radio as there is no power or cell phone data/WiFi Internet.
+- 64-bit Windows 10 or Windows 11 with virtualization enabled.
+- Docker Desktop using Linux containers and the WSL2 backend.
+- PowerShell 7 or Windows PowerShell 5.1.
+- Git for Windows.
+- At least 4 CPU cores, 16 GB RAM, and 20 GB free storage.
+- Administrator access once to edit the Windows hosts file.
-## System Requirements
+For a field computer, use encrypted storage and keep backups on separate encrypted removable media. There is no automatic failover if the computer or its storage is damaged.
-1.) Windows 10 or Windows 11 Laptop with WSL2 (Windows Subsystem for Linux)
-2.) Docker Desktop with WSL2 Enabled
-3.) Enough HDD Space to handle Mapping Data (if you want a large region like North America you'll need 30+ GB)
-4.) 4 or more Core Processor
-5.) 16GB or more of RAM
+## Install from PowerShell
-## Setup Notice
+Start Docker Desktop, then open PowerShell:
-There is no redundancy, backup or fail-over in this setup. Everything runs on the local computer and is not intended to be accessed by anyone off of the local computer. If the local computer gets damaged this could result in loss of data. It's recommend that you have a USB drive that you can backup the database to (ideally the whole resgrid directory) periodically during the operation.
-
-## Prerequisites & Dependencies
-
-1. Update Windows
-2. Install WSL2 and Ubuntu 22.04
-3. Open up your Ubuntu 22.04 instance and finalize the setup (set password).
-4. Install Docker and enable WSL2 backend.
+```powershell
+git clone --branch laptop https://github.com/Resgrid/resgrid-setup.git resgrid
+Set-Location .\resgrid
+Set-ExecutionPolicy -Scope Process Bypass
+.\setup.ps1
+```
-## Docker Compose Setup
+`setup.ps1` checks Docker Desktop, generates unique infrastructure passwords and Resgrid encryption keys, creates new OpenIddict certificates with .NET, writes `.env`, creates data directories, and starts Compose.
-1. Open Notepad as Administrator and open C:\Windows\System32\drivers\etc\hosts file.
+To configure without pulling or starting images:
-2. Add the following lines to the hosts file and save.
+```powershell
+.\setup.ps1 -NoStart
```
-127.0.0.1 rg.mylocal
-127.0.0.1 rgapi.mylocal
-127.0.0.1 rgevents.mylocal
-127.0.0.1 rgtile.mylocal
-```
-
-If you get a permissions error you didn't open up Notepad as Administrator, also don't use any RichText editor (Wordpad, Word, etc).
-3. Navigate to Geofabrik and download the .osm.pbf file the region you will be operating in.
+Custom local hostnames:
-It is not recommend to try and pull an entire Sub Region (i.e. North America) as that will take quite a long time to import into the database. Instead it's recommended to import and additional Sub (Sub) Region, like a US State (i.e. Florida) or a Special Sub Region if they are available (i.e. US South).
+```powershell
+.\setup.ps1 `
+ -WebHost dispatch.mylocal `
+ -ApiHost dispatchapi.mylocal `
+ -EventsHost dispatchevents.mylocal
+```
-4. Using the Windows File Explorer move the osm.pbf file into Linux (left side bar) Ubuntu-22.04, home and your username folder. This will put it in your home directory.
+If you prefer WSL2, run `bash setup.sh` from the checkout; the script defaults to downloading the `laptop` branch.
-5. Start your Ubuntu-22.04 WSL2 Instance so the command prompt is visible.
+## Configure local name resolution
-6. Clone the setup scripts for the Laptop compose:
+Open Notepad as Administrator and edit:
-```bash
-git clone https://github.com/Resgrid/resgrid-setup.git -b laptop resgrid
+```text
+C:\Windows\System32\drivers\etc\hosts
```
-You should now have a folder called resgrid in your current directory.
-
-7. Open the resgrid directory:
+Add the line printed by setup. With default names:
-```bash
-cd resgrid
+```text
+127.0.0.1 rg.mylocal rgapi.mylocal rgevents.mylocal
```
-8. Docker Hub Authentication
+Open these URLs and accept Caddy's internal certificate for each hostname:
-Resgrid container images are hosted on Docker Hub under the `dhi.io` repository. You will need a Docker Hub account (free) to pull the images. If you don't have one, create a free account at [https://hub.docker.com](https://hub.docker.com).
+- `https://rg.mylocal`
+- `https://rgapi.mylocal/api/health/getcurrent`
+- `https://rgevents.mylocal`
-Once you have an account, log in from your terminal before running the containers:
+The web client cannot use the API until the API certificate is accepted or Caddy's local root certificate is installed in Windows Trusted Root Certification Authorities.
-```bash
-docker login dhi.io
-```
+## Verify first start
-Enter your Docker Hub username and password when prompted.
+The worker creates and migrates the main, OIDC, worker, and document PostgreSQL databases:
-9. Import the osm.pbf you downloaded and placed in your home directory into the tile server. Change /home/yourname/yourregion.osm.pbf in the command below to the correct home directory name (yourname) and the name of the region file you downloaded (yourregion).
-
-```bash
-docker run \
- -v /home/yourname/yourregion.osm.pbf:/data/region.osm.pbf \
- -v ./docker-data/osm:/data/database/ \
- overv/openstreetmap-tile-server \
- import
+```powershell
+docker compose ps
+docker compose logs -f worker
```
-If the container exits without errors, then your data has been successfully imported and you are now ready to run the tile server. If you selected a very large region, like North America this process can take days.
-
+When migrations settle, open `https://rg.mylocal` and use **Sign Up**. There is no shared default administrator login.
-## Run the Docker Compose
+Local diagnostic ports are:
-Once you have setup the environment variables you can now run the docker compose file in the resgrid directory:
+| Service | Address |
+|---|---|
+| Web | `http://127.0.0.1:5151` |
+| API | `http://127.0.0.1:5152` |
+| Events | `http://127.0.0.1:5153` |
+| TTS | `http://127.0.0.1:5154` |
+| MCP | `http://127.0.0.1:5155/mcp` |
+| RabbitMQ management | `http://127.0.0.1:5160` |
-```bash
-docker compose up
-```
+MCP's transport endpoint is unauthenticated; the loopback binding is intentional.
-That will run the interactive version of the containers, Ctrl+C will stop the containers.
+## Optional services
-If you want to run the containers in the background, use the -d option:
+Tracker gateway:
-```bash
-docker compose up -d
+```powershell
+docker compose --profile tracking up -d
```
-The Resgrid system will take about 5 minutes to start up fully, this is due to the startup order of the containers. The last container to startup will be the web container, once that one is ready, you can now access the system.
-
-
-## Initial Web Login
-
-Open up your web browser and navigate to **https://rg.mylocal**, **https://rgapi.mylocal**, **https://rgevents.mylocal** and **https://rgtile.mylocal**. You will need to accept the self-signed cert for each url and add exceptions in the browsers. You can follow this guide to add those exceptions.
+Configure `RESGRID__UnitTrackingConfig__*` first. Tracker ports listen on network interfaces so physical devices can connect; review Windows firewall rules.
-Once you have completed the steps above you will be able to log into the web applications user interface. Open up a web browser and navigate to **https://rg.mylocal**, you will then be prompted by the login screen. Your default administrator credentials are **admin/changeme1234**. Once you log into the system it’s recommended that you change your admin password from the Edit Profile page by clicking on the Administrator name in the upper left hand corner.
+Inbound-email relay:
-## Updating
+```powershell
+docker compose --profile relay up -d
+```
-To update Resgrid you'll need to stop the system, clear the current containers and restart.
+Configure the relay department and mail domains first. The SMTP listener has no authentication or TLS and opens port 25.
-Stop all running containers.
+## Update
-```bash
-docker compose down
+```powershell
+docker compose pull
+docker compose up -d
+docker compose logs -f worker
```
-Remove all cached images (to ensure we get new ones).
+Do not remove every Docker image; that affects unrelated local projects and is unnecessary.
-```bash
-docker rmi -f $(docker images -aq)
-```
+## Backup and rollback
-Restart the containers and they will pull new containers.
+Back up `.env` and the `docker-data` directory to separate encrypted storage. `.env` contains encryption and OIDC material required by existing data. Create a consistent database dump:
-```bash
-docker compose up -d
+```powershell
+docker compose exec -T db pg_dumpall -U resgrid | Out-File -Encoding utf8 .\resgrid-backup.sql
```
-## What's Next?
+Before upgrading, record the current image digests and keep the pre-upgrade dump. Rolling back containers alone may be unsafe after worker schema migrations; restore the compatible database dump and matching `.env` before starting older images.
+
+## Mapping and offline use
-This Quick Start gets the system running via local host, but not externally or within your network. You will need to create DNS entries in your internal or external DNS server to point to the server that is running the containers. It's also recommend you change some default values in the resgrid.env file to ensure proper security.
\ No newline at end of file
+The default Leaflet setting uses the public OpenStreetMap tile service for initial testing only. It is not an offline map and is not intended for bulk or operational use. Configure an approved map provider or a separately prepared local tile service before deploying the laptop without internet access.
diff --git a/docs/self-hosted/multi.md b/docs/self-hosted/multi.md
new file mode 100644
index 0000000..b0ead7c
--- /dev/null
+++ b/docs/self-hosted/multi.md
@@ -0,0 +1,159 @@
+---
+sidebar_position: 5
+---
+
+# Kubernetes and k3s
+
+The `multi` branch deploys current Resgrid Core services with Kustomize through `kubectl apply -k`. It does not require Helm.
+
+The base creates:
+
+- Web, API, events, worker/migrations, TTS, and MCP Deployments.
+- PostgreSQL, Redis, RabbitMQ, and RustFS single-replica StatefulSets with persistent volume claims.
+- A RustFS bucket initialization Job.
+- A standard Kubernetes Ingress for the web, API/TTS, and events hostnames.
+- A generated Secret containing the complete Resgrid environment.
+
+Optional manifests add tracker-gateway and inbound-email relay workloads.
+
+:::warning Availability
+The included StatefulSets are single replicas and are not an HA data tier. For production, use managed/clustered dependencies, image digests, resource policies, monitoring, network policies, and storage-provider backups appropriate to the workload.
+:::
+
+## Architecture requirement
+
+Current Resgrid application images are published for `linux/amd64` only. Application Deployments select nodes labeled `kubernetes.io/arch=amd64`. Infrastructure can run on supported ARM64 nodes, so a mixed cluster works, but a pure Raspberry Pi/ARM64 k3s cluster cannot run the application pods natively today.
+
+`setup.sh` refuses to apply when the cluster has no registered AMD64 node. Do not remove the node selector unless you publish and validate native ARM64 images or deliberately provide a supported emulation runtime.
+
+## Requirements
+
+- Kubernetes 1.27+ or a current k3s release.
+- At least one AMD64 worker.
+- A default `ReadWriteOnce` StorageClass (`local-path` is the k3s default).
+- An IngressClass (`traefik` is the k3s default).
+- `kubectl`, OpenSSL, and a configured kube context.
+- Three DNS names pointing to the ingress address.
+- Registry credentials if `dhi.io` requires authentication for your environment.
+
+Verify before installing:
+
+```bash
+kubectl config current-context
+kubectl get nodes -L kubernetes.io/arch
+kubectl get storageclass
+kubectl get ingressclass
+```
+
+## Configure and apply
+
+```bash
+git clone --branch multi https://github.com/Resgrid/resgrid-setup.git resgrid-k8s
+cd resgrid-k8s
+chmod +x setup.sh
+./setup.sh
+```
+
+Setup asks for the three hostnames, IngressClass, and pod CIDR. It generates infrastructure credentials, Resgrid keys, OpenIddict certificates, ingress TLS files, and ignored host-specific inputs under `deploy/generated`. It displays the active kube context and requires confirmation before applying.
+
+Generate without changing the cluster:
+
+```bash
+RESGRID_NO_APPLY=1 ./setup.sh
+kubectl kustomize deploy >/dev/null
+```
+
+Non-interactive install using an existing TLS certificate:
+
+```bash
+RESGRID_WEB_URL=dispatch.example.com \
+RESGRID_API_URL=dispatchapi.example.com \
+RESGRID_EVENTS_URL=dispatchevents.example.com \
+RESGRID_INGRESS_CLASS=nginx \
+RESGRID_POD_CIDR=10.244.0.0/16 \
+RESGRID_TLS_CERT_FILE=/secure/fullchain.pem \
+RESGRID_TLS_KEY_FILE=/secure/privkey.pem \
+RESGRID_APPLY=1 \
+./setup.sh
+```
+
+Without supplied TLS files, setup generates a self-signed certificate containing all three hostnames. Distribute/trust `deploy/generated/tls.crt` on clients.
+
+The pod CIDR configures which ingress-to-pod forwarded headers Resgrid trusts. k3s commonly uses `10.42.0.0/16`; inspect your CNI and supply its actual network for other distributions.
+
+## Registry login
+
+If image pulls from `dhi.io` require authentication:
+
+```bash
+kubectl -n resgrid create secret docker-registry dhi-registry \
+ --docker-server=dhi.io \
+ --docker-username='YOUR_USER' \
+ --docker-password='YOUR_TOKEN'
+kubectl -n resgrid patch serviceaccount default \
+ -p '{"imagePullSecrets":[{"name":"dhi-registry"}]}'
+```
+
+Use a service/robot token and keep it out of Git.
+
+## Verify first start
+
+```bash
+kubectl -n resgrid get pods -w
+kubectl -n resgrid logs -f deployment/worker
+kubectl -n resgrid get ingress
+kubectl -n resgrid get pvc
+```
+
+The worker creates/migrates the main, OIDC, worker, and document PostgreSQL databases. After migrations settle, open the web hostname and use **Sign Up**.
+
+## Optional services
+
+Tracker gateway: update `RESGRID__UnitTrackingConfig__*` in `deploy/generated/resgrid.env`, re-apply the generated Secret/base, then create its workload:
+
+```bash
+kubectl apply -k deploy
+kubectl apply -f deploy/optional/tracking.yaml
+kubectl -n resgrid get service tracker-gateway
+```
+
+The LoadBalancer Service publishes tracker TCP/UDP ports. k3s ServiceLB and cloud providers advertise them differently; verify the assigned address and firewall exposure.
+
+Email relay: update its department/domain settings, re-apply, then:
+
+```bash
+kubectl apply -k deploy
+kubectl apply -f deploy/optional/relay.yaml
+kubectl -n resgrid get service relay
+```
+
+The relay publishes SMTP port 25 without SMTP authentication or TLS. Place it behind a filtering MTA or strict firewall.
+
+## Scaling and customization
+
+Scale stateless services after validating dependency capacity:
+
+```bash
+kubectl -n resgrid scale deployment/web deployment/api deployment/events --replicas=2
+```
+
+Use a Kustomize overlay for image digests, storage sizes/classes, resources, topology constraints, probes, or external data services. Keep generated secrets out of overlays and Git.
+
+MCP is a ClusterIP-only Service because its HTTP transport is unauthenticated. Add an authenticated ingress only if your security design explicitly protects it.
+
+## Backup and rollback
+
+Create a PostgreSQL dump:
+
+```bash
+kubectl -n resgrid exec statefulset/postgres -- \
+ pg_dumpall -U resgrid > "resgrid-$(date +%F).sql"
+```
+
+Back up `deploy/generated/resgrid.env`, ingress TLS material, and RustFS/PostgreSQL PVCs using your storage provider's consistent snapshot/backup system.
+
+Before upgrading, record image digests and render the candidate with `kubectl kustomize deploy`. Apply with `kubectl apply -k deploy`, then follow worker migrations and rollouts.
+
+Application rollback does not reverse database migrations. Retain previous manifests/digests plus a compatible pre-upgrade database backup. Restore data and the matching generated Secret before reapplying older workloads when schema compatibility requires it.
+
+`kubectl delete -k deploy` removes the namespace workloads and generated resources; StatefulSet/PVC retention behavior varies. Inventory and back up PVCs before any uninstall.
diff --git a/docs/self-hosted/quick-start.md b/docs/self-hosted/quick-start.md
index 00181a9..720552b 100644
--- a/docs/self-hosted/quick-start.md
+++ b/docs/self-hosted/quick-start.md
@@ -2,215 +2,89 @@
sidebar_position: 1
---
-# Quick Start
+# Quick start
-In this quick start we will get Resgrid up in running via Docker Compose for testing and evaluation. This quick start is valuable for getting the system up and running quickly for evaluation or testing purposed, but is not the recommended setup for production use.
+This quick start runs the current Resgrid Core stack on one 64-bit Linux server for evaluation or a small self-hosted environment. For Windows, Raspberry Pi RICK, and Kubernetes/k3s layouts, start with the [deployment comparison](./installation).
-:::danger Warranty
-Resgrid's self hosted version is provided with no warranty, no guarantee of suitability and limited free support (Github Issues and Discussions only).
-Updates for our self hosted version are infrequent compared to our hosted version due to the additional cost in time to create those releases. We try
-our best to ensure an easy and working system that doesn't require a lot of tweaking, but due to it's complexity that is difficult.
+:::danger Evaluation is not production readiness
+The stack has single instances of its database, cache, message bus, and object store. Production use requires security review, monitoring, capacity planning, tested backups, and a recovery plan. Never deploy the committed template credentials.
:::
-## Prerequisites
+## 1. Prepare the host
-1.) Server or VM that meets the System Requirements below
-2.) Internet Access (to and from the Server or VM)
-3.) 3 Sub-Domains for the system:
- a.) Sub-Domain for Main Web App (Resgrid)
- b.) Sub-Domain for API (Resgrid API)
- c.) Sub-Domain for Event Hub (Resgrid Events)
-4.) Valid Email Address for LetsEncrypt
-
-## Requirements Notice
-
-It is highly recommended that Resgrid is installed and setup by an IT Professional. There is a large amount of system configuration, tweaking and setup that is required to be done before and after you install Resgrid. Below is a list of technologies that you should have skilled professionals available to you or requisite knowledge before installing. Resgrid does not provide support or configuration guidance for those systems outside of the minimum needed to get the system functional.
-
-- Linux Server (Ubuntu)
-- Docker, Kubernetes
-- MS SQL Server
-- DNS, hostname mapping, proxy configuration
-- RabbitMQ
-- Redis
-- Elastic
-- MongoDb
-- Mail Server SMTP, POP3
-- Firewall and system hardening
-
-## System Requirements
-
-The quick-start installation is suitable for a department of around 50 personnel on a machine with 32GB of RAM, 500GB of storage and a 8 logical processors. But depending on call volume or user interaction patterns may require more. You can run Resgrid on a lower-spec machine but it's not recommended.
-
-We do not recommend that mission critical systems be installed on a single machine. Resgrid is split into multiple containers to allow for multiple machines to be used to ensure the system is resilient to failure of one of it's components. Each dependency also needs to be resilient in that case, for example Clustered SQL Servers, RabbitMQ, Redis, etc.
-
-## Prerequisites & Dependencies
-
-To run the Resgrid containers you will Docker, install Docker . You will also need Docker Compose, Install Docker Compose , the guide below will assume the docker-compose executable is installed.
-
-:::tip Note
-The guide below assumes a Linux server. We test our containers on Ubuntu 24.04 as part of our normal releases. But other Linux distros that support docker should work just fine. You may have to translate some commands, or some options may not apply. We do not provide assistance for any OS that isn't the one above.
-:::
-
-- Open Ports 80 and 443 and pass to the server (if you want it to be externally accessible)
-- SMTP Server for sending email
-- 3 Publicly Available URLs (if you want valid, non self-signed certs)
- - Main Web App (i.e. rg.mycompany.com)
- - API (i.e. rgapi.mycompany.com)
- - Events (i.e. rgevents.mycompany.com)
-
-:::tip Note
-Any correctly configured SMTP server will work if it’s local or not. If you have an SMTP server provided by your ISP or provider that will also work.
-:::
-
-Install Docker-CE on Ubuntu 24.04
-https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository
-
-Allow running of docker for non-root users
-https://docs.docker.com/engine/install/linux-postinstall/
-
-Install Docker Compose on Ubuntu 24.04
-https://docs.docker.com/compose/install/linux/
-
-:::tip Note
-We recommend using Docker (or Docker-CE) as the container system as it's what we use in production. Other container engines should work, but we are unable to verify if there are any issues with them. If you run into issues please try using Docker (or Docker-CE) and ensure your using the correct version of Ubuntu before submitting a support request.
-:::
-
-## Docker Compose Setup
-
-Download and Extract Package
-
-Clone the setup scripts for the all-in-one QuickStart:
+Install Docker Engine, Docker Compose v2, OpenSSL, and curl on a 64-bit Linux server. Ubuntu Server 24.04 LTS is a practical baseline. Start Docker and verify:
```bash
-git clone https://github.com/Resgrid/resgrid-setup.git resgrid
+docker info
+docker compose version
+openssl version
```
-You should now have a folder called resgrid in your current directory.
-
-Open the resgrid directory:
+Plan three hostnames that all resolve to the server:
-```bash
-cd resgrid
-```
+- Web, for example `dispatch.example.com`
+- API, for example `dispatchapi.example.com`
+- Events, for example `dispatchevents.example.com`
-## Docker Hub Authentication
+For an internet deployment, forward TCP 80/443 and create real DNS records. For a LAN-only test, the installer defaults to `.mylocal` names and Caddy's internal certificate.
-Resgrid container images are hosted on Docker Hub under the `dhi.io` repository. You will need a Docker Hub account (free) to pull the images. If you don't have one, create a free account at [https://hub.docker.com](https://hub.docker.com).
-
-Once you have an account, log in from your terminal before running the containers:
+The infrastructure images come from `dhi.io`. If image pulls report an authorization error, authenticate with an entitled Docker account:
```bash
docker login dhi.io
```
-Enter your Docker Hub username and password when prompted.
-
-## Setting Environment Variables
-
-Edit the environment file:
+## 2. Run the installer
```bash
-nano .env
+curl -fsSL https://raw.githubusercontent.com/Resgrid/resgrid-setup/master/setup.sh | bash
```
-You will need to set at a minimum the following top 7 variables in the resgrid.env file.
-
-| Variable | Description |
-| ----------------------------- | --------------------------------------------------------- |
-| NGINX_RESGRID_WEB_URL | The FQDN of the server for the main Resgrid web app |
-| NGINX_RESGRID_API_URL | The FQDN of the server for Resgrid api |
-| NGINX_RESGRID_EVENTS_URL | The FQDN of the server for Resgrid Event hub |
-| NGINX_LETSENCRYPT_EMAIL | Your email address used for LetsEncrypt |
-| NGINX_RESGRID_WEB_IP | This can be an internal (LAN) IP or a public one, but needs to be the IP that the proxy is serving SSL |
-| NGINX_RESGRID_API_IP | This can be an internal (LAN) IP or a public one, but needs to be the IP that the proxy is serving SSL |
-| NGINX_RESGRID_EVENTS_IP | This can be an internal (LAN) IP or a public one, but needs to be the IP that the proxy is serving SSL |
-
+The installer asks for hostnames/TLS mode, generates unique passwords and Resgrid encryption keys, creates new OpenIddict certificates, writes `.env`, and starts the stack.
-Once those are set to real and correct values you can continue on for initial testing and validation. But to use the system for anything other then quick testing you should review and change any environment variables in the .env file that has **(REQUIRED)** text in the comment.
-
-If you set the **NGINX_LETSENCRYPT_EMAIL** variable value to **internal** that will have Caddy Proxy generate a self-signed certificate. This allows you to test out Resgrid in an internal or air-gapped environment. But depending on your browser's security settings this may make the system not work correctly. We recommend using a publicly accessible URLs or use your own proxy server.
-
-:::danger Note
-Failure to review and change the values inside the .env file for a development, production, testing or staging system could lead to issues, service disruption and potential security issues (i.e. utilizing the default encryption keys in the file).
-:::
-
-## External Networking
-
-This setup script assumes you are forwarding TCP port 80 and TCP port 443 from the Internet to the server you are running the script on. This docker setup comes with a Caddy reverse proxy for the web components (Web, Api and Events). If you are using a firewall or another proxy; i.e. HAProxy, NGINX, etc. You can forward directly to the ports for each component.
-
-| Port | Description |
-| ----------------------------- | --------------------------------------------------------- |
-| 5151 | Main Resgrid web app |
-| 5152 | Resgrid api |
-| 5153 | Resgrid Event hub |
-
-Setting **NGINX_RESGRID_WEB_IP**, **NGINX_RESGRID_API_IP** and **NGINX_RESGRID_EVENTS_IP** in the .env file will then point to your firewall/load balancer or proxy.
-
-:::tip Note
-The Resgrid Event Hub (5153) is a SignalR hub that utilized Web Sockets for realtime updates of UI components. Your proxy will need to upgrade/handle and pass those socket calls.
-:::
-
-## Run the Docker Compose
-
-Once you have setup the environment variables you can now run the docker compose file:
+Automated example:
```bash
-docker compose up -d
+RESGRID_WEB_URL=dispatch.example.com \
+RESGRID_API_URL=dispatchapi.example.com \
+RESGRID_EVENTS_URL=dispatchevents.example.com \
+RESGRID_LETSENCRYPT_EMAIL=admin@example.com \
+bash setup.sh
```
-The Resgrid system will take about 5 minutes to start up fully, this is due to the startup order of the containers. The last container to startup will be the web container, once that one is ready, you can now access the system.
+Use `RESGRID_NO_START=1` to configure without pulling or starting containers.
-To get log output you can run:
+## 3. Verify migrations
```bash
-docker compose logs
+cd ~/resgrid
+docker compose ps
+docker compose logs -f worker
```
-Or if you need to get output from a specific container just supply the name of the container from the docker-compose.yml file, for example:
-
-```bash
-docker compose logs worker
-```
+The worker creates and migrates four PostgreSQL databases. First start can take several minutes.
-## Important Note About Support
+With internal TLS, add all three hostnames to every client's hosts file and accept/trust the certificate for the web, API, and events endpoints. Accepting only the web certificate is insufficient.
-Resgrid is a complex system that can scale from a single instance to dozens of systems to service thousands of users. These installation setups get your system into a state where you can test and validate locally on the install system. To get Resgrid up and running to service non-local users you will need to reconfigure and harden the system. To complete those steps and configuration the system to your organizational needs you will require an IT professional. We do not provide installation support outside this guide via our Github page.
+When migrations settle, open the web hostname and use **Sign Up** to create the first account and department. There is no shared default administrator account.
-
-## Initial Web Login
-
-Visit all of the URLs you specified above in a web browser **NGINX_RESGRID_WEB_URL**, **NGINX_RESGRID_API_URL** and **NGINX_RESGRID_EVENTS_URL** over https:// and ensure they load correctly. If you are using an internal/air-gapped install with self-signed certificates you will need to accept the self-signed cert for each url and add exceptions in the browsers.
-
-:::tip Note
-If you are using an internal/air-gapped install we recommend adding **NGINX_RESGRID_WEB_URL**, **NGINX_RESGRID_API_URL** and **NGINX_RESGRID_EVENTS_URL** to the hosts file or your internal network DNS server as you should access all of those URLs via their name and not your machines IP address. View instructions on setting up hosts files here https://linuxize.com/post/how-to-edit-your-hosts-file/.
-
-You will also need a valid certificate for running fully air-gapped. We recommend Step-CA server https://smallstep.com/docs/step-ca/ for running your own Certificate Authority and syncing the certificates from that with all your workstations so you don't get certificate errors. You will configure the Caddy proxy to get ACME certificates from Step-CA https://smallstep.com/docs/tutorials/acme-protocol-acme-clients/#caddy-v2
-:::
-
-Once you have completed the steps above you will be able to log into the web applications user interface. Open up a web browser and navigate to the URL you specified in **NGINX_RESGRID_WEB_URL**, you will then be prompted by the login screen. Your default administrator credentials are **admin/changeme1234**. Once you log into the system it’s recommended that you change your admin password from the Edit Profile page by clicking on the Administrator name in the upper left hand corner.
-
-## Updating
-
-To update Resgrid you'll need to stop the system, clear the current containers and restart.
-
-Stop all running containers.
+## 4. Operate and update
```bash
-docker compose down
+docker compose ps
+docker compose logs -f SERVICE
+docker compose pull
+docker compose up -d
```
-Remove all cached images (to ensure we get new ones).
+Do not delete every Docker image during an update. Pulling and recreating this Compose project is sufficient and does not disturb unrelated containers.
-```bash
-docker rmi -f $(docker images -aq)
-```
-
-Restart the containers and they will pull new containers.
+Before an update, securely back up `.env` and create a consistent PostgreSQL dump:
```bash
-docker compose up -d
+docker compose exec -T db pg_dumpall -U resgrid > "resgrid-$(date +%F).sql"
```
-## What's Next?
+Keep the previous image digests and pre-update dump. Older application images may not work with a newly migrated schema, so rollback can require restoring PostgreSQL as well as the previous manifests/images.
-This Quick Start gets the system running via local host, but not externally or within your network. You will need to create DNS entries in your internal or external DNS server to point to the server that is running the containers. It's also recommend you change some default values in the resgrid.env file to ensure proper security.
\ No newline at end of file
+Continue with the full [self-hosted installation guide](./installation) for optional services, endpoints, configuration, backup scope, and rollback details.
diff --git a/docs/self-hosted/rick.md b/docs/self-hosted/rick.md
index bb370cc..f0c9208 100644
--- a/docs/self-hosted/rick.md
+++ b/docs/self-hosted/rick.md
@@ -2,147 +2,173 @@
sidebar_position: 4
---
-# Offline Multi-User
+# Resgrid Incident Command Kit (RICK)
-In this guide we will get Resgrid up in running in a Portable, Offline mode that
+The `rick` branch divides Resgrid across three portable Linux nodes on a private wired LAN:
-:::danger Warranty
-Resgrid's self hosted version is provided with no warranty, no guarantee of suitability and limited free support (Github Issues and Discussions only).
-Updates for our self hosted version are infrequent compared to our hosted version due to the additional cost in time to create those releases. We try
-our best to ensure an easy and working system that doesn't require a lot of tweaking, but due to it's complexity that is difficult.
-:::
+| Role | Services |
+|---|---|
+| Web/API | Caddy, web, API, events, worker/migrations, TTS, MCP; optional tracker gateway and relay |
+| Infrastructure | Redis, RabbitMQ, RustFS; optional offline OSM tile service |
+| Database | PostgreSQL and all four Resgrid databases |
-## Use Case
+This separation reduces resource contention and makes role recovery clearer, but it is not high availability. Every node is a single point of failure.
-This setup is intended to get Resgrid up and running on a single-user environment, like a laptop that will not be connected to or have internet access. No external users (i.e. from another machine or mobile device) will be connecting to this installation. For example you are coordinate rescue and recovery efforts for a hurricane from a location on your laptop, you are communicate with your field teams only via a radio as there is no power or cell phone data/WiFi Internet.
+## Important architecture notice
-## System Requirements
+The current published Resgrid application images are `linux/amd64` only. Infrastructure images publish native ARM64 variants, but the web-role Resgrid images do not.
-1.) Windows 10 or Windows 11 Laptop with WSL2 (Windows Subsystem for Linux)
-2.) Docker Desktop with WSL2 Enabled
-3.) Enough HDD Space to handle Mapping Data (if you want a large region like North America you'll need 30+ GB)
-4.) 4 or more Core Processor
-5.) 16GB or more of RAM
+On a Raspberry Pi web node, RICK therefore runs the application images using the kernel's x86_64 binfmt/QEMU handler. This has a performance cost. Test the full kit under realistic call, unit, event, mapping, TTS, and tracker load before field use. Native multi-architecture Resgrid images are the preferred long-term solution.
-## Setup Notice
+Install persistent emulation support on the web Pi:
-There is no redundancy, backup or fail-over in this setup. Everything runs on the local computer and is not intended to be accessed by anyone off of the local computer. If the local computer gets damaged this could result in loss of data. It's recommend that you have a USB drive that you can backup the database to (ideally the whole resgrid directory) periodically during the operation.
-
-## Prerequisites & Dependencies
-
-1. Update Windows
-2. Install WSL2 and Ubuntu 22.04
-3. Open up your Ubuntu 22.04 instance and finalize the setup (set password).
-4. Install Docker and enable WSL2 backend.
-
-## Docker Compose Setup
+```bash
+sudo apt update
+sudo apt install -y qemu-user-static binfmt-support
+cat /proc/sys/fs/binfmt_misc/qemu-x86_64
+```
-1. Open Notepad as Administrator and open C:\Windows\System32\drivers\etc\hosts file.
+The handler must report `enabled`. `rick.sh web start` stops with an actionable error if an ARM64 node lacks the handler.
-2. Add the following lines to the hosts file and save.
-```
-127.0.0.1 rg.mylocal
-127.0.0.1 rgapi.mylocal
-127.0.0.1 rgevents.mylocal
-127.0.0.1 rgtile.mylocal
-```
+## Hardware and LAN
-If you get a permissions error you didn't open up Notepad as Administrator, also don't use any RichText editor (Wordpad, Word, etc).
+- Three Raspberry Pi 5 systems with 8 GB RAM recommended, or equivalent 64-bit Linux nodes.
+- 64-bit Raspberry Pi OS/Ubuntu Server; 32-bit operating systems are unsupported.
+- SSD storage for PostgreSQL; high-endurance storage for every node.
+- Wired Ethernet switch and fixed DHCP reservations/static addresses.
+- Docker Engine and Compose v2 on each node.
+- Separate encrypted backup media.
-3. Navigate to Geofabrik and download the .osm.pbf file the region you will be operating in.
+Example plan:
-It is not recommend to try and pull an entire Sub Region (i.e. North America) as that will take quite a long time to import into the database. Instead it's recommended to import and additional Sub (Sub) Region, like a US State (i.e. Florida) or a Special Sub Region if they are available (i.e. US South).
+| Role | Address |
+|---|---|
+| Web/API | `192.168.50.11` |
+| Infrastructure | `192.168.50.12` |
+| Database | `192.168.50.13` |
-4. Using the Windows File Explorer move the osm.pbf file into Linux (left side bar) Ubuntu-22.04, home and your username folder. This will put it in your home directory.
+All three client hostnames (`rg.rick.local`, `rgapi.rick.local`, and `rgevents.rick.local`) resolve to the web node.
-5. Start your Ubuntu-22.04 WSL2 Instance so the command prompt is visible.
+## Configure once
-6. Clone the setup scripts for the Laptop compose:
+Clone on an administration computer or one node:
```bash
-git clone https://github.com/Resgrid/resgrid-setup.git -b laptop resgrid
+git clone --branch rick https://github.com/Resgrid/resgrid-setup.git resgrid-rick
+cd resgrid-rick
+chmod +x setup.sh rick.sh database/db/*.sh
+./setup.sh
```
-You should now have a folder called resgrid in your current directory.
+The configurator asks for the three hostnames and three node addresses, then generates shared credentials, application keys, and OpenIddict certificates. Run it once only. Independently generated `.env` files will not interoperate.
-7. Open the resgrid directory:
+Securely copy the complete configured checkout to the same path on each node:
```bash
-cd resgrid
+rsync -a --delete ./ pi@192.168.50.11:/opt/resgrid-rick/
+rsync -a --delete ./ pi@192.168.50.12:/opt/resgrid-rick/
+rsync -a --delete ./ pi@192.168.50.13:/opt/resgrid-rick/
```
-8. Docker Hub Authentication
+Protect and back up `.env`; it contains database credentials, encryption keys, and OIDC private keys.
-Resgrid container images are hosted on Docker Hub under the `dhi.io` repository. You will need a Docker Hub account (free) to pull the images. If you don't have one, create a free account at [https://hub.docker.com](https://hub.docker.com).
+## Validate and start
-Once you have an account, log in from your terminal before running the containers:
+Database node:
```bash
-docker login dhi.io
+cd /opt/resgrid-rick
+./rick.sh database config
+./rick.sh database start
+./rick.sh database status
```
-Enter your Docker Hub username and password when prompted.
-
-9. Import the osm.pbf you downloaded and placed in your home directory into the tile server. Change /home/yourname/yourregion.osm.pbf in the command below to the correct home directory name (yourname) and the name of the region file you downloaded (yourregion).
+Infrastructure node:
```bash
-docker run \
- -v /home/yourname/yourregion.osm.pbf:/data/region.osm.pbf \
- -v ./docker-data/osm:/data/database/ \
- overv/openstreetmap-tile-server \
- import
+cd /opt/resgrid-rick
+./rick.sh infra config
+./rick.sh infra start
+./rick.sh infra status
```
-If the container exits without errors, then your data has been successfully imported and you are now ready to run the tile server. If you selected a very large region, like North America this process can take days.
+Web node, after database and infrastructure are healthy:
+```bash
+cd /opt/resgrid-rick
+./rick.sh web config
+./rick.sh web start
+./rick.sh web logs worker
+```
-## Run the Docker Compose
+The worker migrates `resgrid`, `resgridoidc`, `resgridworkers`, and `resgriddoc`. Accept Caddy's internal certificate for all three client hostnames, then open the web hostname and use **Sign Up**.
-Once you have setup the environment variables you can now run the docker compose file in the resgrid directory:
+## Network policy
-```bash
-docker compose up
-```
+Permit only:
-That will run the interactive version of the containers, Ctrl+C will stop the containers.
+| Source | Destination | Ports |
+|---|---|---|
+| Clients | Web node | TCP 80/443 |
+| Web node | Database node | TCP 5432 |
+| Web node | Infrastructure node | TCP 5672, 6379, 9000 |
+| Administrators | Infrastructure node | TCP 15672 if the RabbitMQ UI is needed |
-If you want to run the containers in the background, use the -d option:
+Do not expose PostgreSQL, Redis, RabbitMQ, or RustFS outside the kit LAN. MCP is loopback-only on the web node.
-```bash
-docker compose up -d
-```
+## Prepare offline images
-The Resgrid system will take about 5 minutes to start up fully, this is due to the startup order of the containers. The last container to startup will be the web container, once that one is ready, you can now access the system.
+While internet is available, run `./rick.sh ROLE pull` on the corresponding node. For air-gapped recovery, export the images reported by `docker compose config --images`, copy the archive to protected media, and test a restore with `docker load` before deployment.
+The web-node archive contains AMD64 images even though the host is ARM64. Preserve the binfmt packages and test after operating-system upgrades.
-## Initial Web Login
+## Optional offline maps
-Open up your web browser and navigate to **https://rg.mylocal**, **https://rgapi.mylocal**, **https://rgevents.mylocal** and **https://rgtile.mylocal**. You will need to accept the self-signed cert for each url and add exceptions in the browsers. You can follow this guide to add those exceptions.
+Import a small regional `.osm.pbf` on the infrastructure node before the incident. Large imports can take many hours or days:
-Once you have completed the steps above you will be able to log into the web applications user interface. Open up a web browser and navigate to **https://rg.mylocal**, you will then be prompted by the login screen. Your default administrator credentials are **admin/changeme1234**. Once you log into the system it’s recommended that you change your admin password from the Edit Profile page by clicking on the Administrator name in the upper left hand corner.
+```bash
+mkdir -p docker-data/osm
+docker run --rm \
+ -v /path/to/region.osm.pbf:/data/region.osm.pbf:ro \
+ -v "$PWD/docker-data/osm:/data/database/" \
+ overv/openstreetmap-tile-server:latest import
+./rick.sh infra start --profile maps
+```
-## Updating
+Set `RESGRID__MappingConfig__LeafletTileUrl` in the shared `.env` to `http://INFRA_NODE:5156/tile/{z}/{x}/{y}.png`, redistribute `.env`, and recreate the web role.
-To update Resgrid you'll need to stop the system, clear the current containers and restart.
+## Optional tracker and email services
-Stop all running containers.
+After configuring tracking settings:
```bash
-docker compose down
+./rick.sh web start --profile tracking
```
-Remove all cached images (to ensure we get new ones).
+After configuring relay department/domain settings:
```bash
-docker rmi -f $(docker images -aq)
+./rick.sh web start --profile relay
```
-Restart the containers and they will pull new containers.
+Tracker ports and SMTP port 25 require deliberate firewall rules. The relay has no SMTP authentication or TLS.
+
+## Backup, update, and rollback
+
+Database dump from the database node:
```bash
-docker compose up -d
+docker compose --env-file .env -p resgrid-rick-database -f database/docker-compose.yml \
+ exec -T db pg_dumpall -U resgrid | gzip > "resgrid-$(date +%F).sql.gz"
```
-## What's Next?
+Back up the dump, `.env`, RustFS data, and Caddy state off-kit. Validate recovery on spare media/nodes.
+
+Update in database/infrastructure → web order, following worker migration logs. Retain previous image digests and a pre-upgrade dump. If migrations are incompatible with the previous release, restore PostgreSQL and `.env` before restarting the older web-role images.
+
+## Troubleshooting
-This Quick Start gets the system running via local host, but not externally or within your network. You will need to create DNS entries in your internal or external DNS server to point to the server that is running the containers. It's also recommend you change some default values in the resgrid.env file to ensure proper security.
\ No newline at end of file
+- `exec format error`: x86_64 binfmt is missing/disabled on the ARM64 web node.
+- `WAIT_HOSTS` timeout: verify node addresses in `.env`, routing, and firewall rules.
+- Browser login failure: accept/trust the API and events certificates, not only the web certificate.
+- Nodes disagree about credentials: restore the same backed-up `.env` to all three; do not rerun setup separately.
diff --git a/docs/setup-guides/_category_.json b/docs/setup-guides/_category_.json
new file mode 100644
index 0000000..39c24ec
--- /dev/null
+++ b/docs/setup-guides/_category_.json
@@ -0,0 +1,8 @@
+{
+ "label": "Setup Guides by Organization",
+ "position": 5,
+ "link": {
+ "type": "generated-index",
+ "description": "Step-by-step configuration recipes for the kinds of organizations that run Resgrid: fire departments, EMS, search and rescue, emergency management, incident management teams, CERT, security companies, industrial emergency response teams, delivery and transit operators, and multi-agency dispatch centres."
+ }
+}
diff --git a/docs/setup-guides/cert-community-response.md b/docs/setup-guides/cert-community-response.md
new file mode 100644
index 0000000..52aa6f8
--- /dev/null
+++ b/docs/setup-guides/cert-community-response.md
@@ -0,0 +1,66 @@
+---
+sidebar_position: 7
+title: CERT & Community Response
+---
+
+# Setting Up a CERT or Community Response Program
+
+For Community Emergency Response Teams, neighbourhood response groups, auxiliary / reserve programs, faith-based disaster teams and volunteer fire police. Members are many, part-time and varied in tech comfort — so the recipe favours **simplicity**: a clean roster, reliable notifications, an easy calendar, training tracking, and a few records for deployments.
+
+## 1 — Department settings
+
+| Setting | Value |
+|---|---|
+| Modules | Messaging, Calendar, Documents, Notes, Trainings, Records on; Shifts, Inventory, Checklists on only if you use them; Mapping on. |
+| Staffing reset | Off. |
+| Suppress notifications for | *Inactive* staffing level. |
+| Security | View personal info → *Admins + Team leaders*; Create calls → *Admins + Team leaders*; 2FA for admins. |
+
+## 2 — Types, groups, roles, statuses
+
+| Item | Values |
+|---|---|
+| **Unit types** | CERT team, Vehicle, Trailer. |
+| **Call types** | Deployment, Damage assessment, Shelter support, Traffic / crowd, Search assist, Training, Community event. |
+| **Priorities** | Urgent, Standard, Planned. |
+| **Certifications** | CERT basic, CPR/First aid, Traffic control, Shelter operations, ICS 100/700, Background check (with expiry). |
+| **Groups** | Station = your meeting point / cache; organisational groups per neighbourhood or team. |
+| **Roles** | CERT member, Team leader, Program coordinator, Logistics, Communications (ham), Medical. |
+| **Statuses** | Personnel: Available · Deployed · Not available; staffing: Active · Inactive · Deployable this week. |
+
+## 3 — Personnel
+
+- Invite in batches; hold a short **onboarding session** to install Responder, verify contact methods and set notification preferences (push + SMS).
+- Enter certifications (background check expiry matters).
+- Mark long-inactive members **hidden** rather than deleting; **communication tests** each season find dead numbers.
+
+## 4 — Calendar, trainings, documents
+
+- **Calendar** types: Training (RSVP), Meeting, Community event (sign-up sheet with limited slots), Deployment.
+- **Trainings**: module refreshers between in-person classes with quizzes; require completion for deployment eligibility (report to the coordinator).
+- **Documents**: field operating guide, forms, maps, MOU with the sponsoring agency.
+- **Notes**: radio plan, cache combination (restricted by permission), current standing orders.
+
+## 5 — Deployments (calls)
+
+- The coordinator creates a *Deployment* call (or the sponsoring EOC dispatches through a **department link**) and dispatches to the *CERT member* role or to neighbourhood groups.
+- **Messages with responses** for availability polls before a deployment.
+- **Check-in timers** (*Sector rotation* 2 h) for field teams; team leaders check in from Responder.
+
+## 6 — Records (CERT pack)
+
+Enable Records and use the **CERT Operations Pack**: *CERT Damage Assessment* (photo coordinates on), *CERT Assignment Tracking* and *CERT Activity / Communications Log*. Quick entry preset; the coordinator reviews. Add **Community risk reduction** activities (preparedness fairs, smoke-alarm installs) for grant reporting.
+
+## 7 — Communication
+
+- Chat: department channel + team channels; Assistant for *"who is available this weekend?"*.
+- Notifications: *CERT member available < 10* before events.
+- Workflows: *Call created* → email the sponsoring agency; *Certification expiring (background check)* → member + coordinator.
+- **Connect** public profile for class schedules and recruitment.
+
+## First-week checklist
+
+- [ ] Roster invited; ≥ 80 % verified email and mobile
+- [ ] Calendar types and the next three trainings entered with RSVP
+- [ ] A test deployment call received by everyone
+- [ ] CERT Damage Assessment definition published
diff --git a/docs/setup-guides/delivery-transit-field-service.md b/docs/setup-guides/delivery-transit-field-service.md
new file mode 100644
index 0000000..45cb7b9
--- /dev/null
+++ b/docs/setup-guides/delivery-transit-field-service.md
@@ -0,0 +1,73 @@
+---
+sidebar_position: 10
+title: Delivery, Transit & Field Service
+---
+
+# Setting Up a Delivery, Transit or Field-Service Operation
+
+For courier and delivery fleets, bus / paratransit / shuttle operators, utility and field-service crews, tow operators and any business that dispatches vehicles and people to jobs. In Resgrid a **vehicle is a unit**, a **job is a call**, a **planned sequence of stops is a route**, and end-of-day summaries are **records**.
+
+## 1 — Department settings
+
+| Setting | Value |
+|---|---|
+| 24-hour time | Per preference. |
+| Use branding in emails | On. |
+| Modules | Routes, Units, Shifts, Checklists, Work orders (Readiness Pro), Inventory, Records on; Mapping on; Trainings optional. |
+| Dispatch settings | Default statuses dispatched → *En route*, released → *Available*; rest period 5 min; *Order by driving ETA* on. |
+| Mapping settings | Unit location TTL 30 min. |
+
+## 2 — Types
+
+| Type | Values |
+|---|---|
+| **Unit types** | Van, Box truck, Bus, Paratransit van, Service truck, Tow truck, Bike / cargo bike. |
+| **Call types** | Delivery, Pickup, Service call, Breakdown, Accident, Passenger incident, Route deviation, Customer complaint. |
+| **Priorities** | Scheduled, Same-day, Urgent, Emergency. |
+| **Certifications** | Driver licence class, DOT medical card (expiry), Forklift, Hazmat endorsement, First aid, Passenger assistance. |
+
+## 3 — Groups, roles, statuses
+
+- **Stations**: each depot / yard with address and geofence (service area).
+- **Organisational groups**: regions or contracts.
+- **Roles**: Driver, Helper, Technician, Dispatcher, Supervisor, Mechanic.
+- **Custom statuses**: units — Off duty · Loading · En route · On site / Delivering · Returning · Breakdown · Out of service; personnel — On duty · Off duty · On break; staffing — Available · Unavailable.
+
+## 4 — Vehicles and drivers
+
+- One **unit** per vehicle with a *Driver* role (and *Helper* where used); User Defined Fields on units for plate, VIN, capacity, lift-equipped.
+- **Hardware GPS tracking** bindings per vehicle (Teltonika / Digital Matter / Traccar) with source priority above the phone; the Unit app on the driver's device for status, checklists and routes.
+- Drivers verify contact methods and install Responder or use the Unit app only.
+
+## 5 — Routes and jobs
+
+- **Routes**: build route plans with **stops** (address, contact, planned arrival/departure, dwell time, notes), assign a unit, optionally optimise stop order and use the depot as start/end; drivers **start** the route in the Unit app and stops are marked on geofence arrival. Link stops to **calls** where each stop is a job.
+- **Calls** for ad-hoc jobs: dispatch to a unit; **destination** POIs for customer sites; **call templates** for Delivery / Pickup / Service call with UDFs (order number, PO, customer reference).
+- **Run cards**: *Breakdown* → Service truck ×1 closest-unit auto-dispatch; *Urgent delivery* → Van ×1 closest.
+- **Contacts**: customers with addresses, delivery instructions as alert notes; categories per contract.
+
+## 6 — Records
+
+From the **Operational report templates** pack: *Delivery Run Report* (Quick entry, one per unit per day), *Bus/Route End-of-Day Summary* (transit), *Job/Service Completion* (field service, signature field, photo attachments). Reviewer: dispatcher. **Report exports** to email customers proof-of-delivery or to upload to the ERP nightly through a workflow.
+
+## 7 — Readiness
+
+- **Checklists**: *Vehicle pre-trip* (Unit, each shift, reported location required, critical: brakes, lights, tyres) with *Create a work order on failure* and *Place unit out of service*; *Lift inspection weekly* (paratransit); *Load securement* (trucks).
+- **Work orders** (Readiness Pro): preventive schedules by **meter** (miles / kilometres from the tracker) — oil change every 8,000 km, brake inspection every 30,000 km; business calendar Mon–Sat; vendor charges for outside shops; parts from inventory.
+- **Inventory**: depot as a facility; parts (filters, bulbs, wipers) as bulk with reorder points and a preferred supplier; handhelds and scanners as serialized assets issued to drivers; purchasing with purchase orders.
+- **Shifts**: assigned driver shifts per depot; workshifts anchor *each shift* checklists.
+
+## 8 — Communication
+
+- Chat: depot channels; DMs to units for turn-by-turn changes; urgent messages for recalls.
+- Notifications: *Unit breakdown* → dispatcher + mechanic; *Driver available < N* per depot before the morning wave.
+- Workflows: *Call closed (Delivery)* → email the customer contact with the proof-of-delivery export; *Record finalized (Run report)* → upload to the ERP SFTP; *Work order overdue* → Slack.
+- Weather alerts for winter operations.
+
+## First-week checklist
+
+- [ ] Every vehicle as a unit with a tracker binding
+- [ ] Depot geofences drawn; customers imported as contacts
+- [ ] One route built and run end-to-end in the Unit app
+- [ ] Pre-trip checklist scheduled per vehicle with out-of-service on failure
+- [ ] Delivery Run Report definition published and exported via workflow
diff --git a/docs/setup-guides/emergency-management.md b/docs/setup-guides/emergency-management.md
new file mode 100644
index 0000000..fa6fd77
--- /dev/null
+++ b/docs/setup-guides/emergency-management.md
@@ -0,0 +1,79 @@
+---
+sidebar_position: 5
+title: Emergency Management
+---
+
+# Setting Up an Emergency Management Agency / EOC
+
+For county, city, tribal, campus or corporate emergency-management offices that activate an **Emergency Operations Centre**, coordinate **Emergency Support Functions**, manage shelters and resource requests, and work with many partner agencies. In Resgrid a *call* is an **activation or event**, groups are **EOC sections and ESFs**, and Records carry the **situation reports, ICS forms and resource requests**.
+
+## 1 — Department settings
+
+| Setting | Value |
+|---|---|
+| 24-hour time | On. |
+| Modules | Shifts (for activation rosters), Calendar, Documents, Notes, Records, Inventory (warehouse/caches), Checklists on; Trainings optional. |
+| Data classification (security policy) | CUI if you handle FOUO material; Government/CUI preset. |
+| Staffing reset | Off. |
+
+## 2 — Types
+
+| Type | Values |
+|---|---|
+| **Unit types** | Mobile command vehicle, Trailer (generator / comms / shelter), Drone, Vehicle. EOC sections are groups, not units. |
+| **Call types** | EOC activation, Severe weather, Flood, Wildfire, Hazmat, Power outage, Shelter opening, Resource request, Public health, Exercise, Planned event. |
+| **Call priorities** | Monitoring, Partial activation, Full activation, Emergency. |
+| **Certification types** | ICS 100/200/300/400/700/800, G-series courses, Shelter management, Damage assessment, PIO. |
+| **Document categories** | EOP & annexes, ESF checklists, MOUs, Maps, Contact rosters, Sitreps. |
+
+## 3 — Groups, roles, statuses
+
+- **Stations**: *Primary EOC*, *Alternate EOC*, *Warehouse* with addresses.
+- **Organisational groups**: Command, Operations, Planning, Logistics, Finance/Admin; one group per ESF (ESF-1 Transportation … ESF-15 External affairs).
+- **Roles**: EOC manager, Section chief, ESF lead, Duty officer, PIO, Liaison, Shelter manager, Damage assessor, Radio operator.
+- **Custom statuses**: personnel — Activated (in EOC) · Activated (remote) · Standing by · Off duty · Deployed to field; staffing — Available · Unavailable · Deployed; units — Available · Deployed · Out of service.
+
+## 4 — Personnel and partners
+
+- Invite agency staff **and** partner-agency representatives (they can belong to their own department too and switch).
+- **Contacts**: shelter operators, utilities, hospitals, media, mutual-aid coordinators; categories per ESF.
+- **Distribution lists**: `esf-leads@`, `shelters@`, `pio@` including external addresses.
+- **Department links** to every fire/EMS/law agency that shares a Resgrid department, so the EOC map shows their units.
+
+## 5 — Activations (calls)
+
+- Create an **EOC activation** call with priority *Partial* or *Full*; dispatch to the section groups and ESF roles; the incident chat channel becomes the EOC channel.
+- Use **scheduled calls** for planned events (parades, elections) and **call templates** for each activation level.
+- **Check-in timers**: *IC* 60-minute briefing cadence.
+- **Weather alerts**: subscribe every county zone; threshold *Warning* → duty officer; *Watch* → notes.
+
+## 6 — Records (EOC pack and ICS forms)
+
+From the **EOC Coordination Pack**: *EOC Duty / Shift Log* (Quick entry, one per duty officer shift) and *Agency / ESF Status Report* (Review required, one per ESF per operational period). From the **Disaster Field Assessment Pack**: *Rapid Needs / Initial Damage Assessment* (with photo coordinates retained). From **Incident Support**: ICS 202, 205, 209, 211, 213RR, 214, 215, 260. Number ICS forms **per incident**. Use the **Exercise / AAR** pack after every exercise. Legal holds and records requests handle post-event public-records demands.
+
+**Deployments** track EMAC / state resource orders your agency requests or hosts.
+
+## 7 — Resource orders and logistics
+
+- **Resource orders**: municipalities request cots, generators, pumps; the EOC fills from the warehouse or partner departments.
+- **Inventory**: warehouse and trailers as locations; cots, blankets, water, MREs as bulk with reorder points; generators, radios, satellite phones as serialized assets; deployable caches as kits; issue to external agencies via an *External* location.
+- **Checklists**: *EOC readiness* (Department, monthly: generators, comms, supplies), *Shelter site inspection* (per shelter group, annual), *Trailer pre-deployment* (Unit).
+- **Work orders** (Readiness Pro): generator monthly run and annual load test, trailer inspections.
+
+## 8 — Communication
+
+- **Messages** with acknowledgement responses for activation notices.
+- **Chat**: custom channels per ESF with role rules; urgent messages for recalls; export transcripts after each activation.
+- **Notifications**: *Document added* (EOP category) → section chiefs; *Weather alert received*.
+- **Workflows**: *Call created (EOC activation)* → email all ESF leads + post to the EOC Teams channel; *Record finalized (ESF status)* → compile into the sitrep export nightly.
+- **Big Board** on the EOC wall; **Incident Command app** for the EOC manager.
+- **Connect** public profile for community preparedness posts.
+
+## First-week checklist
+
+- [ ] Sections and ESFs as groups; leads as group admins
+- [ ] Activation templates for partial and full activation
+- [ ] Weather zones subscribed and tested
+- [ ] EOC Duty Log and ESF Status Report definitions published
+- [ ] Warehouse inventory initialised; one resource order run end-to-end
+- [ ] Department links to partner agencies established
diff --git a/docs/setup-guides/ems-agency.md b/docs/setup-guides/ems-agency.md
new file mode 100644
index 0000000..acc1070
--- /dev/null
+++ b/docs/setup-guides/ems-agency.md
@@ -0,0 +1,93 @@
+---
+sidebar_position: 3
+title: EMS Agency
+---
+
+# Setting Up an EMS Agency
+
+For ambulance services, fire-based EMS divisions, inter-facility transport companies and community-paramedicine programs. The emphasis is on **units and crews**, **controlled substances**, **expiring supplies** and **protecting patient information**.
+
+:::caution Patient data
+Resgrid is not an ePCR. Keep patient care records in your ePCR system; use Resgrid calls, records and chat for dispatch, response, logistics and QA. Enrol in [Advanced Data Protection](../web-app/data-protection) if call notes or records will contain patient identifiers, and treat that as one control inside your own HIPAA program.
+:::
+
+## 1 — Department settings
+
+| Setting | Value |
+|---|---|
+| 24-hour time | On. |
+| Staffing reset | Off (crews are on shift, not on call). |
+| Require password reset via email | On. |
+| Modules | Shifts, Checklists, Inventory, Records on; Maintenance with Readiness Pro. |
+| Dispatch settings | Default statuses dispatched → *Responding*, released → *Available*; rest period 10 min; unit status timers 2 min (dispatched without en route) and 20 min (at hospital). |
+
+## 2 — Types
+
+| Type | Values |
+|---|---|
+| **Unit types** | ALS ambulance, BLS ambulance, Supervisor, Wheelchair van, Bariatric, Community paramedic. |
+| **Call types** | By nature: Cardiac, Respiratory, Trauma, Stroke, OB, Behavioral, Overdose, Fall, Sick person, Interfacility transfer, Standby / event, Mutual aid. |
+| **Call priorities** | If you use MPDS: Echo, Delta, Charlie, Bravo, Alpha, Omega (Echo/Delta = Emergency sound). Otherwise Emergency, Urgent, Routine, Scheduled. |
+| **Certification types** | EMR, EMT, AEMT, Paramedic, CPR/BLS, ACLS, PALS, PHTLS, Driver (EVOC). |
+| **Note categories** | Hospital diversion, Protocol updates, Drug shortages. |
+
+## 3 — Groups, roles, statuses
+
+- **Stations**: one per base/post with address and geofence (used for closest-unit selection).
+- **Roles**: EMT, AEMT, Paramedic, Supervisor, Dispatcher, Driver.
+- **Custom statuses** (EMS template): units — Available · Responding · On scene · Transporting · At hospital · Returning · Out of service · Posting; personnel — On duty · Off duty · Responding · On scene.
+
+## 4 — Units and crews
+
+Create each ambulance with roles **Driver/EMT** and **Attendant/Paramedic** (both required). Use **Unit staffing** at the start of every shift (or from the Unit app) so the crew is known — checklists, chat DMs to the unit and accountability rely on it. Add [hardware GPS tracking](../web-app/unit-tracking) bindings if the ambulances have trackers.
+
+## 5 — Dispatch
+
+- Calls from your CAD by email import; or dispatchers use the **Dispatch app**.
+- **Run cards**: *ALS emergency* (Echo/Delta): ALS ambulance ×1 + Paramedic role ×1; *BLS*: BLS ambulance ×1; *MCI* alarm level 2 adds ALS ×2 + Supervisor ×1. Closest-unit mode, *Order by driving ETA* on, minimum staffing *Fully staffed*, auto-dispatch on with a 10-minute rest period.
+- **Destinations**: create hospital and ED POIs under Mapping so crews pick a destination on the call.
+- **Protocols**: pre-arrival instruction protocols by chief complaint if you dispatch in-house.
+
+## 6 — Shifts
+
+Assigned 12-hour or 24-hour shifts per station; supervisors approve trades. Turn on *Use shift for group dispatch* so a station page goes to the on-duty crew only. Create matching **workshifts** so checklists can run *each shift*.
+
+## 7 — Checklists
+
+| Checklist | Target | Schedule | Notes |
+|---|---|---|---|
+| Ambulance start-of-shift | Unit | Each shift | Critical: drug box seals, O2 level, stretcher lock, monitor self-test. |
+| Controlled substance count | Unit | Each shift | **Witness required**, photo on failure, *Create work order on failure* off. |
+| Monitor / defib daily | Serialized equipment | Daily | Pads and battery expiry. |
+| Station restock weekly | Group | Weekly | |
+
+## 8 — Inventory
+
+- Items with **lot tracking + expiration**: medications, IV fluids, airway supplies; set minimum and reorder point; run the **expiration** alert weekly.
+- **Controlled substances**: flag the items; every movement needs a witness; print the controlled-substance log monthly.
+- Serialized assets: monitors, ventilators, stretchers, radios, tablets.
+- Kits: jump bags per unit; issue to the unit at shift start.
+- Purchasing: suppliers from Contacts; receive against purchase orders.
+
+## 9 — Records and QA
+
+- Activate Records with the *Review required* preset; use **Run** records for response documentation that does not belong in the ePCR, **Unit activity** per unit per call.
+- **Quality review**: a rubric *Run report QA* (times complete, narrative matches interventions, protocol cited) sampling 10 per month.
+- Restrict narrative and participant fields; enrol in ADP; set the disclosure statutory clock to your state's value.
+- Analytics: response performance by call type; turnout target 60 s, travel target per your contract.
+
+## 10 — Communication
+
+- Messages with responses for shift coverage.
+- Notifications: *ALS unit available < 1* → supervisor; inventory alerts → logistics.
+- Workflows: *Call created* → API call to billing/ePCR; *Checklist failed (narcotics)* → email medical director; *Record finalized* → export template to the medical director weekly.
+- Chat: incident channels for handoffs; images off in general channels unless ADP is on.
+
+## First-week checklist
+
+- [ ] Every ambulance created with two required roles and a Unit tablet
+- [ ] Crews set unit staffing at shift start
+- [ ] Hospital destination POIs created
+- [ ] Narcotics checklist with witness runs each shift
+- [ ] Medication lots with expiry entered; expiration alert reviewed
+- [ ] ADP decision made and, if enrolled, verification prompt tested on the Dispatch console
diff --git a/docs/setup-guides/fire-department.md b/docs/setup-guides/fire-department.md
new file mode 100644
index 0000000..cfce1e3
--- /dev/null
+++ b/docs/setup-guides/fire-department.md
@@ -0,0 +1,124 @@
+---
+sidebar_position: 2
+title: Fire Department
+---
+
+# Setting Up a Fire Department
+
+This recipe covers volunteer, combination and career fire departments — from a single-station volunteer company to a multi-battalion career department. Differences between the two ends are called out as you go.
+
+## What you will end up with
+
+- Calls arriving from your dispatch centre (email or SMS page) or created by your own dispatcher, alerting the right stations, roles and units by push, SMS, email and voice.
+- Live status of every member and apparatus on the dashboard, the Big Board and the apps.
+- Run cards that fill the assignment automatically.
+- Daily apparatus and SCBA checks, with failures turning into work orders.
+- Run, training and work records with NERIS incident reports (US).
+- Hydrants, occupancies, inspections and permits if you run prevention.
+
+## 1 — Department settings
+
+| Setting | Value |
+|---|---|
+| Time zone / 24-hour time | Your zone; most fire departments use 24-hour time. |
+| Department address | Station 1 or the administration office. |
+| Default map centre | The middle of your first-due area. |
+| Staffing reset | Volunteer: **On**, daily 06:00 → *Available* (clears forgotten *Unavailable* flags). Career: off. |
+| Modern notification sounds | On. |
+| Modules | All on except *Maintenance* until you have Readiness Pro. |
+
+## 2 — Types
+
+| Type | Values |
+|---|---|
+| **Unit types** | Engine, Ladder / Truck, Rescue, Tender / Tanker, Brush, Command, Utility, Ambulance (if you run EMS). |
+| **Call types** | Structure fire, Vehicle fire, Brush / wildland fire, Fire alarm, MVA, MVA with entrapment, Medical, Hazmat, Gas leak, Water rescue, Public assist, Mutual aid, Standby. |
+| **Call priorities** | Low (routine, no sound at night), Medium, High, Emergency (full alert, overrides quiet hours). Keep the four defaults and set colours. |
+| **Certification types** | Firefighter I, Firefighter II, Driver/Operator, Fire Officer I, EMT, EMR, Hazmat Ops, CPR. |
+| **Document categories** | SOG/SOP, Bylaws, Apparatus manuals, Training, Forms. |
+| **Note categories** | Standing orders, Road closures, Hydrants OOS, Minutes. |
+
+## 3 — Groups & stations
+
+- One **Station** group per firehouse with the street address; draw the **geofence** for its first-due area.
+- Multi-station: an **Organisational** group per battalion or district as the parent.
+- Make each station's captain a **group admin**.
+
+## 4 — Roles
+
+Firefighter, Interior firefighter, Driver/Operator, Officer, Chief officer, EMT/EMR, Support/Fire police, Probationary. Roles are what run cards and dispatch-by-role use — keep them about *capability*, not rank (ranks are separate).
+
+## 5 — Custom statuses
+
+Load the **Fire** template under Custom Statuses and trim:
+
+- **Personnel**: Standing by · Responding to station · Responding to scene · On scene · Available at station · Not responding · Off duty.
+- **Staffing**: Available · Unavailable · On call · On shift.
+- **Units** (Engine/Ladder/Rescue/Tender/Brush): In quarters · Responding · On scene · Available · Returning · Out of service.
+
+## 6 — Units
+
+Create every apparatus with its type and station, and add **unit roles** — Engine: Driver, Officer, Firefighter ×2 (mark Driver and Officer *required*). Utility and command vehicles: a single Officer/Driver role.
+
+## 7 — Personnel
+
+Use **Department Settings → Invites** to invite everyone by email. Ask members to:
+
+1. Install **Responder**, sign in, verify email and mobile number.
+2. Set notification preferences (push for calls; SMS as backup).
+3. Fill in their home address (ETA and closest-member logic).
+
+Assign roles and stations; enter certifications with expiry dates.
+
+## 8 — Security & permissions
+
+| Permission | Volunteer | Career |
+|---|---|---|
+| Create calls | Admins + Officers | Admins + Dispatcher role |
+| Close / delete calls | Officers / Dept admins | Dispatcher / Dept admins |
+| View personal info | Everyone | Admins + Officers |
+| Create shifts | Dept admins | Dept admins |
+| Manage checklists / work orders | Admins + Apparatus officer role | Same |
+| 2FA for admins | Dept admins | All admins |
+
+## 9 — Dispatch
+
+- **Call import**: forward CAD pages to the dispatch import email; choose the matching **email format** (Active911, IAmResponding, county-specific formats, or Generic).
+- **Text messaging**: provision a number if members will text `responding` / `available`.
+- **Dispatch settings**: *Also dispatch to entire group* on unit dispatch (volunteer); *Use shift for group dispatch* (career); default statuses dispatched → *Responding*, released → *Available*.
+- **Run cards** (`Dispatch.RunCards`): *Structure fire* (High + Structure fire): L1 Engine ×2, Ladder ×1, Rescue ×1, Chief officer ×1; L2 adds Engine ×1, Tender ×1. *Brush fire*: Brush ×2, Engine ×1. *Medical*: Rescue ×1 + EMT ×2. Station-based mode; auto-dispatch **off** for volunteers until confident, **on** for career.
+- **Check-in timers**: PAR 20 min on Structure fire; Rehab 45 min.
+- **Protocols**: structure-fire and gas-leak protocols with questions and attachments.
+
+## 10 — Readiness: checklists, work orders, inventory
+
+- **Checklists** (free): from templates — *Fire apparatus daily* (Unit, each shift or daily 07:00, window 120 min, critical items brakes/lights/pump), *Fire apparatus weekly*, *SCBA weekly* (Serialized equipment, witness required), *Station facility monthly*.
+- **Work orders** (Readiness Pro): enable Maintenance; preventive schedules per apparatus (annual pump test, ladder test, oil change every 250 hours by meter); *Create a work order on failure* on the daily checklist; operations policy with a $500 approval threshold.
+- **Inventory**: SCBA packs, cylinders, TICs, radios and gas meters as serialized assets; foam, absorbent, medical supplies as bulk with reorder points; turnout gear kits issued to members.
+
+## 11 — Records
+
+- Enable `Records.System` and **activate**. Locked types cover Run, Training, Work, Meeting. Preset: *Quick entry* for volunteers, *Review required* for career (officer reviews).
+- **NERIS** (US): enter entity ID and credentials, map every call type in the crosswalk, auto-submit after the first few are checked.
+- **Prevention**: hydrants (import from the water utility), occupancies for target hazards, inspection programs if you have a bureau, permits (burn, fireworks), CRR activities for accreditation.
+- **Analytics**: set turnout target 80 s and travel target 240 s (NFPA 1710) or your standard of cover.
+
+## 12 — Communication and engagement
+
+- **Shifts**: signup *duty crew* shifts (volunteer) or assigned platoon shifts (career).
+- **Calendar**: trainings with RSVP; business meetings.
+- **Trainings**: annual refreshers with quizzes.
+- **Notifications**: *Driver/Operator available < 2* → officers; *Unit out of service* → chief.
+- **Workflows**: *High/Emergency call* → email chief + Discord; *Certification expiring* → member + training officer.
+- **Communication tests**: monthly all-call page test.
+- **Chat**: department and station channels; incident channels are automatic.
+
+## First-week checklist
+
+- [ ] Every member verified email + mobile and installed Responder
+- [ ] Every apparatus created with roles; Unit app on each tablet
+- [ ] A test call dispatched to a test group and received on all channels
+- [ ] Run card test/simulate matches expectations
+- [ ] Daily apparatus checklist scheduled and running
+- [ ] Records activated; one Run record finalized end-to-end
+- [ ] Security permissions reviewed; 2FA on for admins
diff --git a/docs/setup-guides/incident-management-team.md b/docs/setup-guides/incident-management-team.md
new file mode 100644
index 0000000..309c41f
--- /dev/null
+++ b/docs/setup-guides/incident-management-team.md
@@ -0,0 +1,68 @@
+---
+sidebar_position: 6
+title: Incident Management Team
+---
+
+# Setting Up an Incident Management Team
+
+For Type 3 all-hazards IMTs, wildland teams, regional IMTs and large-event command teams that stand up an ICS organisation for days or weeks, often on someone else's incident. The emphasis is on **command boards**, **ICS forms as records**, **deployments** and the **Incident Command app**.
+
+## 1 — Department settings and types
+
+| Item | Value |
+|---|---|
+| Modules | Records, Documents, Calendar, Checklists, Inventory on; Shifts on for operational periods. |
+| **Unit types** | Overhead team, Crew, Engine (if you bring apparatus), Vehicle, Trailer. |
+| **Call types** | Incident (assigned), Planned event, Exercise, Standby, Mutual aid. |
+| **Call priorities** | Immediate need, Standard, Planned. |
+| **Certification types** | Every ICS position qualification (ICT3, OSC3, PSC3, LSC3, FSC3, SOF3, PIO3, DIVS, STEN …), red card, medical, driving. |
+
+## 2 — Groups and roles
+
+- **Organisational groups** per section: Command, Operations, Planning, Logistics, Finance/Admin.
+- **Roles** = ICS positions and trainee flags: IC, Deputy IC, Safety officer, PIO, Liaison, Operations section chief, Division/group supervisor, Planning section chief, Resources unit leader, Situation unit leader, Logistics section chief, Supply/Facilities/Ground support/Comms unit leaders, Finance section chief, Time/Cost/Comp-claims unit leaders, Trainee.
+- Custom statuses: personnel — Available for assignment · Assigned · En route to incident · Checked in · Demobilised · Unavailable.
+
+## 3 — Command definitions
+
+**Department → Commands** — build your standard ICS organisation as a **command definition** (template) with sections, branches, divisions and single resources so the Incident Command app can instantiate it on a call and assign people to positions. Keep variants: *Type 3 wildland*, *Type 3 all-hazards*, *Planned event*.
+
+## 4 — Deployments and calls
+
+- Each assignment is a **call** (type *Incident*) with the incident name; dispatching to roles staffs the team.
+- Track the **resource order** that brought you there in **Records → Deployments** (order number, requesting/receiving agency, fills per member, snapshots of the order document). Add a connector if your ordering system serves the Mutual-Aid Order Feed.
+- **Command app**: the IC and section chiefs run command boards, accountability and the Command chat channel.
+
+## 5 — Records: ICS forms
+
+Create definitions from the **Incident Support (ICS Logistics, Finance and Administration)** pack and number them **per incident**:
+
+| Planning cycle | Forms |
+|---|---|
+| Objectives and organisation | ICS 202, 203, 204, 207 |
+| Communications and medical | ICS 205, 205A, 206 |
+| Safety | ICS 208, 215A |
+| Status | ICS 209, 210, 211, 219, 221 |
+| Resources and logistics | ICS 213, 213RR, 215, 217A, 218, 220, 260 |
+| Time and cost | ICS 214, 225, OF-286, OF-288, OF-294, OF-296, OF-297, OF-315, SF-261 |
+
+Use *Review required* for the IAP forms (planning section chief reviews), *Quick entry* for ICS 214 activity logs (every member, one per operational period). Compile the **IAP package** as a packet from the records queue. Use the **Exercise / AAR** pack after each assignment.
+
+## 6 — Readiness
+
+- **Checklists**: *Go-kit* (Personnel, monthly), *Team cache* (Group, quarterly), *Vehicle pre-trip* (Unit).
+- **Inventory**: cache trailer as a facility with containers; radios, laptops, printers, sat phones as serialized assets issued per deployment; consumables as bulk.
+- **Trainings** and **certifications** for position task books; **calendar** for team meetings and exercises; **messages with responses** for availability polls before each assignment.
+
+## 7 — Communication
+
+- Chat: Command channel (IC + role holders), incident channel, section channels.
+- Workflows: *Call created (Incident)* → email the team roster and post to the team Slack; *Record finalized (ICS 209)* → email the agency administrator.
+- Voice: PTT channels for Command and Operations.
+
+## First-week checklist
+
+- [ ] Roles = ICS positions; certifications entered
+- [ ] Command definition templates built and tested in the Incident Command app
+- [ ] ICS 202/204/205/206/214 definitions published with per-incident numbering
+- [ ] One exercise incident run end-to-end: call, command board, forms, AAR
diff --git a/docs/setup-guides/industrial-emergency-response.md b/docs/setup-guides/industrial-emergency-response.md
new file mode 100644
index 0000000..0bfe0e4
--- /dev/null
+++ b/docs/setup-guides/industrial-emergency-response.md
@@ -0,0 +1,66 @@
+---
+sidebar_position: 9
+title: Industrial Emergency Response
+---
+
+# Setting Up an Industrial Emergency Response Team
+
+For plant fire brigades, refinery / chemical / mining / utility emergency response teams, and large-site ERTs that combine fire, hazmat, rescue and medical capability inside a fence line, under OSHA / process-safety regulation. The emphasis is on **safety-critical maintenance**, **serialized equipment with calibration**, **hazardous-work controls**, **shift handover** and **near-miss reporting**.
+
+## 1 — Department settings
+
+| Setting | Value |
+|---|---|
+| 24-hour time | On. |
+| Modules | Everything on including Maintenance (Readiness Pro) and Checklists. |
+| Security policy | Enterprise preset; SSO with the corporate IdP; MFA for all; data classification *Confidential*. |
+| Dispatch settings | Default statuses dispatched → *Responding*; unit status timers 3 min. |
+
+## 2 — Types
+
+| Type | Values |
+|---|---|
+| **Unit types** | Fire brigade engine, Hazmat trailer, Rescue truck, Medical unit, Foam unit, Utility. |
+| **Call types** | Fire, Spill / release, Gas detection, Confined-space rescue, Medical, Evacuation / muster, Drill, Mutual aid (municipal FD), Standby (hot work). |
+| **Priorities** | Level 1 (local), Level 2 (site-wide), Level 3 (off-site impact / mutual aid) — Level 3 = Emergency sound. |
+| **Certifications** | NFPA 1081 brigade member, Hazmat technician, Confined-space rescue, Rope rescue, EMR/EMT, Incident commander, Forklift, Respirator fit test (expiry!). |
+
+## 3 — Groups, roles, statuses
+
+- **Stations**: *Main plant fire station*, *Tank farm*, *Warehouse* with addresses and geofences per process area.
+- **Organisational groups**: Day ERT / Night ERT (matching plant crews).
+- **Roles**: Brigade member, Hazmat technician, Rescue technician, Medical responder, Incident commander, Safety officer, Control-room operator.
+- **Custom statuses**: personnel — Available (on site) · Responding · On scene · Staging · Off site; units — In service · Responding · On scene · Out of service · Decon.
+
+## 4 — Dispatch
+
+- Calls from the control room via the **Dispatch app** or **email import** from the plant alarm system; **text-to-call** from operators.
+- **Run cards**: *Spill/release* (Level 2 + Spill): Hazmat trailer ×1, Hazmat tech ×2, Safety officer ×1, Brigade engine ×1; *Confined-space rescue*: Rescue truck ×1, Rescue tech ×3, Medical ×1; **station coverage minimum** keeps one crew in the plant when a unit leaves for mutual aid.
+- **Protocols** per hazard class with attached SDS and isolation procedures.
+- **Indoor maps** of process buildings with hazard zones and muster points; **occupancies** per building with utility shutoffs, hazmat inventory and tactical summaries.
+- **Check-in timers**: *Hazmat exposure* 20/30 min, *PAR* 15 min.
+
+## 5 — Readiness (the core)
+
+- **Checklists**: *Rescue equipment weekly* (Serialized equipment, critical items), *Gas monitor bump test* (Serialized, daily, numeric reading with passing range), *SCBA weekly* (witness), *Safety audit* (Group, monthly, photo on failure), *Foam unit monthly* — all with **Create a work order on failure** and **Place equipment out for repair**.
+- **Work orders** (Readiness Pro): use **Safety-critical** and **Hazardous work** routinely — procedure, version, permit, isolation reference and qualified personnel are then mandatory; safety-hold release requires an independent reviewer; operations policy with spending thresholds and working-hours calendar; preventive schedules by **meter** (pump hours) and **calendar** (annual hydrostatic tests), with **condition triggers** on gas-monitor readings.
+- **Inventory**: every gas monitor, SCBA, harness, rope and radio as a serialized asset with **calibration / retirement date as expiry**; spill supplies and foam as bulk with reorder points; controlled items (e.g. antidote kits) with witnessing; purchasing through site suppliers.
+
+## 6 — Records (industrial pack)
+
+From the **Industrial Operations and Process Safety Pack**: *Operator / Control-Room Shift Handover* (Quick entry, one per unit per shift) and *Incident / Near Miss* (Approval preset, HSE manager approves, restricted fields). From **HAZMAT Response Pack**: *HAZMAT Release / Response*. Add *Exercise / AAR* for drills and *Run* for every response. **Investigations** for significant events with chain of custody. Quality-review rubric on near-miss reports.
+
+## 7 — Communication
+
+- Chat: ERT channel, control-room channel, incident channels per event; **urgent** messages for muster.
+- Notifications: *Hazmat tech available < 2* → ERT lead; *Equipment out for repair* → maintenance.
+- Workflows: *Call created (Level 2+)* → email site management + SMS the municipal FD liaison; *Work order safety hold applied* → Teams post to maintenance; *Record finalized (Near miss)* → export to the EHS system nightly.
+- **Weather alerts** for wind (release modelling) and lightning.
+
+## First-week checklist
+
+- [ ] All ERT members with certifications and fit-test expiry dates
+- [ ] Every serialized asset entered with calibration expiry; expiration alert reviewed
+- [ ] Gas monitor and rescue equipment checklists scheduled with work-order-on-failure
+- [ ] Hazardous-work work order run through hold → release with an independent reviewer
+- [ ] Shift Handover and Near Miss definitions published
diff --git a/docs/setup-guides/multi-agency-dispatch-center.md b/docs/setup-guides/multi-agency-dispatch-center.md
new file mode 100644
index 0000000..22db0df
--- /dev/null
+++ b/docs/setup-guides/multi-agency-dispatch-center.md
@@ -0,0 +1,53 @@
+---
+sidebar_position: 11
+title: Multi-Agency Dispatch Centre
+---
+
+# Setting Up a Multi-Agency Dispatch Centre
+
+For a county or regional dispatch centre, a mutual-aid coordination centre, or a dispatch company that pages and tracks several independent departments. In Resgrid every agency keeps **its own department** (roster, units, settings, records) and the centre is a department too, joined to each agency by a **department link**. Links share active calls and unit/personnel status in the direction you choose, and **resource orders** move units between agencies.
+
+## 1 — Structure
+
+| Piece | How to set it up |
+|---|---|
+| **Centre department** | Its own personnel are the dispatchers (role *Dispatcher*); stations = the centre and any backup centre; usually no units. |
+| **Agency departments** | Each agency follows its own guide ([fire](fire-department), [EMS](ems-agency) …) and administers itself. |
+| **Department links** | From the centre's **Department → Links**, create a link to each agency (the agency accepts it). Choose what is shared: *active calls*, *units*, *personnel status* — typically calls **to** the agency and status **from** the agency. |
+| **Dispatcher permissions** | In each agency, the link grants the centre the ability to create calls in that agency; the agency keeps close/delete rights. |
+
+## 2 — Dispatching through links
+
+- Dispatchers use the **Dispatch app** (or the web) signed in to the **centre** department. The New Call page lists linked agencies' units and groups as dispatch targets.
+- A call created for an agency lives in **that agency's** department (its numbering, its records, its notifications); the centre sees it on its own dashboard through the link.
+- **Run cards** are configured per agency (the agency's types and units). A regional standard of *Structure fire* cards in every agency keeps behaviour consistent.
+- **Email / SMS import**: CAD pages can go to each agency's import address; or the centre creates calls by hand.
+
+## 3 — The Big Board and mapping
+
+- Run the **Big Board** in the centre with linked departments' units and calls visible.
+- Mapping shows units from every linked agency (subject to each agency's *view unit locations* permission and the link's sharing settings).
+- **Weather alerts** subscribed for the whole region in the centre department.
+
+## 4 — Resource orders
+
+Use **Orders** for cross-agency moves: the centre (or an agency) raises an order (*2 tenders to Station 4 for water shuttle*), agencies **fill** it with specific units, and fills are accepted/returned — with the whole exchange audited. Agencies with Records can log the same order as a **deployment** with the order document as a snapshot.
+
+## 5 — Communication
+
+- **Chat**: create a custom channel in the centre department for coordinators; incident channels stay inside the owning agency.
+- **Messages / distribution lists**: `chiefs@` across agencies via contacts.
+- **Workflows** in the centre: *Call created* → post to the regional Discord; in each agency: *Call created* → local notifications.
+- **Communication tests** run per agency.
+
+## 6 — Records and reporting
+
+Records stay per agency (each agency's NERIS identity and definitions). The centre uses **Reports → Active calls and resources** and its own Run records for centre activity; for regional statistics ask agencies to schedule **report exports** to a shared mailbox, or use **saved reports** per agency.
+
+## Setup checklist
+
+- [ ] Centre department created; dispatchers with the Dispatcher role and Dispatch app login permission
+- [ ] Each agency linked; sharing directions verified with a test call
+- [ ] Regional call type / priority naming agreed and applied in every agency
+- [ ] Big Board running with linked units visible
+- [ ] One resource order filled and returned end-to-end
diff --git a/docs/setup-guides/overview.md b/docs/setup-guides/overview.md
new file mode 100644
index 0000000..bc6fe59
--- /dev/null
+++ b/docs/setup-guides/overview.md
@@ -0,0 +1,54 @@
+---
+sidebar_position: 1
+title: Choosing a Setup Guide
+---
+
+# Setting Up Resgrid for Your Organization
+
+Resgrid started as computer-aided dispatch for fire departments, but the same building blocks — **calls, people, units, groups, statuses, schedules, records, checklists, inventory, maps and notifications** — configure into very different organizations. These guides give you a recipe for each kind, with concrete values to enter, which modules to switch on or off, and which mobile app each person should use.
+
+Every guide assumes you have already created your department (hosted at [resgrid.com](https://resgrid.com) or [self-hosted](../self-hosted/installation)) and are signed in as its administrator. The generic, screen-by-screen walk-through is in [How-tos → Setup department](../how-tos/setup-department); the guides below tell you *what to put in*.
+
+## Pick the guide closest to you
+
+| Organization | Guide | Typical modules |
+|---|---|---|
+| Volunteer, combination or career fire department | [Fire department](fire-department) | Dispatch, run cards, personnel/units, shifts, checklists, work orders, inventory, Records + NERIS, prevention |
+| Ambulance service, fire-based EMS, community paramedicine | [EMS agency](ems-agency) | Dispatch, units, shifts, checklists (narcotics), inventory (lots/expiry), records, ADP |
+| Search and rescue team, mountain / cave / swiftwater / K9 | [Search & rescue](search-and-rescue) | Dispatch to roles, mapping & custom maps, routes, records (SAR pack), calendar, inventory |
+| County / city emergency management, EOC | [Emergency management](emergency-management) | Calls as activations, groups per section/ESF, records (EOC pack, ICS forms), weather alerts, links, resource orders |
+| Incident management team, wildland / all-hazards | [Incident management team](incident-management-team) | Command definitions, records (ICS 201–225, OF/SF forms), deployments, IC app |
+| CERT / community response / auxiliary | [CERT & community response](cert-community-response) | Personnel, calendar, trainings, messages, records (CERT pack), simple dispatch |
+| Private security, campus / healthcare security, facilities | [Security & facilities](security-and-facilities) | Calls by client site, custom statuses, patrol routes, indoor maps, records (patrol log / incident report), checklists |
+| Industrial fire brigade, plant emergency response team | [Industrial emergency response](industrial-emergency-response) | Dispatch, units, hazmat protocols, checklists, work orders with safety holds, inventory (serialized), records (industrial pack), indoor maps |
+| Delivery, courier, field service, bus / transit operator | [Delivery, transit & field service](delivery-transit-field-service) | Units as vehicles, routes, calls as jobs, records (delivery run / route EOD), hardware GPS tracking |
+| Central dispatch centre serving several agencies | [Multi-agency dispatch centre](multi-agency-dispatch-center) | Department links, resource orders, run cards, Dispatch app, Big Board |
+
+## The order that works for everyone
+
+Whatever the guide, this order avoids rework:
+
+1. **Department settings** — name, time zone, address, map centre, 24-hour time.
+2. **Types** — unit types, call types, call priorities, certification types (guides list them).
+3. **Groups & stations** — the physical places first, organisational groups second; draw geofences.
+4. **Roles** — what you dispatch by and report on.
+5. **Custom statuses** — from a template; adjust wording.
+6. **Units** — with unit roles (seats).
+7. **Personnel** — invite in bulk; ask everyone to verify email and phone and install the app.
+8. **Security & permissions** — tighten what the defaults leave open (delete calls, view PII).
+9. **Dispatch settings** — how groups/units/shifts dispatch; email/SMS import; run cards.
+10. **Everything else** — records, checklists, inventory, shifts, calendar, workflows, notifications — one module at a time, with a champion for each.
+
+## Which app for whom
+
+| App | Who uses it |
+|---|---|
+| **Responder** | Every member: receive calls, set status and staffing, chat, checklists, records in the field. |
+| **Unit** | The apparatus / vehicle / team tablet: unit status, crew, AVL, checklists, unit records. |
+| **Dispatch** | Dispatchers and duty officers: create and manage calls, see everything. |
+| **Incident Command** | Incident commanders: command boards, accountability, incident channels, ICS records. |
+| **Big Board** | Station and EOC wall displays. |
+
+## Getting help
+
+The [support portal](https://resgrid.zohodesk.com/portal/en/home), the community Discord and GitHub issues are linked under **Help** in the web app.
diff --git a/docs/setup-guides/search-and-rescue.md b/docs/setup-guides/search-and-rescue.md
new file mode 100644
index 0000000..e58045e
--- /dev/null
+++ b/docs/setup-guides/search-and-rescue.md
@@ -0,0 +1,80 @@
+---
+sidebar_position: 4
+title: Search & Rescue
+---
+
+# Setting Up a Search & Rescue Team
+
+For volunteer SAR teams — ground, mountain, K9, technical rope, swiftwater, cave, drone — that are paged by a sheriff, park service or coordination centre and deploy for hours or days. The emphasis is on **dispatching by capability (roles)**, **maps**, **availability polling** and **mission records**.
+
+## 1 — Department settings
+
+| Setting | Value |
+|---|---|
+| Disable auto-available | **On** (members should not drift back to *Available* automatically). |
+| Staffing reset | Off — availability is set deliberately. |
+| Mapping settings | Personnel and unit location TTL 240–480 minutes (field teams report rarely). |
+| New Call form fields | Show what3words and coordinates; make location required. |
+| Modules | Shifts off (unless you run an on-call rota); Inventory, Checklists, Records, Calendar, Trainings on. |
+
+## 2 — Types
+
+| Type | Values |
+|---|---|
+| **Unit types** | Ground team, K9 team, Technical team, Swiftwater team, UTV/ATV, Drone, Command post, Vehicle. |
+| **Call types** | Missing person, Overdue hiker, Injured hiker / rescue, Recovery, Evidence search, Mutual aid, Training / exercise, Standby (event). |
+| **Call priorities** | Urgent (immediate response, full alert), Standard (respond within the hour), Planned (scheduled search / training). |
+| **Certification types** | SARTECH II/III, Wilderness first aid / WFR, Rope technician, Swiftwater, K9 certification, Avalanche, Drone pilot (Part 107), ICS 100/200/700. |
+
+## 3 — Groups, roles, statuses
+
+- **Station**: the cache / meeting point (with address). **Organisational** groups: Ground, Technical, K9, Support/Logistics, Command.
+- **Roles** (what you dispatch by): Ground searcher, Team leader, K9 handler, Rope tech, Swiftwater, Medical (WFR+), Drone pilot, Radio operator, Incident commander, Logistics.
+- **Custom statuses**: personnel — Available · Responding to CP · At command post · Deployed in field · Returning · Not available; staffing — Available this week · Limited · Unavailable · Deployed elsewhere. Units (Team) — Staging · Assigned · Searching · Subject located · Returning.
+
+## 4 — Personnel and units
+
+- Invite members; ask for verified email + mobile, home address (for ETA to the trailhead) and the Responder app.
+- Certifications with expiry drive who may be dispatched to technical roles.
+- Units are your **teams** (Team Alpha … with roles Team leader, Navigator, Medic, Searcher ×4) and **vehicles** (UTVs, command trailer). Staff teams at the CP from the Unit app.
+
+## 5 — Dispatch
+
+- Callouts arrive by SMS or email from the sheriff — set up **email import** (Generic format) or **text-to-call**; or the duty officer creates the call in the Dispatch app.
+- Dispatch to **roles**, not groups: *Missing person* → Ground searcher + Team leader + K9 handler; *Rescue* → Rope tech + Medical.
+- **Run cards**: *Missing person* (Urgent + Missing person): Team leader ×1, Ground searcher ×6, K9 team ×1; manual selection mode (people choose to respond).
+- **Messages with responses** for availability polls: *Available for a callout starting 06:00 tomorrow? Yes / No / Later*.
+- **Check-in timers**: *Sector rotation* 2 h per field team.
+
+## 6 — Mapping
+
+- Layers: trail systems, land ownership, search segments exported from CalTopo/SARTopo (GeoJSON/KML), cell coverage.
+- POI types: trailheads, huts, helispots, water sources, gates.
+- **Custom maps**: raster tiles of your operating area for offline use; region maps for segments with POA.
+- Consider hardware trackers on UTVs and the command trailer.
+
+## 7 — Records (SAR pack)
+
+Enable Records and create definitions from the **SAR Mission Pack**: *SAR Mission Summary*, *SAR Segment Debrief* (coverage / POD), *SAR Clue Report* (restricted). Add *Exercise / AAR* for trainings and *ICS 214* from the Incident Support pack for personal activity logs. Preset *Review required* with the operations chief as reviewer. Capture **unit tracking fixes** and **incident chat** as evidence on the mission summary.
+
+## 8 — Readiness
+
+- **Checklists**: *Personal 24-hour pack* (Personnel target, monthly, self-run), *Team cache inventory* (Group, quarterly), *UTV pre-trip* (Unit), *Rope kit inspection* (Serialized equipment, annual, witness).
+- **Inventory**: team cache as a facility with containers; ropes, hardware, GPS units, radios and PLBs as serialized assets with retirement dates as expiry; issue personal gear to members with expected return.
+- **Calendar**: trainings with sign-up sheets, fitness sessions, debriefs.
+- **Trainings**: navigation, radio, ICS refreshers with quizzes for probationary members.
+
+## 9 — Communication
+
+- Chat channels per team; the incident channel is automatic per callout; **urgent** messages for recall.
+- Notifications: *Team leader availability < 2* → coordinator.
+- Workflows: *Call created* → email the sheriff's dispatch a confirmation; *Message sent (poll)* → webhook to a roster sheet.
+- Voice: PTT channels per team where radio coverage is poor.
+
+## First-week checklist
+
+- [ ] Roles match your capability matrix; certifications entered
+- [ ] Custom statuses reflect CP → field → return flow
+- [ ] Test callout by SMS import received by all
+- [ ] Search-area layers loaded on the map and in Responder
+- [ ] SAR Mission Summary definition published; a training mission recorded end-to-end
diff --git a/docs/setup-guides/security-and-facilities.md b/docs/setup-guides/security-and-facilities.md
new file mode 100644
index 0000000..61e4f84
--- /dev/null
+++ b/docs/setup-guides/security-and-facilities.md
@@ -0,0 +1,78 @@
+---
+sidebar_position: 8
+title: Security & Facilities
+---
+
+# Setting Up a Security Company, Campus Security or Facilities Team
+
+For contract security companies with many client sites, campus / healthcare / corporate security departments, and facilities teams that respond to alarms, incidents and service requests. In Resgrid a **client site is a station group**, a **patrol vehicle or post is a unit**, an **incident or request is a call**, and patrol logs and incident reports are **records**.
+
+## 1 — Department settings
+
+| Setting | Value |
+|---|---|
+| 24-hour time | On. |
+| Use branding in emails | On (clients see your logo). |
+| Staffing reset | At shift boundaries → *Off duty*. |
+| Suppress notifications for | *Off duty*. |
+| Mapping settings | Personnel location TTL 15 min. |
+| Modules | Shifts, Checklists, Work orders (Readiness Pro), Inventory, Records, Routes on; Trainings on. |
+| Security policy | SSO with the corporate IdP where available; *Require SSO*; session timeout 720; view users / units **group only** so client sites are isolated. |
+
+## 2 — Types
+
+| Type | Values |
+|---|---|
+| **Unit types** | Patrol vehicle, Foot post, Bike patrol, Mobile supervisor, K9. |
+| **Call types** | Alarm response, Suspicious activity, Trespass, Escort request, Medical, Fire alarm, Access control, Maintenance request, Incident report, Welfare check. |
+| **Priorities** | Routine, Urgent, Emergency. |
+| **Certifications** | Guard licence (with expiry), First aid/CPR, Use of force, Firearms (if armed), Fire warden, Forklift. |
+| **Contact note types** | Site instructions, Key-holder, Alarm code (restricted). |
+
+## 3 — Groups, roles, statuses
+
+- **Organisational group per client**; **station group per site** with the address and a geofence (alarm-response area); site supervisors as group admins.
+- **Roles**: Security officer, Supervisor, Dispatcher / operations centre, Site lead, Armed officer, Fire warden.
+- **Custom statuses** (security template): personnel — On patrol · At post · Responding · On scene · On break · Off duty; staffing — On duty · Off duty · Available for overtime; units (Patrol) — Available · Responding · On site · Out of service.
+
+## 4 — Units and tracking
+
+One unit per patrol vehicle (role *Officer*) and per fixed post; **hardware GPS tracking** on vehicles (source priority above the phone app) so the operations centre always sees them.
+
+## 5 — Calls and dispatch
+
+- Dispatchers use the **Dispatch app**; alarm-centre emails create calls via **email import**; client requests by **text-to-call**.
+- **Contacts** per site: client contact, key-holders, alarm company — with **alert notes** (dogs, access hazards) and gate codes in the [occupancy](../web-app/records/occupancies) record.
+- **Run cards**: *Alarm response* (Urgent + Alarm): Patrol vehicle ×1 closest-unit, auto-dispatch; *Medical on site* adds First-aid role ×1.
+- **Indoor maps** for campuses and large buildings: access points and assembly points searchable in dispatch.
+- **Templates**: Alarm response, Escort, Medical; call-note templates for standard dispositions (*False alarm — reset*, *Owner notified*).
+
+## 6 — Shifts and routes
+
+- **Assigned shifts** per site with rotating patterns; trades within the same site group; workshifts for *each shift* checklists.
+- **Routes**: patrol routes per site with checkpoint stops and geofence radius; officers run them in the Unit app; the end-of-shift *Security Patrol Log* record captures checkpoints and exceptions.
+
+## 7 — Records
+
+From the **Operational report templates** pack: *Security Patrol Log* (Quick entry, prefix PAT, sequence per site group) and *Security Incident Report* (Review required, involved persons restricted). Add *Job/Service Completion* for facilities work. Group-scope Records so clients' reports stay separate; use **report exports** to email a client a nightly patrol summary through a workflow. Legal holds and records requests cover subpoenas.
+
+## 8 — Readiness
+
+- **Checklists**: *Patrol vehicle start-of-shift* (Unit, each shift, reported location required), *Post orders acknowledgement* (Group per site), *Fire extinguisher monthly* (Serialized equipment), *Lighting and camera check* (Group, weekly) with *Create a work order on failure*.
+- **Work orders** (Readiness Pro): *Facility* type for door, camera, lighting faults; business calendar Mon–Fri 08:00–17:00 with response targets per priority; vendor charges for outsourced repairs; spending approval above a threshold.
+- **Inventory**: uniforms, radios and body cameras issued to officers; keys and access cards as serialized assets; vehicle equipment on units.
+
+## 9 — Communication
+
+- Chat: custom channel per client site (group rule) and a supervisors channel; GIFs off; moderation delegated to site supervisors.
+- Notifications: *Patrol unit out of service* → operations; *Checklist missed* → site supervisor.
+- Workflows: *Call closed* → email the client contact a summary from a Records export; *Form submitted (incident statement)* → create a work order via API.
+- **Communication tests** quarterly.
+
+## First-week checklist
+
+- [ ] Client and site groups with geofences; officers assigned; SSO tested
+- [ ] Patrol vehicles as units with trackers
+- [ ] Alarm-response run card tested with *Run Test*
+- [ ] Patrol Log and Incident Report definitions published; group scoping on
+- [ ] Start-of-shift checklist scheduled per vehicle
diff --git a/docs/web-app/account-security.md b/docs/web-app/account-security.md
new file mode 100644
index 0000000..d1f19c5
--- /dev/null
+++ b/docs/web-app/account-security.md
@@ -0,0 +1,69 @@
+---
+sidebar_position: 49
+title: Account Security
+---
+
+# Account Security
+
+Settings that belong to *you* rather than to the department: two-factor authentication, active sessions, username, password and account deletion. All of them live under your **profile dropdown** (your name, top-left).
+
+## Two-factor authentication (2FA)
+
+**Profile dropdown → Two-Factor Authentication.**
+
+
+
+Resgrid supports **authenticator apps (TOTP)** — Google Authenticator, Microsoft Authenticator, Authy, 1Password and similar.
+
+1. Press **Enable Authenticator App**.
+2. Scan the QR code (or enter the key manually) in your app.
+3. Enter the 6-digit code and press **Verify & Enable**.
+4. **Save your recovery codes** somewhere safe. Each code can be used once if you lose your phone.
+
+
+
+At login you will be asked for the current code; tick **Don't ask again on this device for 30 days** on trusted computers. **Regenerate Recovery Codes** when you are running low; **Disable 2FA** requires your current code and resets the authenticator key.
+
+Some operations ask you to **confirm your identity** with a fresh code — revealing [protected data](data-protection), changing security settings, SSO configuration.
+
+:::info Department policy
+A department [security policy](security-permissions#security-policy) can **require 2FA for administrators** (or everyone). If it does, you will be taken to the setup page until it is complete.
+:::
+
+## Active sessions
+
+**Profile dropdown → Two-Factor Authentication → Sessions** (`/User/AccountSecurity/Sessions`).
+
+
+
+Lists everywhere your account is signed in — application / device, approximate network location, started / expires and last active. **Revoke** a single session, **Sign out all other sessions**, or **Sign out everywhere** (including this one). Administrators can also end a member's sessions from the Personnel page, and a department security policy can cap session lifetime.
+
+## Change username / password
+
+- **Change Username** — enter the current username and the new one. Usernames must be unique across the whole Resgrid system.
+- **Change Password** — current password plus the new password twice. Minimum length and complexity follow the department security policy.
+
+Both are audited and end other sessions where the policy requires it.
+
+## Deleting your account
+
+**Profile → Delete Account** (`/User/Account/DeleteAccount`).
+
+- If you are the **account owner** (managing member) of any department you must first transfer ownership in *Department Settings* or delete that department.
+- Deleting clears your personal information and login but does **not** remove department-owned data (calls, records, logs you wrote); that data belongs to the department and its retention rules.
+- Deletion deactivates you in **every** department you belong to, removes your scheduled automations (report deliveries, scheduled status and staffing changes) and stops all notifications.
+
+If you only want to leave one department, ask its administrators to remove you from the Personnel list instead.
+
+## Passkeys and SSO
+
+Departments on the Enterprise tier can sign in with **SSO (SAML / OIDC)** — see [Enterprise SSO](../enterprise/sso-overview). When SSO is enforced, password and 2FA settings are managed by your identity provider.
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/TwoFactor/{Index,Enable2FA,ShowRecoveryCodes,ViewRecoveryCodes,Disable2FA,Verify2FA}`, `/User/AccountSecurity/{ChangeUsername,ChangePassword,Sessions}`, `/User/Account/DeleteAccount` |
+| Login flow | `/Account/LoginWith2fa`, `/Account/LoginWithRecoveryCode` |
+| Session model | Session id + authentication generation claims; revoking bumps the generation so API/BFF tokens minted for that session stop working |
+| Policy | `SessionSecurityConfig` and the department security policy (`/User/Security/SecurityPolicy`) |
diff --git a/docs/web-app/calendar.md b/docs/web-app/calendar.md
index c34ba7d..6b7fb48 100644
--- a/docs/web-app/calendar.md
+++ b/docs/web-app/calendar.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 12
+sidebar_position: 19
title: Calendar
---
# Calendar
-The Calendar module provides event scheduling, RSVP management, recurring event support, all-day and multi-day events, and external calendar sync via iCal feeds. It is managed by the `CalendarController`.
+The **Calendar** holds trainings, meetings, public events, maintenance days, deadlines — anything with a date. Members can **RSVP / sign up**, get reminders, see it in the apps, and subscribe from their phone or Outlook calendar. Scheduled checklist checks and shifts can be overlaid.
+
+**Left menu → Calendar.** Event types (with colours) are managed under **Manage Types**; calendar sync is described in [Calendar sync](../how-tos/calendar-sync).
+
+
## Calendar View
@@ -24,6 +28,8 @@ The main calendar view displays:
**Authorization:** `Schedule_Create` policy
+
+
### Event Fields
| Field | Required | Description |
@@ -103,6 +109,8 @@ The `RemoveFromEvent` action removes an attendee from a calendar event.
Calendar item types provide categorization and color coding.
+
+
### Managing Types
| Action | Authorization | Description |
|--------|---------------|-------------|
@@ -160,8 +168,21 @@ Calendar sync can be enabled or disabled system-wide via the `CalendarConfig.ICa
| `ICalProductId` | `-//Resgrid//Calendar//EN` | PRODID value used in generated iCal files |
| `ICalFeedCacheDurationMinutes` | `15` | How long (in minutes) a feed response can be cached by the subscribing client |
-## Calendar Data Formats
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Volunteer fire** | Types: Training (blue), Business meeting (green), Public event (orange), Work detail; RSVP on trainings so instructors know numbers; reminder 24 h before. |
+| **EMS** | Types: CE class, Skills check, Vehicle service; signup sheets for CE sessions with limited seats. |
+| **SAR** | Types: Training, Callout debrief, Fitness; sign-up sheets for multi-day exercises. |
+| **Emergency management** | Types: Exercise, Public outreach, EOC briefing; share the iCal feed with partner agencies. |
+| **Security / business** | Types: Site visit, Client meeting, Toolbox talk; lock creation to supervisors via permissions. |
+## Technical reference
+
+`CalendarController`; routes `/User/Calendar/{Index,New,Edit,View,SignupSheet,Types,NewType,EditType,EditCheckIn}`; permission `CreateCalendarEntry`, `UseCalendarSync`; events `CalendarEventAddedEvent`, `CalendarEventUpdatedEvent`; iCal feed `api/v4/Calendar/*` (see [Calendar export API](../api/calendar-export)).
+
+### Calendar Data Formats
### FullCalendar v6 Format
The `GetV2CalendarEntriesForCal` endpoint returns events in FullCalendar v6-compatible JSON format:
- Start/end times in ISO format
@@ -199,8 +220,7 @@ The subscription feed returns all department calendar events as a single `.ics`
The `GetMapDataForItem` endpoint geocodes a calendar item's location and returns lat/lon coordinates for map display.
-## Data Endpoints
-
+### Data Endpoints
| Endpoint | Purpose |
|----------|---------|
| `GetDepartmentCalendarItems` | All calendar items as JSON |
@@ -211,8 +231,7 @@ The `GetMapDataForItem` endpoint geocodes a calendar item's location and returns
| `ActivateCalendarSync` | Generate a calendar sync subscription URL |
| `RegenerateCalendarSync` | Regenerate the sync key (invalidates old URL) |
-## Interactions with Other Modules
-
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Groups** | Events can target specific groups |
diff --git a/docs/web-app/call-checkin-timers.md b/docs/web-app/call-checkin-timers.md
index b8f0585..1b0649e 100644
--- a/docs/web-app/call-checkin-timers.md
+++ b/docs/web-app/call-checkin-timers.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 40
+sidebar_position: 6
title: Call Check-In Timers
---
@@ -7,6 +7,8 @@ title: Call Check-In Timers
The Call Check-In Timer system is an accountability and safety feature that tracks whether personnel, units, or operational roles have checked in within required time intervals while a call (incident) is active. Timers visually escalate through **Green / Warning / Critical** states, helping incident commanders maintain situational awareness and comply with safety protocols such as NFPA 1561 PAR checks.
+
+
**Navigation:** Dispatch → View Call → Check-In Timers panel
---
@@ -182,8 +184,17 @@ All check-in timer configuration changes are recorded in the department's audit
---
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Fire** | PAR every 20 minutes on Structure fire types; Rehab timer 45 minutes; IC timer 15 minutes. |
+| **Hazmat / industrial** | Hazmat exposure timer per unit type with warning at 20 of 30 minutes. |
+| **SAR** | Sector rotation timers of 2 hours for field teams; check-ins with GPS from the Unit app. |
+
+## Technical reference
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Dispatch & Calls** | Check-in timers are enabled on calls at creation or update; timer statuses display on the View Call page |
diff --git a/docs/web-app/chat.md b/docs/web-app/chat.md
new file mode 100644
index 0000000..c842b6a
--- /dev/null
+++ b/docs/web-app/chat.md
@@ -0,0 +1,107 @@
+---
+sidebar_position: 32
+title: Chat & Assistant
+---
+
+# Chat, Assistant & Moderation
+
+Resgrid includes a realtime **chat** system — direct messages, group chats, department and station channels, and per-incident channels — plus an **Assistant** (chatbot) that answers questions and takes actions in plain language, and a **moderation** console for administrators. Chat is available on the web and in all four mobile apps (Responder, Unit, Dispatch, Incident Command) with the same channels and history.
+
+Feature flag: `Chat.System` (free for all plans; used for staged rollout). If chat is missing, ask your administrator or Resgrid support to enable it.
+
+
+
+## Where to find it
+
+- **Chat bubble** at the bottom-right of every web page opens a floating chat panel.
+- **Profile dropdown → Chat** opens the full-page chat.
+- **✨ Assistant** button next to the chat bubble opens the Assistant drawer.
+- **Department dropdown → Chat Moderation** (department and group administrators).
+
+## Channels
+
+| Channel type | Who is in it | Created by |
+|---|---|---|
+| **Department channel** | Everyone in the department | Automatically |
+| **Station / group channels** | Members of that station or group | Automatically for every group |
+| **Direct messages** | You and one other member — or a **unit** (the unit's crew receives it) | Anyone |
+| **Group chats** | An ad-hoc set of members | Anyone |
+| **Custom channels** | Rules by group, role or user (any rule matching admits the member) | Administrators |
+| **Incident channels** | Everyone dispatched to a call; plus one channel per command-board lane and a **Command** channel restricted to the Incident Commander and active incident role holders | Automatically on call creation; archived on close |
+| **Assistant** | You and the Assistant | Automatically |
+
+Identities: people, **units** ("Engine 6" — the human sender is always recorded for audit), the **Incident Commander** role, and the Assistant.
+
+## Messaging features
+
+- Text, emoji, **images** (attachments are scanned), **GIFs** (safe-for-work rating enforced), link previews, **shared locations**.
+- **Threads** (reply in thread, optionally also send to channel), **reactions**, **@mentions**, **pins**.
+- **Urgent messages** with per-user acknowledgement — a unit audience expands to its crew; any crew member's acknowledgement satisfies the unit. Urgent messages override mute when the department setting allows.
+- Read / delivered indicators, typing and presence.
+- **Push notifications** follow the per-app routing matrix: mentions, DMs and urgent messages push; channel chatter does not push to a channel you have open on screen.
+- Muting per channel; message editing with history; moderator deletion leaves a tombstone.
+
+## The Assistant
+
+The Assistant is a conversational helper inside chat (and, when configured, over SMS and other messaging platforms). It understands commands such as *"set me responding"*, *"who is on shift tonight?"*, *"what calls are active?"*, *"page Station 2"*, and — when allowed — *"dispatch Engine 1 to the structure fire on Pine Ridge"*. Anything it does not recognise as a command is answered by a guard-railed language model that only has access to your department's data through Resgrid's own permissions.
+
+The Assistant conversation is **text only**: attachments, reactions, pins and threads are disabled there.
+
+### Assistant settings
+
+**Department dropdown → Assistant** (administrators):
+
+| Setting | Meaning |
+|---|---|
+| **Enable Assistant** | Allow members of this department to use the Assistant. |
+| **Allowed platforms** | Comma-separated: `WebChat`, `SmsTwilio`, `SmsSignalWire`, `Discord`, `Slack`, `Telegram`, `WhatsApp`, `Teams`, `Signal` — or `*` for all. |
+| **Allow dispatch via Assistant** | Authorized users may create or dispatch calls through it. |
+| **Confirm status changes** | Require an explicit confirmation before destructive or status-changing actions. |
+| **Confirm phone linking** | Require a one-time *Reply YES* before linking an SMS number to a matching account. |
+| **Proactive notifications** | Let the Assistant push calls and reminders to linked users. |
+| **Messages / user / minute, Messages / dept / minute** | Rate limits (blank = system default). |
+| **Department AI / LLM provider** | Optional OpenAI-compatible endpoint, model and API key so the Assistant runs on *your* provider. The key is encrypted at rest and never displayed. |
+
+
+
+## Moderation
+
+**Department dropdown → Chat Moderation.** Department administrators see the whole department; group administrators see their group's channels.
+
+
+
+| Tab | What it does |
+|---|---|
+| **Requests** | Pending reports from members (reason: inappropriate content, harassment, spam, sensitive information, policy violation, other). Open one to see the item, the original evidence (retained even if the author edits or deletes), and the audit trail. **Remove content** or **Complete — no action**, optionally with a note sent to the reporters. |
+| **Reports** | Search new and completed requests by the user who added the content or who reported it, content type and date. |
+| **Chat controls** | Mute or ban a user in a channel, lock / unlock or archive a channel, delete messages. Every action is written to an immutable moderation log mirrored to the department audit log. |
+| **Chat settings** | Allow image attachments, allow GIFs, allow location sharing, urgent messages override mute, Assistant enabled, **message retention (days, 0 = forever)**, maximum attachment size (MB). |
+| **Chat exports** | Request a ZIP export (JSON + CSV transcripts including identities, edit history and the moderation log) for a date range — for records requests, HR or legal. Downloads are audited. |
+
+Members report a message from its menu (**Report for moderation**) and can check the report's status afterwards. Reports can also be raised on internal messages, call notes and call images.
+
+## Records integration
+
+Selected incident-channel messages can be captured as **evidence** on a Record (see [Records → Evidence](records/authoring#evidence)) — the capture is a checksummed snapshot, so later edits or deletions do not change what was preserved.
+
+## Setup examples
+
+| Department | Suggested setup |
+|---|---|
+| **Volunteer fire** | Keep department + station channels; encourage DMs to units for on-scene coordination; retention 365 days; Assistant enabled with *Confirm status changes* on. |
+| **EMS** | Disable image attachments in channels where PHI could appear, or enrol in ADP; retention 30 days; incident channels for handoff notes. |
+| **Emergency management / EOC** | Custom channels per ESF with role rules; urgent messages for activations; export transcripts after each activation for the after-action file. |
+| **Security / business** | Custom channels per client site by group rule; GIFs off; moderation delegated to site supervisors as group admins. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Controllers | `ChatController` (`Index`; `Chatbot` redirects to Index), `ModerationController`, `ChatbotSettingsController` |
+| Web components | `rg-chat`, `rg-assistant`, `rg-chat-page`, `rg-chatbot`, `rg-chat-moderation` (`Areas/User/Apps`) |
+| Feature flags | `Chat.System`; `Chatbot.TwilioTextIntegration` routes inbound SMS through the Assistant pipeline |
+| Realtime | Eventing hub `ChatEvent` (RabbitMQ topic); presence TTL configurable in `ChatConfig` |
+| API | `api/v4/Chat/*`, `api/v4/Chatbot/SendChatMessage` |
+| Workers | Chatbot message logic, retention purge, export ZIP builder |
+| Data | Migrations M0104–M0109; `ChatModerationActions` mirrored to `AuditLog` |
+| Design | `int-Coordination/docs/architecture/chat-system-design.md` |
diff --git a/docs/web-app/checklists.md b/docs/web-app/checklists.md
new file mode 100644
index 0000000..b15a9ed
--- /dev/null
+++ b/docs/web-app/checklists.md
@@ -0,0 +1,207 @@
+---
+sidebar_position: 26
+title: Checklists
+---
+
+# Checklists
+
+Checklists are the daily, per-shift, weekly and periodic checks your crews already do on paper — apparatus checks, start-of-shift inspections, personal gear checks, facility walk-throughs, safety audits. Resgrid lets you build them once, schedule them, hand them to the right people, and keep a tamper-evident record of what was checked, when, by whom, and with what evidence.
+
+:::tip Free for every department
+Checklists are included with every Resgrid plan. The optional **Work Orders / Maintenance** follow-up (turning a failed check into a repair ticket automatically) is part of the paid **Readiness Pro** add-on — see [Work Orders](work-orders).
+:::
+
+
+
+## Where to find it
+
+**Left menu → Checklists.** The module has five tabs across the top:
+
+| Tab | What it is for |
+|---|---|
+| **Checklists** | The library of checklist definitions your department owns. Create, edit, publish and retire here. |
+| **Due checks** | Everything that is scheduled or overdue for the next seven days — the "what do I need to do today" list. |
+| **Checklist compliance report** | Completion rate, on-time rate and missed-deadline trend for a date range. |
+| **Checklist templates** | Ready-made starting points (unit checks, SCBA, PPE, station, vehicle, safety audit …) you can copy and adapt. |
+| **Checklist reminders** | Department-wide reminder and escalation rules. |
+
+If the Checklists item is missing from the left menu, an administrator has turned the module off under **Department Settings → Module Settings**, or the `Checklists.System` feature flag is not enabled for your department (self-hosted installs).
+
+## Key concepts
+
+- **Definition** — the checklist itself: sections, items, answer types, scoring rules. Definitions are versioned. A **draft** can be edited freely; **publishing** creates an immutable version that runs are recorded against. Publishing a new draft later creates version 2, 3, … Existing runs always keep the version they were completed on.
+- **Target** — what a run is carried out *against*: the whole **Department**, a **Unit**, a **Group / station**, a **Person**, or a **serialized piece of equipment** from Inventory. The target type is fixed when you create the definition.
+- **Run** — one completed (or in-progress) instance of a checklist against a target, with answers, notes, photos, signatures and an optional witness.
+- **Schedule** — a recurrence rule (each shift, daily, weekly, monthly, quarterly, six-monthly, annually) that generates **occurrences** with a completion window and an assignee.
+- **Occurrence / check** — one scheduled instance that is *Scheduled*, *In progress*, *Completed*, *Missed*, *Excused* or *Cancelled*.
+
+## Building a checklist
+
+### Start from a template
+
+**Checklists → Checklist templates** lists the built-in library. Use **Find a template** to filter, **Preview template** to read every item, then **Use this template** to copy it into a new draft you own. Templates are generic — adapt them to your equipment, manufacturer procedures and local requirements before publishing.
+
+
+
+### Or start from scratch
+
+**Checklists → New checklist** opens the editor.
+
+
+
+**Checklist settings**
+
+| Field | What to enter |
+|---|---|
+| **Checklist name** | Shown on the due list and in reports — make it recognisable at a glance (`Engine 1 Daily Check`, `SCBA Weekly`). |
+| **Instructions** | Shown at the top of every run. Never include patient data. |
+| **Category** | Start of shift, Unit check, Personal gear, Annual review, Facility, Safety audit, Equipment check or Other. Used for filtering and reporting. |
+| **Target type** | Department, Unit, Group / station, Personnel or Serialized equipment. Cannot be changed after the first publish. |
+| **Passing score (%)** | The threshold a run must reach to be **Passed**. Leave blank if you only care about individual item results. |
+| **Require reported location** | Forces the person running the check to capture GPS coordinates (or enter them manually). Useful for remote sites and mobile crews. |
+| **Require a different authenticated member to witness** | A second logged-in member must independently verify the submitted answers and evidence before the run is complete. Use for controlled substances, SCBA and anything with regulatory weight. |
+| **Create a Readiness Pro work order on failure** | (Readiness Pro) Automatically raises a work order when the run fails, with a chosen priority. Can also **place the unit out of service** or **place the equipment out for repair**. |
+
+**Sections and items**
+
+Group items into sections (`Cab`, `Pump panel`, `Compartment 1` …). For every item you choose:
+
+| Option | Meaning |
+|---|---|
+| **Answer type** | Pass / Fail, Yes / No, Checkbox, Numeric reading, Quantity, Free text, Select list, Date, Photo or Signature. |
+| **Passing answer / range / choice** | What counts as a pass for that item (e.g. tyre pressure between 95 and 110 psi; select list must equal `Full`). |
+| **Critical failure overrides the score** | If this item fails the whole run fails regardless of score. Use for brakes, SCBA low-air alarm, AED pads etc. |
+| **Allow N/A with a reason** | Lets the crew skip the item (a reason is required). |
+| **Require a note / photo on failure** | Forces evidence when something is wrong. |
+| **Score weight** | Relative weight in the percentage score. `0` excludes the item from the score. |
+| **Show only when / Also required when** | Simple conditional logic: show or require this item only when an earlier item has a given answer (e.g. show *Describe damage* only when *Body damage?* is `Yes`). |
+
+Save as **draft** as often as you like. When it is ready, open the checklist and choose **Publish draft**. Publishing is what makes the checklist schedulable and runnable.
+
+### Editing and retiring
+
+Open any checklist from the list to see its **published version**, its **draft** (if one exists), **history** of runs and its **schedules**.
+
+- **Edit draft** changes the draft only; the published version keeps running until you publish again.
+- **Retire** stops new runs and cancels future scheduled checks. History is kept.
+- **Delete draft** discards unpublished changes.
+
+## Running a checklist
+
+Open the checklist and press **Start checklist**, choose the target (which unit, station, person or asset), and work through the items.
+
+
+
+- Answer every applicable item. N/A requires a reason.
+- **Save progress** to come back later; **Submit checklist** locks the answers. Submitted answers and evidence cannot be changed — corrections are made with a new run.
+- Photos (PNG/JPEG up to 10 MB) are virus-scanned before they are accepted.
+- Signatures can be drawn or uploaded.
+- If the definition requires a **witness**, the run moves to **Awaiting witness**. Share the run's page link with the second member; they sign in, review, and press **Attest and complete**.
+
+Crews normally run checks from the **Unit** or **Responder** mobile apps; the web page is the same run engine and can be used from a station computer or tablet.
+
+### Results
+
+The run detail page shows every item, answer, note and evidence file plus author, submitted time, witness and reported location. **Export JSON** and **Print** are available. Runs that fail show which items failed and whether a critical item overrode the score.
+
+
+
+## Scheduling
+
+From a published checklist choose **Schedules → New schedule**.
+
+
+
+| Setting | Notes |
+|---|---|
+| **Frequency** | Each shift, Daily, Weekly, Monthly, Quarterly, Every six months, Annually. |
+| **Time zone** | The zone the local times are read in (defaults to the department time zone). |
+| **Local times** | Up to eight `HH:mm` times per day, comma separated. A skipped clock time (DST) moves forward; a repeated time occurs once. |
+| **Days for weekly checks** | Which weekdays a weekly check opens. |
+| **Day of month / Starting month** | For monthly or rarer checks. Short months use their last day; the starting month anchors quarterly, six-monthly and annual checks. |
+| **Workshift for checks each shift** | For *Each shift* checks, uses the recorded start of a [Workshift](workshifts). Otherwise the local times apply daily. |
+| **Completion window (minutes)** | How long the crew has once a check opens. After the window closes the check counts as **Missed**. |
+| **Assigned to** | *Automatic routing* sends the check to whoever holds the target (the unit's crew, the station's members, the person). Or pick a specific **Person**, **Personnel role**, **Group or station** or **Unit crew**. |
+| **Start / End date, Paused, Enabled** | Control the life of the schedule. Pausing cancels unstarted checks. |
+
+Saving a schedule pins the *current* published version; changing the schedule replaces future unstarted checks.
+
+### Due checks
+
+**Checklists → Due checks** lists the next seven days plus anything unfinished. Each row shows the target, who it is assigned to, when it is scheduled and when the window ends. **Open check** starts the run; **Excuse check** records a reason and marks it *Excused* (it stays on the record and is excluded from the compliance rate).
+
+
+
+Scheduled checks also appear on the department [Calendar](calendar) when *Readiness checks* is ticked in the calendar filter.
+
+## Reminders and escalation
+
+**Checklists → Checklist reminders** (administrators).
+
+
+
+| Setting | Effect |
+|---|---|
+| **Enable checklist reminders** | Master switch. Reminders apply to checks that start after this is turned on. |
+| **Minutes before the due time** | Send a reminder this many minutes before a check opens (0 disables). |
+| **Notify responsible personnel of missed checks** | A message when the window closes without completion. |
+| **Combine pending reminders into digests** | One message per person instead of one per check. |
+| **Send a digest at shift start / Daily digest time** | When digests go out. |
+| **Escalate to department administrators after N minutes overdue** | Blank disables escalation. |
+
+Messages contain a sign-in link and respect each person's [notification preferences](profile-account) (push, SMS, email). Checklist content is never included in the message.
+
+## Compliance report and readiness packet
+
+**Checklist compliance report** counts *expected*, *completed*, *on-time*, *missed* and *excused* checks in a period (up to 93 days) and charts the missed-deadline trend. Only elapsed scheduled windows count toward the rate; on-demand runs appear in history only. Filter by target, export CSV, print, or **schedule the report** to be emailed (protected data is never emailed — the recipient gets a secure link).
+
+
+
+The **Readiness packet** assembles evidence of readiness *at the time of a call*: dispatched units, checklist results from the 30 days before the call, equipment issued at call time and (with Readiness Pro) work-order state. It downloads as a PDF with a manifest. Use it for after-action reviews, insurance and legal requests.
+
+
+
+## Permissions
+
+Configure under **Department → Security & Permissions**:
+
+| Permission | Default | Grants |
+|---|---|---|
+| **Manage checklists** | Department admins | Create, edit, publish, retire definitions; manage schedules; excuse checks; edit reminders. |
+| **View checklist results** | Department admins | View runs completed by other members. Everyone can always see their own runs. |
+
+Running a check requires being assigned (automatic routing or explicit assignment) — a member cannot run a check assigned to someone else.
+
+## Setup examples
+
+| Department type | Suggested checklists |
+|---|---|
+| **Volunteer / career fire** | *Apparatus daily* per engine/ladder (Unit target, each shift or daily, critical items for brakes/lights/pump), *SCBA weekly* (Serialized equipment, witness required), *Station facility weekly* (Group target). |
+| **EMS** | *Ambulance start-of-shift* (Unit, each shift, drug box seals as critical, narcotics count with witness), *Monitor/defib daily* (Serialized equipment), *Controlled substance count* (witness + photo). |
+| **Search & rescue** | *Personal 24-hour pack* (Personnel target, monthly, self-run), *Team cache inventory* (Group, quarterly), *Vehicle/ATV pre-trip* (Unit). |
+| **Emergency management / EOC** | *EOC readiness* (Department, monthly: generators, comms, supplies), *Shelter site inspection* (Group per site, annual). |
+| **Private security / facilities** | *Patrol vehicle start-of-shift* (Unit, each shift with reported location required), *Post orders check* (Group per site), *Fire extinguisher monthly* (Serialized equipment). |
+| **Industrial / plant ERT** | *Rescue equipment weekly* (Serialized equipment, critical items), *Safety audit* (Group, monthly, photo on failure), with **Create a work order on failure** enabled so defects flow straight to maintenance. |
+
+## Tips
+
+- Keep the daily check short; put rare items on a weekly or monthly schedule so the daily one takes two minutes.
+- Use **Critical** sparingly — only for items that genuinely take the unit out of service.
+- Turn on **Require a photo on failure** for anything you will need to show an auditor or a mechanic.
+- Publish, then schedule. Schedules cannot be created against a draft.
+- Reminders only apply to checks generated after you turn them on.
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Controller | `ChecklistsController` (partials: `ChecklistsSchedulingController`, `ChecklistRemindersController`, `ChecklistReportingController`) under `Areas/User` |
+| Routes | `/User/Checklists/{Index,Templates,Template,New,Edit,Detail,Run,CompletionDetail,Evidence,Schedules,EditSchedule,Due,Occurrence,Reminders,Compliance,ReadinessPacket}` |
+| Feature flag | `Checklists.System` (seeded off by migration M0189; enable per department or globally) |
+| Module switch | `DepartmentModuleSettings.ChecklistsDisabled` |
+| Permissions | `PermissionTypes.ManageChecklists` (112), `PermissionTypes.ViewChecklistResults` (113) |
+| Services | `IChecklistsService`, `IReadinessAccessService.CanUseChecklistsAsync` |
+| Workflow events | `ChecklistCompleted`, `ChecklistFailed`, `ChecklistMissed`, `ChecklistScheduleChanged`, `ChecklistOccurrenceSkipped` — see [Workflows](workflows) |
+| Reports | `/User/Reports/ChecklistComplianceReport` (also schedulable from **Profile → Reporting**) |
+| API | `api/v4/Checklists/*` used by the Unit and Responder apps |
+| Protected data | When the department is enrolled in [Advanced Data Protection](data-protection), checklist answers and evidence are stored encrypted and the page asks you to *Verify and open* before displaying them. |
diff --git a/docs/web-app/command-definitions.md b/docs/web-app/command-definitions.md
index 81f863f..f14d500 100644
--- a/docs/web-app/command-definitions.md
+++ b/docs/web-app/command-definitions.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 26
+sidebar_position: 45
title: Command Definitions
---
@@ -7,6 +7,8 @@ title: Command Definitions
Command Definitions structure incident command assignments following ICS (Incident Command System) principles. The module is managed by the `CommandController`.
+
+
## Command List
**Authorization:** `Command_View` policy
@@ -57,8 +59,18 @@ When the `ForceRequirements` (lock) flag is set, the system enforces that the as
- **No Delete functionality** — Commands cannot be deleted through the UI
- **Synchronous save** — Uses synchronous `Save` method (unlike most other controllers)
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Fire** | ICS structure: IC, Safety, Operations (Divisions A/B/C), RIT, Rehab, Staging, Water supply — as a template for structure fires. |
+| **SAR** | IC, Operations, Planning, Logistics, Search teams 1–6, Base camp; templates per mission type. |
+| **Emergency management** | Full ICS/EOC organisation with sections and ESFs; used by the Incident Command app. |
+| **Events / security** | Event command: IC, Security ops, Medical, Traffic, Comms. |
+
+## Technical reference
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Dispatch** | Commands can be associated with specific call types |
diff --git a/docs/web-app/communication-tests.md b/docs/web-app/communication-tests.md
index b333eaa..7c079dd 100644
--- a/docs/web-app/communication-tests.md
+++ b/docs/web-app/communication-tests.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 39
+sidebar_position: 30
title: Communication Tests
---
@@ -7,6 +7,8 @@ title: Communication Tests
The Communication Tests module allows department administrators to verify that communication channels (SMS, Email, Voice, and Push Notifications) are working correctly for all members of their department. It answers the question: *"If we needed to reach everyone right now, could we?"*
+
+
Admins define tests, run them on-demand or on a schedule, and then review per-user, per-channel reports showing who was reachable and who responded.
**Authorization:** Department Admins only. Access is controlled via `ClaimsAuthorizationHelper.IsUserDepartmentAdmin()`.
@@ -223,3 +225,11 @@ The Communication Tests feature is also available via the Resgrid API v4.
:::note
The `EmailConfirm` and `VoiceWebhook` endpoints are publicly accessible (no authentication required) since they are called by end-users clicking email links or by telephony providers delivering DTMF responses.
:::
+
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Volunteer fire** | Monthly all-call test on the first Monday at 18:30 (push + SMS + email), 15-minute response window; review non-responders and fix their contact verification. |
+| **EMS / career** | Quarterly test of voice alerting only. |
+| **CERT / SAR** | Before each season: full-channel test to every member; follow up unreachable members. |
diff --git a/docs/web-app/connect.md b/docs/web-app/connect.md
index 140c725..9a7df77 100644
--- a/docs/web-app/connect.md
+++ b/docs/web-app/connect.md
@@ -1,11 +1,11 @@
---
-sidebar_position: 34
+sidebar_position: 35
title: Connect
---
# Connect
-The Connect module manages the department's public-facing profile, enabling community engagement and inter-department discovery. It is managed by the `ConnectController`.
+The Connect module manages the department's public-facing profile, enabling community engagement and inter-department discovery.
## Department Profile
@@ -93,8 +93,17 @@ The `GetPostsList` endpoint returns all articles as JSON with:
- Expiry information
- Creator's full name
-## Interactions with Other Modules
+## Setup examples
+| Department type | How to set it up |
+|---|---|
+| **Volunteer fire** | Public profile with recruitment posts and event announcements; accept public messages for non-emergency enquiries. |
+| **CERT / community groups** | Posts for preparedness tips and class schedules. |
+| **Business** | Usually leave Connect disabled. |
+
+## Technical reference
+
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Department** | Department data used for profile |
diff --git a/docs/web-app/contacts.md b/docs/web-app/contacts.md
index 1bff8ac..4f178d8 100644
--- a/docs/web-app/contacts.md
+++ b/docs/web-app/contacts.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 19
+sidebar_position: 12
title: Contacts
---
# Contacts
-The Contacts module manages external contacts (people and organizations) with category organization, notes, and address management. It is managed by the `ContactsController`.
+**Contacts** are the people and organisations *outside* your department that you deal with on calls and in business: property owners, key-holders, businesses, mutual-aid agencies, vendors, patients' next of kin, clients. Contacts carry addresses, phone numbers, **notes** (including *alert notes* that pop up when the contact is attached to a call), attachments, categories and — for premises — legacy **pre-plan** data.
+
+**Left menu → Contacts.** Categories and contact note types are managed from the page and under **Department → Types**. Suppliers in [Inventory purchasing](inventory#purchasing) and occupancies in [Records](records/occupancies) link to contacts.
+
+
## Contact List
@@ -29,6 +33,8 @@ The system supports two contact types:
**Authorization:** `Contacts_Create` policy
+
+
### Contact Fields
| Field | Required | Description |
@@ -81,6 +87,8 @@ Creates `AuditEvent` on deletion.
### Adding Notes
+
+
Notes can be added to contacts with:
| Field | Description |
@@ -122,8 +130,22 @@ The `GetCallsJson` endpoint returns all calls linked to a contact with:
- Priority name and color
- Timestamp
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Fire** | Categories: Key holders, Businesses, Mutual aid, Vendors; alert notes for aggressive dogs, oxygen in use, access issues; pre-plan data moves to Records occupancies when enabled. |
+| **EMS** | Categories: Facilities (nursing homes with charge-nurse numbers), Hospitals, Frequent patients (with ADP enrolled). |
+| **SAR** | Categories: Agencies (sheriff, park service), Landowners, Helicopter providers, Subjects (restricted). |
+| **Emergency management** | Categories: ESF partners, Shelter operators, Utilities, Media; distribution lists built from contacts. |
+| **Security** | Categories: Clients, Site contacts, Alarm companies, Police liaison; per-client visibility via group scoping. |
+| **Delivery / transit** | Customers and stops as contacts; link to route stops. |
+
+## Technical reference
+
+`ContactsController`; routes `/User/Contacts/{Index,Add,View,Edit,Delete,Categories,AddCategory,EditCategory,Preplan,Attachments}?contactId=`; permissions `ContactView`, `ContactEdit`, `ContactDelete`, `ViewProtectedContactData`; contact details are ADP-protected fields.
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Dispatch** | Contacts linked to calls; alert notes displayed during dispatch |
diff --git a/docs/web-app/custom-maps.md b/docs/web-app/custom-maps.md
index cd44968..394d01f 100644
--- a/docs/web-app/custom-maps.md
+++ b/docs/web-app/custom-maps.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 11
+sidebar_position: 14
title: Custom Maps
---
@@ -7,6 +7,8 @@ title: Custom Maps
Custom Maps allow departments to upload their own map images — floor plans, venue layouts, campus schematics, satellite imagery, or tactical overlays — and overlay them on the standard Resgrid map. Polygon zones drawn on those images resolve to human-readable locations (e.g., "Building 1, Room 405a") that can be used as call locations, pre-plan attachments, and real-time personnel overlays.
+
+
Custom Maps are designed for:
- **Fire departments** — building pre-plans, high-rise floor plans, industrial facility schematics
- **Law enforcement / security** — venue layouts, campus maps, event perimeters, gate/checkpoint configurations
@@ -404,3 +406,12 @@ Zone notifications extend the standard Resgrid notification system and are deliv
| Share link expired | Regenerate from the Share Map panel; expired links cannot be extended |
| Import failed — "invalid GeoJSON" | Validate the GeoJSON at [geojson.io](https://geojson.io) before importing |
| Indoor personnel not appearing on floor | Confirm the indoor positioning source is sending floor-level data to the Resgrid location API |
+
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Fire** | Georeferenced map-book pages and hydrant maps as raster layers; district grids as region maps. |
+| **SAR** | Search-area maps from CalTopo exported as tiles; segment regions with probability of area. |
+| **Events / venues** | Site plans for large events with staging and medical tents as regions. |
+| **Industrial** | Plant site plans with process-unit regions. |
diff --git a/docs/web-app/custom-statuses.md b/docs/web-app/custom-statuses.md
index a079bd3..343335c 100644
--- a/docs/web-app/custom-statuses.md
+++ b/docs/web-app/custom-statuses.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 21
+sidebar_position: 11
title: Custom Statuses
---
# Custom Statuses
-The Custom Statuses module allows departments to define their own personnel statuses, staffing levels, and unit states. It is managed by the `CustomStatusesController`.
+**Custom statuses** replace the built-in status words with your own. There are three sets: **personnel statuses** (*Responding*, *On scene*, *Available at station* …), **staffing levels** (*Available*, *On duty*, *Off duty*, *Light duty* …) and **unit statuses** per unit type (*En route*, *On scene*, *Transporting*, *Out of service* …). Each status has a colour, whether it needs a destination (a station or a call), what it counts as (responding / available), and how it looks on the apps and the Big Board.
+
+**Department menu → Custom Statuses.** Start from a **template** (fire, EMS, SAR, security …) and adjust.
+
+
## Overview
@@ -31,6 +35,8 @@ Define custom availability levels for personnel (replaces default levels like Av
**Authorization:** `CustomStates_Create` policy
+
+
### State Set Configuration
| Field | Required | Description |
@@ -110,8 +116,22 @@ When no custom states are defined, the system provides built-in defaults:
### Default Unit Statuses
13 built-in statuses from Available through Enroute.
-## JSON API Endpoints
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Volunteer fire** | Personnel: Standing by, Responding to station, Responding to scene, On scene, Available at station, Not responding. Staffing: Available, Unavailable, On call. Units (Engine/Ladder/Rescue): In quarters, En route, On scene, Available, Out of service. |
+| **EMS** | Units (Medic): Available, En route, On scene, Transporting, At hospital, Returning, Out of service; personnel: On duty / Off duty. |
+| **SAR** | Personnel: Available, Responding to CP, At CP, Deployed in field, Returned; units (Team): Staging, Searching, Found, Returning. |
+| **Emergency management** | Personnel: EOC activated, Remote, Off; units minimal. |
+| **Security** | Personnel: On patrol, At post, Responding, Break, Off duty; units (Patrol): Available, Responding, On site, Out of service. |
+| **Delivery / transit** | Units (Vehicle): Loading, En route, Delivering, Returning, Off duty. |
+## Technical reference
+
+`CustomStatusesController`; routes `/User/CustomStatuses/{Index,Templates,New,Edit,EditDetail,Delete}?type=1|2|3`; model `CustomState` / `CustomStateDetail` (`DetailType`: none / station / call destination); JSON endpoints `GetPersonnelStatusesForDepartment`, `GetPersonnelStaffingLevelsForDepartment`, `GetUnitStatusesLevelsForDepartment?unitTypeId=`.
+
+### JSON API Endpoints
These endpoints are **consumed by views throughout the application** for building dynamic status dropdowns:
| Endpoint | Purpose |
@@ -123,8 +143,7 @@ These endpoints are **consumed by views throughout the application** for buildin
All endpoints support an `includeAny` parameter to add an "Any" option to the list.
-## Interactions with Other Modules
-
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Dashboard** | Custom statuses and staffing levels displayed on main dashboard |
diff --git a/docs/web-app/dashboard.md b/docs/web-app/dashboard.md
index 9b73e2b..979eccd 100644
--- a/docs/web-app/dashboard.md
+++ b/docs/web-app/dashboard.md
@@ -1,143 +1,61 @@
---
-sidebar_position: 2
+sidebar_position: 3
title: Dashboard
---
# Dashboard
-The Dashboard is the main operations hub of Resgrid, providing a real-time overview of department activity, personnel status, and active calls. It is served by the `HomeController`.
+The **Dashboard** is the home page after you sign in: the live roster with everyone's status and staffing, your own quick-action buttons, and the department's vital signs. Officers and dispatchers keep it open on a station screen; members use it to set themselves available or responding.
-## Accessing the Dashboard
+
-Navigate to **User → Dashboard** after logging in. This is the default landing page for the User Area.
+## What is on it
-## Features
+| Panel | What it shows |
+|---|---|
+| **Personnel** | Every member you are allowed to see, grouped by station/group (or sorted by name — *Department Settings → Sorting*). Each row: name, **staffing** (Available / Unavailable / On shift …), **status** (Standing by / Responding / On scene …), ETA, roles, the time of the last change, and two dropdowns to change the person's status or staffing. **Reset group to Standing By** clears a group after an incident. |
+| **Actions** | Your own status buttons — Responding, Not responding, Standing by, On scene, or your department's custom statuses. Statuses that need a destination (a station or an active call) open a picker. |
+| **Staffing level** | Set your own staffing with an optional note. |
+| **Department info** | Department ID and code (members need the code to join from the apps), text-to-call number, plan warnings. |
+| **Top bar** | Unread messages and active-call counts; the active-calls icon lists the top calls with quick links. |
-### Personnel Status Overview
+Everything updates in real time through the eventing hub — no refresh needed.
-The dashboard displays a comprehensive status table showing all department personnel grouped by their station/group assignment.
+## Personnel status vs staffing
-**How it works:**
-1. The system loads all action logs (current status) and user states (staffing levels) for the department
-2. Personnel are grouped by their `DepartmentGroup` (station) assignment
-3. Ungrouped personnel are shown in a separate section
-4. The display respects the **authorization visibility matrix** — users only see personnel they have permission to view
+| | Status ("what am I doing right now") | Staffing ("can I be counted on") |
+|---|---|---|
+| Defaults | Standing By, Not Responding, Responding, On Scene, Available Station, Responding to Station, Responding to Scene | Available, Delayed, Unavailable, Committed, On Shift |
+| Custom | [Custom personnel statuses](custom-statuses) — colour, text, whether a destination is required, whether it counts as *responding* | [Custom staffing levels](custom-statuses) |
+| Changed by | The member (apps, web, text, Assistant), officers with permission, dispatch (auto-set on shift dispatch), scheduled status changes | The member, officers, [staffing schedules](profile-account#staffing-schedules), the daily **staffing reset** in Department Settings |
-**Sorting Options:**
-Personnel can be sorted by the department's configured sort order:
-- **Default** — System default ordering
-- **First Name** — Alphabetical by first name
-- **Last Name** — Alphabetical by last name
+Tip: **staffing** feeds availability counts and low-availability [notifications](notifications); **status** feeds the call page and the Big Board.
-Additionally, a **status weight sort** can be applied that prioritizes personnel by their current status severity.
+## Editing profiles from the dashboard
-### Custom Staffing Levels
+Clicking a name opens the person; administrators can **edit the profile** (name, email, phone numbers and carrier, group and roles, addresses, language, time zone, notification options, department admin / disabled / hidden flags). See [Personnel](personnel) and [Profile & Account](profile-account).
-If the department has configured custom staffing levels (see [Custom Statuses](custom-statuses)), the dashboard displays custom staffing buttons. Otherwise, it uses the default staffing levels:
+## Tutorial and setup report
-| Default Staffing Level | Description |
-|----------------------|-------------|
-| Available | Ready for dispatch |
-| Delayed | Available but with delay |
-| Unavailable | Not available |
-| Committed | Currently committed |
-| On Shift | Currently on shift duty |
+First-time administrators see a **dashboard tutorial** overlay; **Help → Setup report** lists what is still unconfigured (no units, no stations, unverified contacts …).
-### Custom Personnel Statuses
+
-Similarly, personnel action statuses can be customized. Default statuses include:
+## Setup tips
-| Default Status | Description |
-|---------------|-------------|
-| Standing By | Available and waiting |
-| Not Responding | Not responding to calls |
-| Responding | En route to call |
-| On Scene | Arrived at call scene |
-| Available Station | Available at station |
-| Responding to Station | En route to station |
-| Responding to Scene | En route to scene |
+| Department | Tip |
+|---|---|
+| **Volunteer fire / EMS** | Sort personnel by group so each station sees its own people first; enable the daily **staffing reset** to Available at 06:00 so stale *Unavailable* flags clear. |
+| **Career** | Members rarely touch status manually — shifts and unit staffing drive it; consider hiding the Actions panel for non-responders by permission. |
+| **SAR / CERT** | Staffing is the key signal (who can deploy this week); ask members to set it from the Responder app. |
+| **Security / business** | Custom statuses such as *On patrol*, *At post*, *Break*; staffing reset at shift boundaries. |
-## User Actions
+## Technical reference
-### Setting Your Own Status
-
-Users can set their own action status from the dashboard:
-
-- **SetCustomAction** — Set your current status with an optional note
-- **SetCustomStaffing** — Set your staffing level
-- **SetUserState** — Set a custom or standard staffing state with a note
-- **UserRespondingToStation** — Mark yourself as responding to a specific station
-- **UserRespondingToCall** — Mark yourself as responding to a specific call
-
-### Managing Other Users' Status
-
-Users with appropriate permissions can set status for other personnel:
-
-- **SetCustomUserAction** — Set another user's action status
-- **SetCustomStaffing** — Set another user's staffing level
-- **SetStateForUser** — Set a specific user's staffing state
-- **SetActionForUser** — Set a specific user's action type
-
-### Bulk Status Actions
-
-- **ResetAllToStandingBy** — Reset the entire department to StandingBy status
-- **ResetGroupToStandingBy** — Reset all personnel in a specific group to StandingBy
-
-## Editing User Profiles
-
-The dashboard provides access to edit any user's profile (with proper permissions):
-
-### Profile Edit Capabilities
-
-| Field | Description | Notes |
-|-------|-------------|-------|
-| First/Last Name | User's display name | Required |
-| Email | Login email address | Must be unique across the system |
-| Mobile Number | SMS contact number | UK carriers require specific number prefixes |
-| Mobile Carrier | SMS provider | Required for text messaging |
-| Group Assignment | Station/group membership | Select from department groups |
-| Personnel Roles | Role assignments | Multiple roles supported |
-| Home Address | Physical home address | Used for proximity calculations |
-| Mailing Address | Postal address | Optional |
-| Voice Settings | VoIP call settings | Subject to subscription plan |
-| Admin Status | Department administrator | Admin-only setting |
-| Disabled Status | Account disabled | Prevents login |
-| Hidden Status | Hidden from views | Personnel still exists but not shown |
-| Language | UI language preference | Sets a language cookie |
-| Timezone | User's timezone | Affects time display |
-
-### Profile Edit Validation
-
-- Mobile carrier rules enforce UK-specific number prefixes for UK carriers
-- Email addresses must be unique across the entire system
-- Password changes require the new password to meet strength requirements
-- Username changes are supported
-- All profile changes fire an `AuditEvent` and clear multiple caches
-
-## Dashboard Widgets
-
-### Active Calls Widget
-Displays currently active calls with priority colors and quick access to call details.
-
-### Subscription Warning
-Shows a warning banner if:
-- The department exceeds its subscription plan limits (personnel or units)
-- There are system-wide notices
-
-### Top Icons Area
-Shows unread message count and quick navigation to messages.
-
-### Upgrade Button
-Displayed for free plan department administrators to encourage plan upgrade.
-
-## Interactions with Other Modules
-
-| Module | Interaction |
-|--------|-------------|
-| **Custom Statuses** | Dashboard reads custom personnel statuses and staffing levels |
-| **Groups** | Personnel are grouped by their station/group assignment |
-| **Personnel Roles** | Roles are displayed alongside personnel names |
-| **Calls** | Active calls widget, responding-to-call links |
-| **Subscription** | Plan limit warnings displayed |
-| **Messages** | Unread count shown in top icons |
-| **Department Settings** | Sort order, text-to-call number, 24h time format |
+| Item | Value |
+|---|---|
+| Controller | `HomeController` (`Dashboard`, `GetUserStatusTable`, `UserActionsPartial`, `PersonnelActionButtonsPartial`, `EditUserProfile`) |
+| Actions | `SetCustomAction`, `SetCustomUserAction`, `SetCustomStaffing`, `SetStateForUser`, `SetActionForUser`, `UserRespondingToStation?stationId=`, `UserRespondingToCall?callId=`, `ResetAllToStandingBy`, `ResetGroupToStandingBy?groupId=` |
+| Realtime | `resgrid.common.signalr` subscribes to personnel/unit/call events from the eventing hub |
+| Visibility | Authorization visibility matrix (`CanUserViewPersonViaMatrixAsync`); PII gated by `ViewPersonalInfo` |
+| Partials | `_TopIconsPartial` (unread counts), `_TopUpgradePartial`, `_SetupWizard`, `GetSubscriptionLimitWarning` |
diff --git a/docs/web-app/data-protection.md b/docs/web-app/data-protection.md
new file mode 100644
index 0000000..e75768f
--- /dev/null
+++ b/docs/web-app/data-protection.md
@@ -0,0 +1,79 @@
+---
+sidebar_position: 48
+title: Advanced Data Protection
+---
+
+# Advanced Data Protection (ADP)
+
+**Advanced Data Protection** encrypts the sensitive content of your department's data — call names, natures, notes and addresses; call notes and attachments; contact details; member sensitive data; and the protected fields of Records, Checklists, Work Orders and Inventory — with **keys owned by your department** and held in a hardened key service. Once enrolled, protected values stay hidden until a signed-in member confirms who they are with a **second factor**, and they remain encrypted in exports, notifications and reports.
+
+:::caution Not a compliance program by itself
+ADP is one control inside a HIPAA / privacy / ePCR compliance program that your agency still owns. It does not, on its own, make you compliant.
+:::
+
+**Department dropdown → Security & Permissions → Data Protection** (`/User/DataProtection`).
+
+
+
+## What is protected — and what is not
+
+| Protected (encrypted) | Stays plaintext |
+|---|---|
+| Call names, natures, notes, addresses; call notes and attachments; contact details and notes; member sensitive data (personal info, emergency contacts); Records narratives, participants and restricted fields; checklist answers and evidence; work-order text and files; inventory holders and notes. | System identifiers, call numbers, priorities, statuses, timestamps, unit names and department structure — the platform needs these to route and display work. |
+
+### While protected
+
+- **Search, reporting, exports, integrations and offline access** cannot see protected content (Records narrative search is withdrawn; export columns are written as `REDACTED` unless an egress acknowledgement is recorded).
+- **Big Board** shows a reduced *protected incident* shell instead of call details.
+- **Workflows** receive redacted payloads.
+- **Text, email, push and voice notifications** send generic content by default (*"A protected dispatch is available — sign in to Resgrid"*). Relaxing a channel is a separate, acknowledged policy change.
+- Resgrid support cannot read protected values without an explicit, audited, department-approved support grant. Key loss is recoverable only through the documented recovery process.
+
+## How members see protected data
+
+When a page contains protected content it shows a **Protected** banner and a **Verify and open** button. The member enters a code from their **authenticator app** (see [Account security](account-security)); the data is revealed for a window your department configures (default 15 minutes; values over 60 require a recorded reason). Every protected read is audited — the audit holds no values itself.
+
+Under **Verification prompt** the managing member can switch the prompt off per application (web site, Dispatch console, Responder, Unit, Incident Command, API integrations). Leave it on wherever you can; switching it off on a dispatch console during an incident may be acceptable, on a phone that can be lost much less so.
+
+## Enrolling
+
+Prerequisites: a **paid plan**, the **ADP add-on** (yearly; purchased by the managing member from **Subscription & Billing → Advanced Data Protection**), the platform enrollment gate open, and the managing member enrolled in an **authenticator**.
+
+The **Enrollment Wizard** has six steps:
+
+1. **What ADP covers** — read the scope and limitations.
+2. **Acknowledgements** — eleven statements the managing member must tick (scope, plaintext metadata, server-side processing, step-up window, Big Board reduction, workflow redaction, notification defaults, search/report limits, migration and disable behaviour, key-loss recovery, not-HIPAA-compliance). Acknowledgements are recorded with a version stamp.
+3. **Preflight checks** — managing member, paid plan, active add-on, gate open, department state, protection service reachable, managing member MFA.
+4. **Migration size estimate** — a read-only **sizing scan** counts rows and estimates how many overnight windows the migration needs.
+5. **Overnight migration window** — choose the quiet hours (local time zone) during which migration runs. While a window is running **no new calls, status changes, staffing changes or scheduled tasks run**; viewing continues; you can abort an active window at any time. Consent to the pause is required.
+6. **Confirm and queue** — requirements are re-verified server-side and the department joins the migration queue (departments migrate one at a time). You receive an email when each night's window opens and closes.
+
+The page then shows **migration progress** (rows processed, current table, anomalies needing attention) and finally **Advanced Data Protection is active**.
+
+## Turning it off
+
+Cancel the add-on on the subscription page. Protection stays active until the end of the current billing period, then an overnight migration decrypts the data back to standard storage (**offboarding**). Until that date the managing member can **revoke offboarding**. Re-enabling later requires purchasing the add-on again and a new enrollment.
+
+## Emergency contacts
+
+The Data Protection page also hosts the member's **emergency contacts** for this department (name, relationship, phone, alternate phone, email, notes, primary flag), stored under the department's protection settings.
+
+## Setup examples
+
+| Department | Recommendation |
+|---|---|
+| **EMS / fire-based EMS** | Enrol. Keep the verification prompt on everywhere except the dispatch console. Default notification egress (generic content). |
+| **Fire (no PHI)** | Optional; useful where call notes contain personal information from callers. |
+| **Security / private** | Enrol if incident reports name individuals; pair with restricted record fields. |
+| **Emergency management** | Usually unnecessary unless shelter registrations or vulnerable-population data are stored. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/DataProtection/{Index,SizingScan,MigrationProgress}`, `/User/Subscription/{BuyAdpAddon,ManageAdpAddon}` |
+| Flag | `Security.DepartmentProtectedDataEnrollment` — operator-managed global admission gate for **new** enrollments only |
+| Permissions | `ManageDepartmentDataProtection` (31), `ViewProtectedCallData` (32), `EditProtectedCallData` (33), `ViewProtectedPersonnelData` (34), `ViewProtectedContactData` (35), `ViewProtectedOperationalData` (36), `ExportProtectedData` (37), `ConfigureProtectedDataEgress` (38), `BreakGlassProtectedData` (39) |
+| State | `DepartmentDataProtectionPolicies.State` (durable); migration and offboarding run by workers in the department's window |
+| Grant | `IProtectedGrantContext` / `__ResgridProtectedGrant` form field carries the step-up grant on writes |
+| Design | `int-Coordination/docs/architecture/department-protected-data-implementation-plan.md` |
diff --git a/docs/web-app/department-links.md b/docs/web-app/department-links.md
index 207a3ac..259dfe1 100644
--- a/docs/web-app/department-links.md
+++ b/docs/web-app/department-links.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 27
+sidebar_position: 46
title: Department Links
---
@@ -7,6 +7,8 @@ title: Department Links
Department Links enable inter-department data sharing, allowing linked departments to view each other's calls, units, and personnel. The module is managed by the `LinksController`.
+
+
## Overview
Department linking is a **plan-gated feature** — departments on the Free Plan cannot use links.
@@ -75,16 +77,24 @@ Comprehensive personnel view from the linked department:
- Role assignments
- Sorted by action weight then name
-## Data Endpoints
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Mutual aid** | Link neighbouring departments to share active calls and unit statuses both ways. |
+| **Central dispatch centre** | A dispatch department links to every agency it dispatches for; agencies share personnel/unit status back. |
+| **County EM** | Links to every fire/EMS agency for the EOC map. |
+## Technical reference
+
+### Data Endpoints
| Endpoint | Purpose |
|----------|---------|
| `GetActiveCallsList` | Active calls from linked department |
| `GetUnitsList` | Units from linked department |
| `GetPersonnelList` | Personnel from linked department |
-## Interactions with Other Modules
-
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Subscription** | Plan limits control link availability |
diff --git a/docs/web-app/department-settings.md b/docs/web-app/department-settings.md
index 00d067a..46c0c4f 100644
--- a/docs/web-app/department-settings.md
+++ b/docs/web-app/department-settings.md
@@ -1,227 +1,142 @@
---
-sidebar_position: 3
+sidebar_position: 38
title: Department Settings
---
# Department Settings
-The Department Settings area is the central configuration hub for a Resgrid department. It is managed by the `DepartmentController` and requires `Department_Update` authorization for most operations.
+Everything about *how your department works* lives under the **Department menu** (your department's name, top-right). This page covers the **Department Settings** pages themselves; other menu items have their own pages (Groups, Types, Custom Statuses, Templates, Protocols, Workflows, Security …).
-## General Settings
-
-### Basic Configuration
-
-| Setting | Description | Validation |
-|---------|-------------|------------|
-| Department Name | Display name for the department | Required |
-| Timezone | Department's timezone for time display | Selected from system timezones |
-| Managing User | Primary department administrator | Must be a department member |
-| 24-Hour Time | Use 24h vs 12h time format | Toggle |
-| Department Address | Physical address of the department | Full address form |
+Only **department administrators** see these pages. Every change is audited.
-### Map Settings
+
-| Setting | Description | Range |
-|---------|-------------|-------|
-| Map Center GPS | Default map center coordinates | Valid latitude/longitude |
-| Map Zoom Level | Default zoom level | 0–15 |
-| Map Refresh Timer | Auto-refresh interval in seconds | 5–120 seconds |
+## General settings
-### Personnel Display Settings
+`/User/Department/Settings`
-| Setting | Description |
-|---------|-------------|
-| Personnel Sort Order | How personnel are sorted (Default, First Name, Last Name) |
-| Auto Available | Automatically set members as available |
-| Hide Unavailable | Hide unavailable personnel from status views |
-| Suppressed Staffing Levels | Hide specific staffing levels from UI |
+| Setting | What it does |
+|---|---|
+| **Department name** | Shown everywhere, including notifications and prints. |
+| **Time zone** | All times in the web site, apps, reports and schedules are shown in this zone. |
+| **Use 24-hour time** | Clock format. |
+| **Managing user** | The account owner — the only person who can change billing, purchase add-ons, enrol in data protection or delete the department. |
+| **Disable auto-available** | By default a member's status returns to *Available* an hour after they set something else; tick to stop that. |
+| **Personnel / unit / call sorting** | Default, first name, last name or group ordering on lists and the dashboard. |
+| **Suppress (mute) for these staffing levels** | Members in the ticked staffing levels (e.g. *Unavailable*, *Off duty*) receive no dispatch notifications. |
+| **Enable modern notification sounds** | Use the newer alert tones in the apps for everyone. |
+| **Require security PIN** | Force every member to confirm dangerous assistant / text actions with their 4-digit PIN. |
+| **Require password reset via email** | Administrators can no longer set a member's password; reset sends the member a single-use link. |
+| **TTS language** | Voice / dialect for voice dispatch prompts. |
-### Scheduled Status/Staffing Resets
+### Personnel staffing reset / status reset
-The system supports automated reset schedules for personnel:
+Automatically reset everyone's **staffing** (e.g. to *Available*) or **status** (e.g. to *Standing By*) at a time of day on chosen weekdays — typical for volunteer departments where people forget to clear *Unavailable*.
-- **Status Reset** — Automatically reset all personnel to a default status at a scheduled time
-- **Staffing Reset** — Automatically reset all staffing levels at a scheduled time
+### Department address and map centre
-These are configured as `ScheduledTask` objects with day-of-week and time selections.
+The department's own address (a station or district office) is used to locate the district and as a fallback map centre. **Default map centre GPS coordinates** pin where every map opens; leave blank to derive it from the address.
-## API & Integration
+## Department profile
-### API Key Management
+`/User/Department/Profile` — description, **short name**, **logo** (PNG/JPEG ≤ 2 MB, re-encoded with metadata removed), public profile settings for [Connect](connect), and **Use branding in emails** (call, message, report and workflow emails carry your logo and name; account and billing emails stay Resgrid-branded). The logo also heads [record prints](records/settings#print-layout).
-- **View API Key** — Displays the current department API key
-- **Provision API Key** — Generates a new API key (GUID format)
-- **RSS Feed Key** — Generates a key for the active calls RSS feed
+
-### Call Email Import
+## Module settings
-Configure email-based call import for automatically creating dispatch calls from incoming emails:
+`/User/Department/ModuleSettings` — switch modules on or off for the whole department: Messaging, Mapping, Shifts, Logs / Records, Reports, Documents, Calendar, Notes, Training, Inventory, **Checklists**, **Maintenance** (work orders). Switching a module off hides it from the menu and the apps; data is kept.
-| Setting | Description |
-|---------|-------------|
-| Hostname | Mail server hostname |
-| Port | Mail server port (default: 110) |
-| Use SSL | Enable SSL for mail connection |
-| Username/Password | Mail server credentials |
-| Email Format Type | Parser format for incoming emails |
-| Call Pruning | Automatically close old calls |
+
-**Supported Email Format Types (~20 types):**
-- CalFire
-- Generic
-- Active911
-- Brann Norge
-- Caliber
-- Carl EMS
-- Coast Guard
-- County Fire
-- Dispatch Pro
-- Facility
-- Four Rivers
-- Frontier Page
-- Hilton Head
-- IaFCDS
-- IAmResponding
-- Oshkosh
-- Parkland County
-- Ranch Kiowa
-- SpottedDog
-- Yellowhead County
-- And others...
+## Call & dispatch settings
-### Text Messaging Settings
+`/User/Department/DispatchSettings`
-| Setting | Description |
-|---------|-------------|
-| Text-to-Call Number | Incoming SMS number for creating calls |
-| Text Command Enable | Enable SMS-based commands |
-| Source Numbers | Phone numbers for outgoing SMS |
-| Import Format | Text-to-call format parser |
+
-**Number Provisioning:**
-- Search available phone numbers by country and area code
-- Provision a specific number
-- Auto-provision the first available number
+| Section | Settings |
+|---|---|
+| **Group dispatch** | **Use shift for group dispatch** — dispatching a group sends only to the people signed up for today's shift. **Set status for shift personnel on dispatch** — automatically set them to a chosen status (default *Responding to scene*). |
+| **Unit dispatch** | **Also dispatch to assigned personnel** (the crew staffed on the unit) and/or **Also dispatch to entire group** (the unit's station). **Personnel on unit set unit status** — when a unit reports a status, its crew are set to *On unit*. |
+| **Default call statuses** | The status personnel / units are set to when **dispatched** and when **released** from a call; per-unit-type overrides for types with custom statuses. |
+| **Rest period** | Deprioritise a unit or person for N minutes after a dispatch so the same resources are not sent back-to-back. |
+| **New call form fields** | Which built-in fields appear on the New Call form and which are required (name, nature, priority and type are always shown and required). |
+| **Unit status timers** | Highlight a unit on the Big Board when it has sat in a status too long (e.g. dispatched > 4 min without departing). |
+| **Run cards & automatic dispatch** | Selection mode, auto-dispatch, minimum staffing, move-ups, closest-unit tuning (maximum location age, radius, include stale, order by driving ETA, shortlist size), station coverage minimums — see [Run Cards](run-cards). |
+| **Check-in timers** | Auto-enable on new calls, default timer configs and per-type/priority overrides — see [Call Check-in Timers](call-checkin-timers). |
-Number provisioning is limited by the department's subscription plan.
+## Call import settings
-## Dispatch Settings
+`/User/Department/CallSettings`
-| Setting | Description |
-|---------|-------------|
-| Dispatch Shift Instead of Group | When dispatching a group, dispatch personnel signed up for the current shift instead |
-| Auto-Set Status for Shift Dispatch | Automatically change dispatched shift personnel to a configurable status |
-| Unit Dispatch Behaviors | Configure how units respond to dispatch |
-| Auto-Enable Check-In Timers for New Calls | Automatically enable check-in timers on every new call created |
-
-### Default Check-In Timer Configs
-
-Admins can define department-wide default check-in timers that apply to all calls. Each config specifies the timer target type, optional unit type, check-in interval (duration in minutes), warning threshold, enabled state, and an optional active-for-states filter.
+
-See [Call Check-In Timers](./call-checkin-timers) for the full list of target types and configuration details.
-
-### Check-In Timer Overrides
-
-Overrides replace default timer configs for specific call types and/or call priorities. They share the same fields as default configs and are evaluated by specificity — an override matching both call type and priority takes precedence over one matching only one of those values.
-
-## Shift Settings
+| Setting | What it does |
+|---|---|
+| **Dispatch import email** | Your department's *all-call* address (`xxxx@dispatch.resgrid.com` on the hosted service). Anything mailed to it becomes a call dispatched to everyone with call notifications on. Forward your CAD pages here. |
+| **Email format type** | The parser for your CAD's page format: Generic, Active911, IAmResponding, CalFire, Caliber, Dispatch Pro, Frontier Page, Hilton Head, IaFCDS, Oshkosh, Parkland County, Yellowhead County, Coast Guard, Brann Norge, Facility, Four Rivers, Ranch Kiowa, SpottedDog, County Fire, Carl EMS … Generic parses subject and body into name and nature. |
+| **Prune calls / minutes to keep open** | Auto-close email/text/audio-imported calls after N minutes. |
+| **Mail server (self-hosted)** | Hostname, port, SSL, username and password of a mailbox to poll. |
-| Setting | Description |
-|---------|-------------|
-| Allow Multi-Group Signup | Allow personnel to sign up for shifts in groups other than their own |
-
-## Mapping Settings
-
-| Setting | Description |
-|---------|-------------|
-| Mapping TTL | Time-to-live for location data on maps |
-| Location Overwrite | Whether new locations overwrite existing ones |
+## Text messaging
-## Module Settings
-
-Enable or disable individual modules for the department:
-
-| Module | Description |
-|--------|-------------|
-| Messaging | Internal messaging system |
-| Mapping | Interactive maps and location tracking |
-| Shifts | Shift scheduling and management |
-| Logs | Run logs and work logs |
-| Reports | Reporting suite |
-| Documents | Document management |
-| Calendar | Event calendar |
-| Notes | Department notes |
-| Training | Training modules |
-| Inventory | Equipment tracking |
-| Maintenance | Maintenance scheduling |
+`/User/Department/TextSettings` — the department's **SMS number** (provision one by country and area code, plan permitting), **text-to-call** (inbound texts create calls) with its format parser, **text commands** (members text `responding`, `available` …), source numbers for outbound SMS. See [Text messaging configuration](../configuration/text-messaging).
-## Invites
+
+
+## Unit settings
-Manage email invitations for new department members:
+`/User/Department/UnitSettings` — unit-level behaviour such as location TTL and status defaults per unit type.
-- **Send Invites** — Send email invitations to join the department (validates email format and uniqueness)
-- **Resend Invite** — Re-send a pending invitation
-- **Delete Invite** — Remove a pending invitation
+## Shift settings
-## Department Deletion
+`/User/Department/ShiftSettings` — **Allow signups for multiple groups** (members can sign up for shifts at stations other than their own).
-:::danger
-Department deletion is a destructive operation that:
-1. Cancels any active Stripe subscriptions
-2. Marks the department for deletion
-3. Cannot be easily undone
-:::
+## Mapping & Big Board settings
-- Requires `Department_Update` authorization
-- Confirmation step required
-- A pending deletion can be cancelled before processing
-- Fires an `AuditEvent` for both deletion and cancellation
+`/User/Department/MappingSettings` — for personnel and units: **TTL in minutes** for locations shown on maps (0 = show forever) and **allow a status with no location to hide the previous location**. See [Mapping](mapping).
-## Setup Wizard
+## API settings
-A guided setup wizard is available for new departments that walks through:
+`/User/Department/Api` — view or **provision** the department **API key** (used by integrations and the apps' department login), and the **RSS active-call feed key**. Regenerating a key invalidates the old one immediately.
-1. **Timezone selection** — Set the department's timezone
-2. **Address configuration** — Set the department's physical address
-3. **Station setup** — Create initial station groups
-4. **Unit creation** — Create initial units
-5. **Email import** — Configure call email import
-6. **Text messaging** — Configure SMS settings
+
+
+## Invites
-The wizard submits all data as a single JSON payload for atomic processing.
+`/User/Department/Invites` — send email invitations (comma-separated addresses); pending invites can be resent or deleted. Invitees create their own account and land in your department.
-## Cache Management
+
-- **Clear Department Cache** — Enqueues a CQRS event to clear all cached data for the department
+## Setup wizard
-## Printer Integration
+`/User/Department/SetupWizard` — for new departments: time zone → address → stations → units → email import → text messaging, saved in one step. Also reachable from the dashboard on first login.
-Station groups can be configured with PrinterNet printers for automatic dispatch printing:
+
-- **GetPrinterNetPrinters** — Retrieves available printers using a PrinterNet API key
+## Delete department
-## Data Endpoints
+`/User/Department/DeleteDepartment` — the managing user can schedule deletion; it cancels subscriptions, marks the department for deletion and can be **cancelled** until processed.
-The controller provides several JSON API endpoints used by the UI:
+## Setup examples
-| Endpoint | Purpose |
-|----------|---------|
-| `GetStationsForGrid` | Station groups data for grid display |
-| `GetRecipientsForGrid` | Filtered recipient list (groups, roles, persons) |
-| `GetDepartmentTypes` | Department type dropdown data |
-| `GetCallEmailTypes` | Available email format types |
-| `GetCallTextTypes` | Available text format types |
-| `GetAvailableNumbers` | Phone numbers available for provisioning |
-| `GetSubscriptionLimitWarning` | Plan limit warnings |
+| Department | Settings worth changing from the defaults |
+|---|---|
+| **Volunteer fire** | Staffing reset daily 06:00 → Available; email import from county CAD (pick the matching format); *Also dispatch to entire group* on unit dispatch; modern sounds on. |
+| **Career fire** | Use shift for group dispatch; set status on shift dispatch; unit status timers 4/8 minutes; run cards auto-dispatch. |
+| **EMS** | Default call statuses: dispatched → *Responding*, released → *Available*; rest period 10 min; require password reset via email. |
+| **SAR** | Disable auto-available; New Call form: make *what3words* / coordinates visible; longer location TTL (240 min). |
+| **Emergency management** | Modules: turn off Shifts and Inventory if unused; 24-hour time; text commands off. |
+| **Security / business** | Branding in emails; text-to-call from client alarm centres; suppress notifications for *Off duty*. |
-## Interactions with Other Modules
+## Technical reference
-| Module | Interaction |
-|--------|-------------|
-| **Subscription** | Plan limits affect features like phone number provisioning and department links |
-| **Custom Statuses** | Staffing reset uses custom staffing levels |
-| **Shifts** | Dispatch settings control shift-based dispatch behavior |
-| **Groups** | Station groups are managed here and used throughout the system |
-| **Calls** | Email import and text-to-call create calls automatically |
-| **Mapping** | Map center and zoom settings affect all map views |
-| **Check-In Timers** | Default timer configs and call-type/priority overrides are managed in Dispatch Settings |
+| Item | Value |
+|---|---|
+| Controller | `DepartmentController` |
+| Routes | `/User/Department/{Settings,Profile,ModuleSettings,DispatchSettings,CallSettings,TextSettings,UnitSettings,ShiftSettings,MappingSettings,Api,Invites,SetupWizard,DeleteDepartment,ClearDepartmentCache}` |
+| Policy | `Department_Update` (administrators); managing-user checks for billing, ADP and deletion |
+| Storage | `Department` row + `DepartmentSettings` rows keyed by `DepartmentSettingTypes` (e.g. 32 = ModuleSettings, 58–60 = run-card dispatch, 70–77 = Records settings) |
+| Cache | Settings cached up to a day; **Clear department cache** enqueues a cache-clear event |
+| Data endpoints | `GetStationsForGrid`, `GetRecipientsForGrid`, `GetDepartmentTypes`, `GetCallEmailTypes`, `GetCallTextTypes`, `GetAvailableNumbers?country=&areaCode=`, `ProvisionNumber`, `GetSubscriptionLimitWarning`, `GetPrinterNetPrinters?key=` |
diff --git a/docs/web-app/dispatch-calls.md b/docs/web-app/dispatch-calls.md
index 3f80b0a..1159bfb 100644
--- a/docs/web-app/dispatch-calls.md
+++ b/docs/web-app/dispatch-calls.md
@@ -5,244 +5,124 @@ title: Dispatch & Calls
# Dispatch & Calls
-The Dispatch module is the core operational component of Resgrid, handling call creation, dispatch, management, and lifecycle. It is managed by the `DispatchController` and is one of the most complex areas of the application.
+**Calls** are the incidents, jobs, events and tasks your people respond to. Dispatching a call tells the right people and units about it — by push notification, text, email and voice — tracks who is responding and who is on scene, collects notes, photos and files, and closes with a disposition that feeds your records and reports.
-## Overview
+
-The dispatch workflow follows this lifecycle:
+## Where to find it
-```
-New Call → Dispatch → Active → Update/Notes → Close → Archive
-```
+**Left menu → Calls.** The Calls page shows:
-## Call Dashboard
+- **Unit statuses** — every unit with its current state and when it changed.
+- **Active calls** — open calls with number, name, priority and time, plus **View**, **Update** and **Close** buttons.
+- A **map** of active calls and units.
+- Buttons for **Routes**, **Archived calls**, **Scheduled calls** and **New Call**.
-The main dispatch dashboard displays:
-- All currently active calls with priority coloring
-- Map centered on the department's configured location (GPS coordinates or geocoded address)
-- Quick access to create new calls, view archived calls, and call analytics
+## Creating a call
-## Creating a New Call
-
-**Authorization:** `Call_Create` policy + `CanUserCreateCall` runtime check
-
-### Required and Optional Fields
-
-| Field | Required | Description |
-|-------|----------|-------------|
-| Call Name | Yes | Short title for the call |
-| Call Nature | Yes | Description of the incident |
-| Call Type | No | Classification type (Fire, EMS, etc.) |
-| Call Priority | No | Urgency level (with custom priorities supported) |
-| Address/Location | No | Incident address, GPS coordinates, or What3Words |
-| Dispatch To | No | Personnel, groups, units, and/or roles to dispatch |
-| Call Notes | No | Initial notes for the call |
-| Protocols | No | Attach dispatch protocols |
-| Linked Calls | No | Reference related calls |
-| Contacts | No | Attach relevant contacts |
-| Form Data | No | Custom form data |
-| Enable Check-In Timers | No | Activates the check-in timer system for this call (auto-checked if the department setting is enabled) |
-
-### Dispatch Targets
-
-Calls can be dispatched to multiple target types simultaneously:
-
-| Target Type | Description |
-|-------------|-------------|
-| **Individual Users** | Specific personnel by ID |
-| **Groups** | All members of a station/group |
-| **Roles** | All personnel with a specific role |
-| **Units** | Specific units (apparatus/vehicles) |
-
-### Shift-Based Dispatch
-
-When the department setting **"Dispatch Shift Instead of Group"** is enabled:
-1. Group dispatch targets are intercepted
-2. Instead of dispatching all group members, the system looks up who is signed up for the current day's shift
-3. Only shift personnel are dispatched
-4. If **"Auto-Set Status for Shift Dispatch"** is enabled, dispatched shift personnel are automatically set to a configurable status (default: RespondingToScene)
-
-### Call Broadcast Pipeline
-
-After a call is saved:
-1. The call is persisted to the database
-2. A `CallAddedEvent` is fired through the event aggregator
-3. The call is enqueued via `IQueueService.EnqueueCallBroadcastAsync`
-4. The queue processor sends push notifications, SMS, and email to all dispatched personnel
-
-:::info Contact Verification Gating
-Outbound dispatch communications are gated by each user's contact verification status. Email dispatches are only sent if the user's email is **Verified** or **Grandfathered**. SMS dispatches are only sent if the user's mobile number is **Verified** or **Grandfathered**. Voice call dispatches are only sent if the relevant phone number (home or mobile) is **Verified** or **Grandfathered**. Users with **Pending** contact methods will not receive dispatches on those channels. See [Contact Method Verification](../configuration/contact-verification) for details.
-:::
-
-### Location Handling
-
-The system supports multiple location input methods:
-- **Direct address** — Street address that gets geocoded
-- **GPS coordinates** — Latitude/longitude pairs
-- **What3Words** — Three-word location codes resolved via the W3W API
-- **Reverse geocoding** — If only coordinates are provided, the system can look up the address
-
-## Check-In Timers
-
-When a call has check-in timers enabled, a **Check-In Timers** panel appears on the View Call page showing real-time countdowns for each configured timer type (PAR, Rehab, IC, Hazmat, etc.). Timers visually escalate from **Green → Warning → Critical** as deadlines approach, and clicking **Check In** resets the timer and logs a record with an optional note and GPS coordinates.
-
-For full configuration, workflow, and API documentation see [Call Check-In Timers](./call-checkin-timers).
-
-## Updating a Call
-
-**Authorization:** `Call_Update` policy + `CanUserEditCall` runtime check
-
-Updating a call supports:
-- Modifying call details (name, nature, type, priority, location)
-- Adding or removing dispatch targets (diff-based — only changes are applied)
-- Updating linked calls and contacts
-- Updating protocols
-- Toggling check-in timers on or off
-- **Rebroadcast option** — Optionally re-send notifications to all dispatched personnel
-
-Changes fire a `CallUpdatedEvent`.
-
-## Closing a Call
-
-**Authorization:** `Call_Update` policy + `CanUserCloseCall` runtime check
-
-When closing a call:
-- Set a close state (Cancelled, Completed, etc.)
-- Add closing notes
-- A `CallClosedEvent` is fired
-
-## Re-Opening a Call
-
-Previously closed calls can be re-opened, which fires a `CallUpdatedEvent`.
-
-## Deleting a Call
-
-**Authorization:** `Call_Delete` policy + `CanUserDeleteCall` runtime check
-
-Calls are **soft-deleted**:
-- `IsDeleted` flag set to `true`
-- `DeletedOn` timestamp recorded
-- `DeletedByUserId` recorded
-- `DeletedReason` stored (optional reason text)
-
-## Call Notes
-
-### Adding Notes
-Any user with `Call_View` permission can add notes to a call. Notes include:
-- Text content
-- Source indicator (Web, Mobile, etc.)
-- Timestamp
-- User location at time of posting
-
-### Flagging Notes
-Notes can be flagged/unflagged with a reason by users with `Call_Update` permission.
-
-### Viewing Notes
-The `GetCallNotes` endpoint returns all notes for a call with:
-- Note text and source
-- User's full name
-- Timestamp (department timezone-converted)
-- Location coordinates
-- Flag status and reason
-
-## File Attachments
-
-Files can be attached to calls:
-
-| Constraint | Value |
-|-----------|-------|
-| Maximum file size | 10 MB |
-| Supported image types | jpg, jpeg, png, gif, bmp |
-| Supported document types | pdf, doc, docx, ppt, pptx, xls, xlsx, txt |
-| Supported audio types | mp3, m4a, ogg, wav |
-| Supported video types | mp4, m4v, mov, wmv, avi, mpg |
-
-## Call Export
-
-### Authenticated Export
-The `CallExport` action provides a comprehensive call export including:
-- Full call details
-- Work logs
-- Unit states
-- Action logs
-- Group information
-- Child/linked calls
-- Contacts
-
-### Anonymous Export
-The `CallExportEx` endpoint supports **anonymous access** via encrypted Base64 query parameters. This enables:
-- External sharing of call information
-- Integration with external systems
-- Station routing display
-
-### PDF Export
-The `CallExportPdf` endpoint generates a PDF document from the call export HTML. It:
-1. Fetches the HTML from `CallExportEx`
-2. Strips script tags
-3. Converts to PDF via `IPdfProvider`
-
-## Adding Archived Calls
-
-Historical calls can be created retroactively:
-- Custom `LoggedOn` date
-- Pre-set call state (already closed)
-- Optional **call number recalculation** for the year
-- Useful for importing historical data or logging calls that happened outside the system
-
-## Call Audio
-
-Calls with audio attachments (dispatch audio) can be retrieved as `audio/mpeg` streams.
-
-## Analytics & Reporting
-
-### Year-to-Date Calls
-Groups calls by week and type for the current year.
-
-### Calls by Type in Range
-Call type distribution within a specified date range.
-
-### Calls by State in Range
-Call state distribution within a specified date range.
-
-## Chat
-
-The dispatch area includes a chat view for real-time communication with department/user identification.
-
-## Data Endpoints
-
-| Endpoint | Purpose |
-|----------|---------|
-| `GetActiveCallsForGrid` | Active calls data for grid display |
-| `GetAllCallsForGrid` | All calls data for grid display |
-| `GetActiveCallsList` | Active calls with permissions and priority colors |
-| `GetArchivedCallsList` | Closed calls filtered by year |
-| `GetCallById` | Single call data |
-| `GetPersonnelForCall` | Personnel with dispatch status for a call |
-| `GetAllDispatchesForCall` | All dispatch codes for a call |
-| `GetMapDataForCall` | Map center and marker data |
-| `GetCallTypes` | Department call types |
-| `GetCallPriorities` | Active call priorities |
-| `GetCallsForSelectList` | Recent calls for dropdown (last 14 days) |
-| `GetCoordinatesFromW3W` | What3Words to GPS conversion |
-| `GetAlertNotesForContact` | Alert-flagged contact notes |
-
-## Interactions with Other Modules
-
-| Module | Interaction |
-|--------|-------------|
-| **Groups** | Dispatch to station groups |
-| **Units** | Dispatch to units, unit state tracking |
-| **Personnel** | Dispatch to individuals, status tracking |
-| **Roles** | Dispatch to roles |
-| **Shifts** | Shift-based dispatch substitution |
-| **Protocols** | Protocol attachment and matching |
-| **Forms** | Custom form data attachment |
-| **Templates** | Quick call templates pre-fill form |
-| **Contacts** | Link contacts to calls |
-| **Custom Statuses** | Custom personnel and unit statuses |
-| **Mapping** | Call location display on maps |
-| **Logs** | Work logs reference calls |
-| **Reports** | Call analytics and reports |
-| **Queue** | Async notification broadcast |
-| **Contact Verification** | Email, SMS, and voice call dispatches are gated by each user's contact verification status |
-| **Check-In Timers** | Configurable accountability timers that track check-ins during active calls |
+**New Call** (the same form is used by the Dispatch app and by email/SMS import).
+
+
+
+| Field | What to enter |
+|---|---|
+| **Name** | Short title — this is the headline in every notification (`Structure Fire - 1450 Pine Ridge Rd`). |
+| **Priority** | Low, Medium, High, Emergency or your [custom priorities](types-configuration#call-priorities). Priority decides the notification sound, colour and whether the call overrides quiet hours in the apps. |
+| **Type** | Fire, Medical, Rescue … from your [call types](types-configuration#call-types). Type drives protocols, run cards, NERIS crosswalk and reporting. |
+| **Reporter name / contact info** | Who called it in. |
+| **Primary / additional contacts** | Link [Contacts](contacts) (a premises, a client, a company). Contacts with **alert notes** pop up a warning. |
+| **Call identifier / Incident Id / Reference Id** | External CAD, parent incident and partner numbers for cross-referencing. |
+| **Nature of the call** | The dispatch text; rich text supported. |
+| **Notes** | Additional notes. |
+| **Map page** | Map-book reference. |
+| **Location** | Type an address and **Find Address**, enter a **what3words** address, enter latitude/longitude, or **Set pin on map**. Reverse geocoding fills the address from a pin. |
+| **Destination** | A point of interest such as a hospital, shelter, transfer centre or staging area (from [Mapping → POIs](mapping#points-of-interest)). |
+| **Indoor location** | A zone from an [indoor map](indoor-maps). |
+| **Protocols** | Matching [dispatch protocols](protocols) are listed; answer their questions to attach guidance. |
+| **Call links** | Link related calls. |
+| **Personnel / Groups / Roles / Units tabs** | Who to dispatch (see below). |
+| **Call template** | Load a [quick template](templates) to pre-fill the form. |
+| **Check-in timers** | Enable [accountability timers](call-checkin-timers) for this call. |
+| **Schedule dispatch** | Delay the dispatch to a future time (at least 15 minutes ahead) — the call appears under *Scheduled calls* until then. |
+| **Custom fields** | Any [User Defined Fields](user-defined-fields) configured for calls. |
+
+### Who gets dispatched
+
+Tick any combination of:
+
+| Target | Effect |
+|---|---|
+| **Personnel** | Named members. The grid shows ETA to the call, current status, staffing and roles. |
+| **Groups** | Every member of a station or group. With **Dispatch shift instead of group** on (Department Settings), only members signed up for today's shift are dispatched. |
+| **Roles** | Every member holding a role (e.g. *Driver*, *Paramedic*). |
+| **Units** | Apparatus and their crews. |
+
+If [Run Cards](run-cards) are enabled, the recommendation for the call's priority/type is pre-filled here (or dispatched automatically).
+
+Press **Create Call**. Notifications go out immediately through the queue: push to the apps, SMS, email and voice according to each member's [notification preferences](profile-account#notifications) and [contact verification](../configuration/contact-verification) status. Notification text is generic when the department is enrolled in [Advanced Data Protection](data-protection).
+
+## Working an active call
+
+**View** opens the call page.
+
+
+
+| Panel | What you can do |
+|---|---|
+| **Call details** | Everything entered above, with the dispatch audio if the call came from a radio/TTS source. |
+| **Map** | Call location, responding personnel and units live, route lines. |
+| **Dispatched personnel / units** | Who was dispatched, their current status and timestamps (responding, on scene …). |
+| **Notes** | Add notes (with your location if allowed); **flag** a note for follow-up with a reason. |
+| **Images and files** | Attach photos, documents, audio and video up to 10 MB; flag inappropriate items for [moderation](chat#moderation). |
+| **Check-in timers** | PAR / rehab / IC / hazmat countdowns with **Check In** buttons and history. |
+| **Incident report** | Start the [NERIS incident report](records/incident-reports) or a [Run record](records/authoring). |
+| **Export** | Printable call export, PDF, and a shareable anonymous export link. |
+
+**Update** changes any field, adds or removes dispatch targets (only the differences are applied) and can **rebroadcast** the notification. **Close** asks for a **close state** (Completed, Cancelled, Unfounded, False alarm …) and closing notes. Closed calls move to **Archived calls** and can be **re-opened**.
+
+**Delete** soft-deletes a call with a reason (it can be restored by support).
+
+## Archived and scheduled calls
+
+- **Archived calls** — closed calls by year, with view and export. **Add archived call** creates a historical call with a custom date and pre-set closed state (optionally recalculating the year's call numbers) — useful when importing history or logging a call that happened outside Resgrid.
+- **Scheduled calls** — calls waiting for their scheduled dispatch time.
+
+
+
+## Other ways calls arrive
+
+| Source | How to set it up |
+|---|---|
+| **Email** | Send or forward CAD pages to your department's dispatch import address ([Call import settings](department-settings#call-import-settings)); choose the parser format for your CAD. |
+| **SMS / text** | Text to the department number ([Text messaging](department-settings#text-messaging)). |
+| **Dispatch app** | Same form on tablet or desktop. |
+| **API** | `api/v4/Calls/SaveCall` with an API key or OAuth token. |
+| **Workflows / Assistant** | Workflow actions and the chat Assistant can create calls when allowed. |
+| **Voice** | Automated voice dispatch reads the call out over the phone or radio TTS. |
+
+## Setup examples
+
+| Department | Recommended call configuration |
+|---|---|
+| **Volunteer fire** | Priorities Low/Medium/High/Emergency; types Fire, Medical, MVA, Rescue, Alarm, Public assist; dispatch to Groups (stations) with *Dispatch shift instead of group* off; email import from county CAD; run cards for structure fires. |
+| **Career fire / combination** | Run cards with auto-dispatch; closest-unit mode; check-in timers (PAR every 20 min) on Fire types; NERIS crosswalk for every type. |
+| **EMS** | Types by determinant (ALS/BLS/IFT); dispatch to Units; destination POIs for hospitals; ADP enrolled. |
+| **SAR** | Types Search, Rescue, Recovery, Training; dispatch to Roles (Team leader, K9, Technical rescue); what3words locations; long check-in timers for field teams. |
+| **Emergency management** | Types Activation, Weather, Shelter, Resource request; dispatch to Roles (ESF leads) and Groups (EOC sections); scheduled calls for planned activations. |
+| **Security / facilities** | Types Alarm, Patrol request, Escort, Medical, Incident; contacts for client sites with alert notes and gate codes; indoor locations. |
+| **Delivery / transit** | Types Delivery, Pickup, Breakdown, Route deviation; dispatch to Units (vehicles); destination POIs; link calls to [Routes](routes). |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Controller | `DispatchController` |
+| Routes | `/User/Dispatch/{Dashboard,NewCall,ViewCall,UpdateCall,CloseCall,DeleteCall,ReOpenCall,ArchivedCalls,AddArchivedCall,ScheduledCalls,CallData,CallExport,CallExportEx,CallExportPdf,GetCallDispatchAudio}` (`?callId=`) |
+| Policies | `Call_View`, `Call_Create`, `Call_Update`, `Call_Delete` + `IAuthorizationService.CanUser{Create,Edit,Close,Delete}CallAsync` |
+| Permissions | `CreateCall`, `DeleteCall`, `CloseCall`, `AddCallData` |
+| Events | `CallAddedEvent`, `CallUpdatedEvent`, `CallClosedEvent`; broadcast via `IQueueService.EnqueueCallBroadcastAsync` (push/SMS/email/voice) |
+| Data endpoints | `GetActiveCallsList`, `GetArchivedCallsList?year=`, `GetScheduledCallsList`, `GetCallNotes`, `GetPersonnelForCall`, `GetAllDispatchesForCall`, `GetMapDataForCall`, `GetCallTypes`, `GetCallPriorities`, `GetCallsForSelectList`, `GetCoordinatesFromW3W`, `GetAlertNotesForContact`, `GetDispatchRecommendation`, `CallsYTD`, `CallsTypesInRange`, `CallsStatesInRange` |
+| Attachments | 10 MB; images jpg/jpeg/png/gif/bmp; documents pdf/doc/docx/ppt/pptx/xls/xlsx/txt; audio mp3/m4a/ogg/wav; video mp4/m4v/mov/wmv/avi/mpg |
+| Soft delete | `IsDeleted`, `DeletedOn`, `DeletedByUserId`, `DeletedReason` |
+| Protected data | Name, nature, notes, address and attachments are ADP-protected fields |
+| API | `api/v4/Calls/*` |
diff --git a/docs/web-app/distribution-lists.md b/docs/web-app/distribution-lists.md
index 6fdd0a7..998cedf 100644
--- a/docs/web-app/distribution-lists.md
+++ b/docs/web-app/distribution-lists.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 28
+sidebar_position: 34
title: Distribution Lists
---
@@ -7,6 +7,8 @@ title: Distribution Lists
Distribution Lists manage email distribution groups for the department. The module is managed by the `DistributionListsController`.
+
+
## Distribution List Management
**Authorization:** `Department_Update` policy
@@ -53,8 +55,17 @@ Toggle a list's active state via `SetListStatus`:
| `ValidateAddress` | Check if an email address is already in use by another list |
| `GetMembersForList` | Get member user IDs for a list |
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Fire** | `officers@` and `members@` lists so any member can email the group; `board@` for the auxiliary. |
+| **Emergency management** | `esf-leads@`, `shelters@` lists including external contacts. |
+| **Business** | `site-alpha@` per client site. |
+
+## Technical reference
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Personnel** | Members are department personnel |
diff --git a/docs/web-app/documents.md b/docs/web-app/documents.md
index de4d5fa..e671847 100644
--- a/docs/web-app/documents.md
+++ b/docs/web-app/documents.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 15
+sidebar_position: 23
title: Documents
---
# Documents
-The Documents module provides file management and sharing capabilities for the department. It is managed by the `DocumentsController`.
+**Documents** is a simple, shared file library: SOPs and SOGs, bylaws, maps, forms, manuals, MSDS sheets — organised by **category**, visible to the whole department or to a group, and downloadable in the apps.
+
+**Left menu → Documents.** Categories come from **Department → Types → Document categories**.
+
+
## Document List
@@ -20,6 +24,8 @@ Displays all department documents with:
**Authorization:** `Documents_Create` policy + `CanCreateDocument()` runtime check
+
+
### Document Fields
| Field | Required | Description |
@@ -71,8 +77,21 @@ Creates `AuditEvent` (DocumentRemoved).
Categories are managed through the [Types & Configuration](types-configuration) module:
- The `GetDepartmentDocumentCategories` endpoint returns distinct categories for filtering
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Fire** | Categories: SOG/SOP, Pre-plans (until moved to Records occupancies), Apparatus manuals, Bylaws, Training handouts. |
+| **EMS** | Protocols (or use the Protocols module for dispatch-linked ones), Drug references, Forms, Policies. |
+| **SAR** | Field guides, Maps, Equipment lists, Member handbook. |
+| **Emergency management** | EOP and annexes, ESF checklists, Contact rosters, MOUs. |
+| **Security / business** | Post orders per site (restrict to the site group), Emergency procedures, Insurance certificates. |
+
+## Technical reference
+
+`DocumentsController`; routes `/User/Documents/{Index,NewDocument,ViewDocument,EditDocument,GetDocument}`; permission `CreateDocument`; event `DocumentAddedEvent`; module switch `DocumentsDisabled`; files are scanned before download is allowed.
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Types** | Document categories managed in Types controller |
diff --git a/docs/web-app/forms.md b/docs/web-app/forms.md
index d7df5f3..da49bc2 100644
--- a/docs/web-app/forms.md
+++ b/docs/web-app/forms.md
@@ -1,72 +1,24 @@
---
-sidebar_position: 24
-title: Forms
+sidebar_position: 42
+title: Forms (retired)
---
# Forms
-The Forms module provides a custom form builder that integrates with the dispatch workflow. It is managed by the `FormsController`.
+:::caution Module retired
+The original **Forms** module (a drag-and-drop form builder whose forms were attached to calls) is **switched off** in current Resgrid releases. Its pages return *not found*, no new form templates can be created, and no new form data is captured. Form data that was captured in the past still renders **read-only** on the call detail page so history is preserved.
+:::
-## Form List
+## What to use instead
-**Authorization:** `Forms_View` policy
+| Need | Use |
+|---|---|
+| Extra fields on calls, units, personnel or records | [User Defined Fields](user-defined-fields) — typed fields with visibility rules, validation, mobile and report visibility. |
+| Structured operational reports with sections, rules, review and signatures | [Records](records/overview) — design a department definition from a template (patrol log, incident report, near-miss, damage assessment, ICS forms …) or from scratch. |
+| Checks that must be answered item by item, with pass/fail and evidence | [Checklists](checklists). |
+| Simple polls or acknowledgements | [Messages](messages) with responses. |
+| Automations that used to fire on form submission | [Workflows](workflows) on *Record finalized*, *Checklist completed* or *Call* events. |
-Displays all non-deleted forms for the department.
+## Technical reference
-## Creating Forms
-
-**Authorization:** `Forms_Create` policy
-
-### Form Fields
-
-| Field | Required | Description |
-|-------|----------|-------------|
-| Name | Yes | Form name |
-| Type | Yes | Form type (from `FormType` enum) |
-| Data | Yes | Form definition/structure data |
-
-### Form Automations
-
-Forms support automation rules that trigger actions based on field values:
-
-| Automation Field | Description |
-|-----------------|-------------|
-| Trigger Field | Which form field to watch |
-| Trigger Value | What value triggers the automation |
-| Operation Type | What action to perform |
-| Operation Value | Parameter for the action |
-
-**Example:** Automatically set call priority to "High" when a form field "Severity" equals "Critical."
-
-Automations are parsed from form keys:
-- `callAutomationTriggerField_*`
-- `callAutomationTriggerValue_*`
-- `callAutomationOperationType_*`
-- `callAutomationOperationValue_*`
-
-## Viewing Forms
-
-**Authorization:** `Forms_View` policy
-
-Displays form details. Validates department ownership.
-
-## Enabling/Disabling Forms
-
-**Authorization:** `Forms_Update` policy
-
-Forms can be toggled active/inactive without deletion:
-- **Enable** — Makes the form available for use
-- **Disable** — Hides the form from selection
-
-## Deleting Forms
-
-**Authorization:** `Forms_Delete` policy
-
-Soft-deletes the form. Validates department ownership.
-
-## Interactions with Other Modules
-
-| Module | Interaction |
-|--------|-------------|
-| **Dispatch** | Forms attached to calls; automations affect call properties |
-| **Types** | Form types define categorization |
+`FormsController` overrides `OnActionExecuting` to return `NotFound()` for every action; the `Forms` and `FormData` tables and the `FormSubmittedEvent` remain in the codebase so the module can be re-enabled by removing that override. `CallData` still renders stored form data on `Dispatch/ViewCall`.
diff --git a/docs/web-app/groups-stations.md b/docs/web-app/groups-stations.md
index e7e1a6e..b786d6b 100644
--- a/docs/web-app/groups-stations.md
+++ b/docs/web-app/groups-stations.md
@@ -1,126 +1,79 @@
---
-sidebar_position: 7
+sidebar_position: 10
title: Groups & Stations
---
# Groups & Stations
-Groups organize department personnel and serve as station locations. The module is managed by the `GroupsController`.
+**Groups** are how you organise people and units. A **Station group** is a physical place with an address — a fire station, an ambulance base, an EOC, a client site, a depot — that personnel and units *respond to* and that owns a **response area (geofence)**. An **Organisational group** is a container without a location — a battalion, a division, a district, a team, a client account — used to nest stations and to scope permissions.
-## Group List
+
-**Authorization:** `GenericGroup_View` policy
+## Where to find it
-The index page displays all department groups with the option to create new groups (subject to plan limits via `CanDepartmentAddNewGroup`).
+**Department dropdown → Stations and Groups** (`/User/Groups`). The list shows every group with type, parent, members and **Edit** / **Geofence** / **Delete** buttons.
-## Creating Groups
+## Creating a group
-**Authorization:** `GenericGroup_Create` policy
+
-### Group Fields
+| Field | Notes |
+|---|---|
+| **Group name** | `Station 1`, `Battalion 2`, `North District`, `Client: Acme HQ`. |
+| **Group type** | **Station** (requires a location) or **Organisational**. |
+| **Parent group** | Nest groups to build a hierarchy (Department → Battalion → Station). |
+| **Station address** | Street address, or GPS coordinates (decimal), or a what3words address. Used for the map, *Responding to station*, ETA and closest-unit selection. |
+| **Dispatch email / Message email** | Optional addresses: mail sent to the dispatch address creates a call dispatched to this group; the message address delivers a message to the group. |
+| **PrintNode printer / Print calls to printer** | With a PrintNode account, calls dispatched to this group's members or units are printed on the station printer. |
+| **Group admins / Group users** | Assign members. A person can be in **one group only**. |
-| Field | Required | Description |
-|-------|----------|-------------|
-| Group Name | Yes | Display name for the group |
-| Group Type | Yes | Regular group or Station type |
-| Parent Group | No | Hierarchical parent group |
-| Members | No | Personnel to assign to this group |
+## Geofence (response area)
-### Station Group Requirements
+**Geofence** on a station opens a map; click to draw the boundary of the station's first-due area and pick a **district colour**. Geofences are used by:
-When creating a **Station** type group, at least one of the following is required:
-- **Physical address** — Full street address
-- **GPS coordinates** — Latitude and longitude
-- **What3Words** — Three-word location code
+- [Run cards](run-cards) in *station-based* mode — the station whose area contains the call is selected first, cascading to the next nearest on shortfall;
+- **Move-up** recommendations and station coverage minimums;
+- Map display and the Big Board.
-### Printer Configuration
+
-Station groups can optionally be configured with PrinterNet integration:
-- API key (stored encrypted using Symmetric Encryption)
-- Printer selection
-- Enables automatic dispatch printing at the station
+## Deleting a group
-### Dispatch/Message Email
+A group cannot be deleted while it has active members, child groups, units or shift groups — move or delete those first. Deleting removes group data, personnel and unit memberships, group inventory and shift data permanently.
-Each group can have a generated dispatch or message email address for external integrations.
+## How groups are used elsewhere
-### Member Assignment Rules
+| Module | Use |
+|---|---|
+| Dispatch | Dispatch to a whole group; *Dispatch shift instead of group*. |
+| Personnel / Units | Grouping on lists and the dashboard; group admins manage their own group. |
+| Security | *Department + group admins* permission level; group-scoped visibility. |
+| Shifts | Shift groups per station. |
+| Records | Group anchor for numbering and group-scoped visibility. |
+| Checklists / Work orders | Target type *Group / station*; assignment routing. |
+| Inventory | A station is a stock location. |
+| Notifications | Low-availability alerts per group. |
-- A user can only belong to **one group at a time**
-- The system validates that selected members are not already assigned to another group
-- Members are added as `DepartmentGroupMember` entries
+## Setup examples
-### Creation Process
-1. Validates member uniqueness (no user in multiple groups)
-2. Validates station address/coordinates for station type
-3. Saves group and member assignments
-4. Configures printer if specified
-5. Fires `AuditEvent` (GroupAdded)
+| Department | Structure |
+|---|---|
+| **Single-station volunteer fire** | One station group. Everyone in it. |
+| **Multi-station fire** | Organisational *Battalion 1/2* → Stations 1–6 with geofences; officers as group admins. |
+| **County EMS** | Stations per base; organisational *North / South division*. |
+| **SAR** | Organisational *Ground / Technical / K9 / Support* teams; one station for the cache / meeting point. |
+| **Emergency management** | Station: *EOC*, *Alternate EOC*; organisational groups per section (Operations, Planning, Logistics, Finance) and per ESF. |
+| **Security company** | Organisational group per **client**, station groups per **site** (with address and geofence for alarm response); site supervisors as group admins. |
+| **Delivery / transit** | Station per depot; organisational groups per route region. |
+| **Industrial** | Station: *Main plant*, *Tank farm*, *Warehouse*; organisational *Day / Night ERT*. |
-## Editing Groups
+## Technical reference
-**Authorization:** `GenericGroup_Update` policy + `CanUserEditDepartmentGroup` runtime check
-
-Editing supports:
-- Changing group name and parent
-- Adding/removing members (diff-based)
-- Updating address, GPS coordinates, or What3Words
-- Modifying printer configuration
-
-Fires `AuditEvent` (GroupChanged).
-
-## Deleting Groups
-
-**Authorization:** `GenericGroup_Delete` policy
-
-:::warning Cascade Protection
-A group **cannot be deleted** if it has:
-- Child groups
-- Assigned users
-- Assigned units
-- Referenced shifts
-
-The delete confirmation page shows counts for each of these dependencies.
-:::
-
-Uses `IDeleteService.DeleteGroupAsync` when deletion is allowed. Fires `AuditEvent` (GroupRemoved).
-
-## Geofencing
-
-**Authorization:** `GenericGroup_Update` policy
-
-Station groups support response area geofencing:
-
-### Viewing/Editing Geofences
-- Opens a map editor centered on the department's configured coordinates
-- Allows drawing polygon geofences
-- Supports custom geofence colors
-
-### Saving Geofences
-The `SaveGeofence` endpoint accepts:
-- Geofence color (hex)
-- Polygon coordinate data (GeoJSON-compatible)
-
-Returns a JSON success/failure result.
-
-## Data Endpoints
-
-| Endpoint | Parameters | Purpose |
-|----------|------------|---------|
-| `GetMembersForGroup` | `groupId`, `includeAdmins`, `includeNormal` | Group members filtered by admin/normal status |
-| `GetAllGroups` | — | All groups (id, name) |
-| `GetGroupsForCallGrid` | — | Groups with member counts for dispatch |
-
-## Interactions with Other Modules
-
-| Module | Interaction |
-|--------|-------------|
-| **Personnel** | Personnel belong to groups; group admins manage their members |
-| **Units** | Units are assigned to station groups |
-| **Dispatch** | Groups are dispatch targets; station locations used for routing |
-| **Shifts** | Shifts reference groups for scheduling |
-| **Mapping** | Station locations displayed on maps; geofences shown as overlays |
-| **Reports** | Group data used in staffing and personnel reports |
-| **Department** | Printer and email configuration per group |
-| **Notifications** | Group-level availability alerts |
-| **Security** | Group admin permissions affect personnel management |
+| Item | Value |
+|---|---|
+| Controller | `GroupsController` |
+| Routes | `/User/Groups/{Index,NewGroup,EditGroup,DeleteGroup,Geofence}?departmentGroupId=` |
+| Policies | `Group_View/Create/Update/Delete` |
+| Data endpoints | `GetAllGroups`, `GetMembersForGroup?groupId=`, `GetGroupsForCallGrid`, `SaveGeofence` |
+| Model | `DepartmentGroup` (`Type` 1 = Station, 2 = Organisational), `DepartmentGroupMember`, `Address`, `Geofence` (polygon + colour) |
+| Events | `GroupAddedEvent`, `GroupUpdatedEvent`, `UserAssignedToGroupEvent` |
diff --git a/docs/web-app/help-setup.md b/docs/web-app/help-setup.md
index beaef49..7ff8463 100644
--- a/docs/web-app/help-setup.md
+++ b/docs/web-app/help-setup.md
@@ -1,11 +1,13 @@
---
-sidebar_position: 36
+sidebar_position: 53
title: Help & Setup
---
# Help & Setup
-The Help module provides onboarding assistance and department configuration evaluation. It is managed by the `HelpController`.
+The Help module provides onboarding assistance and department configuration evaluation.
+
+
## Dashboard Tutorial
diff --git a/docs/web-app/indoor-maps.md b/docs/web-app/indoor-maps.md
new file mode 100644
index 0000000..15b0085
--- /dev/null
+++ b/docs/web-app/indoor-maps.md
@@ -0,0 +1,38 @@
+---
+sidebar_position: 15
+title: Indoor Maps
+---
+
+# Indoor Maps
+
+Indoor maps — floor plans of a hospital, school, factory, stadium or shopping centre with named **zones** (rooms, wings, corridors, stairwells, hazard zones, assembly points, staging areas, access points, utility rooms, search grids) — are one **type of custom map**. They are created and edited on the [Custom Maps](custom-maps) page with the map type set to **Indoor**:
+
+- each **floor** is a *floor-plan layer* (an image; large images are tiled automatically),
+- each **zone** is a *region* drawn in the **Region Editor** with a type, colour, description and a *searchable in dispatch* flag,
+- zones can carry **pre-plan attachments** and **hazard markers**.
+
+
+
+Dispatchers pick an **indoor location** (map → floor → zone) on the New Call and Update Call pages; the apps show the floor plan with the zone highlighted, and search teams can mark *Search grid* zones during large-structure searches. Occupancies in [Records](records/occupancies) link to the building's map for pre-plan walk-throughs.
+
+The older `/User/IndoorMaps/*` links still work — they redirect to the equivalent Custom Maps page.
+
+Read the full guide: [Custom Maps → Managing floors, Managing zones, Using custom maps in dispatch](custom-maps).
+
+## Setup examples
+
+| Department | Use |
+|---|---|
+| **Fire / EMS** | Hospitals, care homes, schools and high-rises in your first-due area: mark FDC, standpipe, utility rooms and hazard zones. |
+| **Campus / healthcare security** | Every building; access points and assembly points searchable in dispatch. |
+| **Industrial** | Process areas as hazard zones, muster points as assembly points. |
+| **Event / venue** | Concourses, gates, medical rooms and staging areas on an *Event* map. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Controllers | `CustomMapsController` (`Index?type=0`, `New?type=0`, `Edit`, `Layers`, `RegionEditor`, `Import`, `GetLayerImage`, `GetLayerTile`); `IndoorMapsController` redirects to it |
+| Model | `CustomMap` (`CustomMapType.Indoor = 0`), `CustomMapLayer` (floor plan / overlay / data / infrastructure), `CustomMapRegion` |
+| Call fields | `Call.IndoorMapFloorId`, `Call.IndoorMapZoneId` |
+| API | `api/v4/CustomMaps/*` for the apps |
diff --git a/docs/web-app/inventory.md b/docs/web-app/inventory.md
index 9b64825..803d457 100644
--- a/docs/web-app/inventory.md
+++ b/docs/web-app/inventory.md
@@ -1,93 +1,163 @@
---
-sidebar_position: 18
+sidebar_position: 28
title: Inventory
---
# Inventory
-The Inventory module tracks equipment, supplies, and other assets across department locations. It is managed by the `InventoryController`.
+Inventory tracks **what your department owns, where it is kept and who is carrying it** — from boxes of gloves and medications with expiry dates, through serialized equipment like SCBA packs, radios and monitors, to kits such as turnout-gear sets and medic bags. Every movement is written to an append-only ledger so you can always answer *"where did it go, who moved it, and who witnessed it?"*
-## Inventory Overview
+
-**Authorization:** `Inventory_View` policy
+## Where to find it
-The main view displays consolidated inventory data loaded via AJAX.
+**Left menu → Inventory.** The workspace is a set of tabs; three related workspaces are reachable from the toolbar:
-### Consolidated View
+| Workspace | Tabs |
+|---|---|
+| **Inventory** (main) | On hand · Items · Categories · Locations · Lots · Assets · Issuances · Kits · Transfers · History |
+| **Counts, alerts and reports** | Stock counts · Inventory alerts · Inventory reports |
+| **Purchasing** | Suppliers · Purchase orders · Inventory valuation |
-The `GetCombinedInventoryList` endpoint returns aggregated inventory grouped by:
-- **Inventory Type** — What the item is
-- **Group/Station** — Where the item is located
-- **Unit** — Which unit it's assigned to
+Two lookups are linked from other modules: **Unit equipment** (everything assigned to an apparatus — linked from the Units page) and **Personnel gear** (everything signed out to a person — linked from the Personnel page).
-## Inventory Types
+If Inventory is missing from the menu, an administrator has disabled it under **Department Settings → Module Settings**.
-### Managing Types
-**Authorization:** `Inventory_Update` policy
+## Key concepts
-| Field | Required | Description |
-|-------|----------|-------------|
-| Type Name | Yes | Name of the inventory type |
-| Description | No | Type description |
-| Expires Days | No | Number of days until items expire |
-| Unit of Measure | No | Measurement unit (each, box, etc.) |
+| Concept | What it is |
+|---|---|
+| **Item** | A catalogue entry — *the kind of thing* you stock (`Nitrile gloves, large`, `SCBA cylinder 45 min`). Not a physical object. |
+| **Tracking mode** | **Bulk** counts a quantity (gloves, saline, fuel). **Serialized** tracks every unit separately with its own serial number, status and history (radios, monitors, SCBA). Decide this before adding stock; it cannot be changed later. |
+| **Category** | Optional grouping for lists and reports; categories can be nested. |
+| **Location** | Where stock lives: **Facility**, **Station**, **Unit** (apparatus), **Personnel** (a person), **Container** (a bag or cabinet inside another location) or **External**. |
+| **Lot** | A batch of one item sharing a lot number, expiry date and cost (medications, batteries, food). |
+| **Asset** | One serialized unit with a serial number, optional asset tag / barcode, status and condition. |
+| **Kit** | A fixed list of items issued together (turnout gear set, jump bag, rope kit). |
+| **Issuance** | Equipment currently signed out to a person or apparatus, with an expected return date. |
+| **Transaction** | One ledger entry: receipt, transfer, consumption, write-off, adjustment, issue, return, count variance. Never edited — mistakes are reversed with a new entry. |
-### Operations
-- **Create Type** — Add a new inventory type
-- **Edit Type** — Modify type details
-- **Delete Type** — Remove a type (validates department ownership)
+## Setting up the catalogue
-## Inventory Adjustments
+### Items
-**Authorization:** `Inventory_Create` policy
+**Inventory → Items → New item.** Three steps:
-Record inventory changes (additions or removals):
+| Step | Fields |
+|---|---|
+| **Basics** | Name, your own **code / part number**, **category**, **unit of measure** (each, box, litre …), **currency** and **unit cost** (for valuation), **preferred vendor**. |
+| **Tracking** | **Tracking mode** (bulk / serialized), **Requires lot tracking**, **Requires expiration date**, **Controlled substance** (movements need a second person to witness and are kept for audit), **Is kit**. |
+| **Stock** | **Default location** (new stock lands here if none is chosen), **Minimum** (raise a low-stock alert below this), **Reorder point** (suggest reordering at this level). |
-| Field | Required | Description |
-|-------|----------|-------------|
-| Inventory Type | Yes | What item is being adjusted |
-| Amount | Yes | Quantity (must not be 0) |
-| Station/Group | No | Location of adjustment |
-| Unit | No | Unit assignment |
-| Batch | No | Batch identifier |
-| Note | No | Adjustment notes |
+Inactive items stay in history but cannot be chosen for new movements.
-Each adjustment records:
-- Department ID
-- Timestamp
-- Acting user
-- Location (group/unit)
+
-## Inventory History
+### Locations
-**Authorization:** `Inventory_View` policy
+**Inventory → Locations → New location.** Choose the **type** and, depending on it, the **station/group**, **unit** or **person** it represents, and an optional **parent** (e.g. `Cabinet 3` inside `Station 1 supply room`). Only the name can be changed later — placement and scope are fixed at creation.
-View all inventory transactions with:
-- Type name
-- Amount and batch
-- Timestamp
-- Station/unit assignment
-- User who made the adjustment
+Every station, unit and member you can see in Resgrid can be used as a location without creating one first; explicit locations are for facilities, containers, shelves and external places (a vendor, a repair shop, a mutual-aid partner).
-## Viewing Individual Entries
+### Assets, lots and kits
-**Authorization:** `Inventory_View` policy
+- **Assets → New asset**: pick the serialized item, enter the serial number (unique per item), asset tag, condition and where it is.
+- **Lots → New lot**: item, lot number, expiry date and cost.
+- **Kits → New kit**: name the kit and list its contents (item + quantity). Kits are issued and returned as a whole.
-View a single inventory entry with full details, including the adding user's name.
+## Day-to-day movements
-## Data Endpoints
+**On hand** shows current balances by item and location. From there (or from the toolbar) you post a **movement**:
-| Endpoint | Purpose |
-|----------|---------|
-| `GetTypesList` | All inventory types with expiry info |
-| `GetCombinedInventoryList` | Consolidated inventory by type/group/unit |
-| `GetInventoryList` | All individual transactions |
+| Movement | Source | Destination | Typical use |
+|---|---|---|---|
+| **Receipt** | — | required | Stock arriving (also posted automatically by *Receive items* on a purchase order). |
+| **Transfer** | required | required (different) | Moving stock between stations or from the supply room to an engine. Both sides are written. |
+| **Consumption** | required | — | Used on a call or training. Can reference a Record / call. |
+| **Write-off** | required | — | Expired, damaged, lost. |
+| **Adjustment** | one of the two | | Correcting a balance outside a formal count. |
+| **Issue / Return** | | | Signing equipment or a kit out to a person or apparatus and back (with return condition). |
-## Interactions with Other Modules
+Enter a positive quantity, choose the lot or the specific asset where relevant, and add a **note** — it appears on the ledger and reports.
-| Module | Interaction |
-|--------|-------------|
-| **Groups** | Inventory tracked at station/group level |
-| **Units** | Inventory can be assigned to specific units |
-| **Department Settings** | Module can be enabled/disabled |
-| **Security** | Inventory adjustment permission configurable |
+
+
+### Controlled substances and witnessing
+
+For items flagged **Controlled substance**, and for some count and receipt operations, the movement is posted as *pending* with a **witness request ID**. A second, independent authorized member opens **History**, enters the request ID and **attests** to what they saw. Stock does not change until the witness approves. Both signatures are recorded on the controlled-substance log.
+
+### Asset status
+
+Open any asset (**Assets → detail**) to change its **status** — in service, issued, damaged, in repair, lost, retired. Each change writes a ledger entry. The asset detail page also shows the asset's [checklists](checklists) and [work orders](work-orders).
+
+
+
+## Counts, alerts and reports
+
+
+
+### Stock counts
+
+**Start count** freezes a snapshot of up to 100 positions (one location, or the whole department). Enter what you actually counted for every line, **save**, then **complete count** to post the variances. If stock or catalogue data changes while a count is open the snapshot is stale — cancel and start again. Newly discovered serialized equipment is recorded through *Receive*, not through a count.
+
+### Alerts
+
+Alerts list **low stock** (below minimum / reorder point), **expiring within 30 days**, **expired**, and **overdue returns**. Press **Refresh alerts** once after rollout or after importing legacy inventory; afterwards they update automatically. Alerts can be pushed to members through [Notifications](notifications).
+
+### Reports
+
+Choose a report, optional filters and a UTC date range, then **Download printable PDF** or **Schedule report delivery** (from **Profile → Reporting**):
+
+- Inventory on hand · Inventory usage · Inventory expiration · Low inventory stock
+- Inventory transfer history · Inventory issuance history · Inventory valuation
+- Controlled substance log (with performer and witness signatures)
+
+Snapshot reports ignore the date range; results are limited to 5,000 rows and to the locations you are authorized to view.
+
+## Purchasing
+
+
+
+- **Suppliers** are company records from [Contacts](contacts) linked here with an account number. Add the company in Contacts first.
+- **Purchase orders**: choose the supplier, reference number and currency, then add one line per item with quantity and unit cost. **Mark as ordered** locks the lines. **Receive items** posts all or part of the delivery to stock (one row per serialized asset with its serial number). **Cancel order** prevents further receipts and keeps what was received.
+- **Inventory valuation** totals what you hold using the cost recorded at receipt, one total per currency. Rows without a cost are listed separately.
+
+## Legacy inventory
+
+Departments that used the original (pre-2026) inventory pages will see **Initialize inventory** the first time they open the workspace. It imports existing types, balances and history into the ledger. The old *Manage Types*, *Adjust* and *History* links redirect into the new workspace.
+
+## Permissions
+
+| Permission | Default | Grants |
+|---|---|---|
+| **Inventory view** (module) | Everyone | See stock in locations you are allowed to see (group scoping applies). |
+| **Adjust Inventory** | Department admins | Post receipts, consumption, write-offs, adjustments; manage the catalogue. |
+| **Transfer Inventory** | Same as Adjust | Transfers between locations. |
+| **Issue Inventory** | Same as Adjust | Issue and return equipment and kits. |
+| **Manage controlled substances** | Department admins | Record controlled-substance transactions. |
+
+Witnessing requires a *different* member who also holds the relevant permission.
+
+## Setup examples
+
+| Department type | Suggested structure |
+|---|---|
+| **Fire** | Locations: each station + each apparatus. Serialized: SCBA packs and cylinders, TICs, radios, gas meters. Bulk with lots: foam, absorbent. Kits: turnout gear per member (issued to Personnel). Issue radios and pagers to people; put hose and tools on apparatus. |
+| **EMS** | Bulk with lots + expiry: medications, IV fluids, airway supplies — set **minimum** and **reorder point**. Controlled substances flagged with witnessing. Serialized: monitors, stretchers, ventilators. Kits: jump bags per unit. Use *Consumption* referencing the call / record. |
+| **SAR** | Team cache as a Facility location with containers per bin; personal gear issued to members with expected return; serialized GPS units, radios, ropes with retirement dates via expiry. |
+| **Emergency management** | Warehouse and trailer locations; cots, generators, water as bulk; deployable caches as kits; issuance to external agencies via an *External* location. |
+| **Security / facilities** | Uniforms and radios issued to officers; keys and access cards as serialized assets; vehicle equipment on Units. |
+| **Industrial ERT** | Rescue equipment and gas monitors as serialized assets with calibration due dates as expiry; spill supplies as bulk; work orders raised from asset status changes. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Controller | `InventoryController` (partials `InventoryOperationsController`, `InventoryPurchasingController`) |
+| Routes | `/User/Inventory/Index?tab=…`, `/User/Inventory/Operations?tab=Counts|Alerts|Reports`, `/User/Inventory/Purchasing?tab=PurchaseOrders|Vendors|Valuation`, `/User/Inventory/UnitEquipment/{unitId}`, `/User/Inventory/PersonnelGear?userId=…`, `/User/Inventory/AssetDetail/{id}` |
+| Module switch | `DepartmentModuleSettings.InventoryDisabled` |
+| Permissions | `PermissionTypes.AdjustInventory`, `TransferInventory` (47), `IssueInventory` (48), `ManageControlledSubstances` (49) |
+| Services | `IInventoryCatalogService`, `IInventoryLedgerService`, `IInventoryIssuanceService`, `IInventoryOperationsService`, `IInventoryPurchasingService` |
+| Workflow events | `InventoryAdjustedEvent` plus inventory alert notifications |
+| API | `api/v4/Inventory/*` (Unit app equipment and checklists use it) |
+| Protected data | Inventory holder and note fields are protected-data classified under [ADP](data-protection). |
diff --git a/docs/web-app/logs.md b/docs/web-app/logs.md
index 7080b25..0a59a7f 100644
--- a/docs/web-app/logs.md
+++ b/docs/web-app/logs.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 13
+sidebar_position: 21
title: Logs
---
# Logs
-The Logs module tracks department activities including run logs, work logs, and other activity records. It is managed by the `LogsController`.
+**Logs** is the original run-log and work-log module — narrative records of calls, trainings, work details and meetings with participants, units and attachments. Departments that enable the **Records** module keep Logs in **read-only** mode for history; new entries are written as [Records](records/overview) instead.
+
+**Left menu → Logs** (appears only while Records is not enabled).
+
+
## Log List
@@ -17,6 +21,8 @@ Displays all call logs and work logs with year-based filtering.
**Authorization:** `Log_Create` policy
+
+
### Log Types
The system supports five log types, each with different field requirements:
@@ -100,8 +106,17 @@ The `CreateUnitHtmlBlock` endpoint dynamically generates HTML form blocks for ad
The `TrainingPerMonth` endpoint returns training log data grouped by month and course for the current year, useful for dashboard charts.
-## Data Endpoints
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Any department not yet on Records** | Use *Run* logs for every call (link the call, add participants and units), *Training* logs for drills, *Work* logs for station duty. Move to Records when you need review workflows, NERIS or immutable history. |
+## Technical reference
+
+`LogsController`; routes `/User/Logs/{Index,NewLog,View,LogExport,DeleteWorkLog}?logId=`; permissions `CreateLog`, `DeleteLog`, `ViewLegacyRecords` (after activation); event `LogAddedEvent`; writes are denied after `RmsDepartmentCutover` activation.
+
+### Data Endpoints
| Endpoint | Purpose |
|----------|---------|
| `GetLogsList` | All logs with year filtering and permissions |
@@ -110,8 +125,7 @@ The `TrainingPerMonth` endpoint returns training log data grouped by month and c
| `GetAttachment` | Download log attachment |
| `CreateUnitHtmlBlock` | Dynamic unit time block HTML |
-## Interactions with Other Modules
-
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Calls** | Run logs create/reference calls |
diff --git a/docs/web-app/mapping.md b/docs/web-app/mapping.md
index bb42155..31b1f10 100644
--- a/docs/web-app/mapping.md
+++ b/docs/web-app/mapping.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 10
+sidebar_position: 13
title: Mapping
---
# Mapping
-The Mapping module provides interactive maps for visualizing department resources, calls, and geographic data. It is managed by the `MappingController`.
+The **Mapping** page is the live operational map: every unit and person with a recent location, active calls, stations, hydrants, points of interest and your own map layers. Use it to see who is where, route a unit to a call, and keep reference layers (districts, water sources, staging areas) at hand.
+
+**Left menu → Mapping.** Layers and points of interest are managed from the buttons on the map page; map behaviour (how long a location stays on the map) is under **Department Settings → Mapping**.
+
+
## Map View
@@ -33,6 +37,8 @@ Personnel location visibility is controlled by the `CanSeePersonnelLocations` pe
Map layers provide custom GeoJSON overlays on the map.
+
+
### Creating Layers
Layers are defined using GeoJSON `FeatureCollection` format and stored in MongoDB.
@@ -54,6 +60,8 @@ Layers are **soft-deleted** (`IsDeleted = true`) rather than permanently removed
### POI Types
+
+
Create categories for points of interest with custom markers and images.
### Individual POIs
@@ -89,8 +97,22 @@ Custom Maps allow departments to upload building floor plans, venue layouts, sch
On the main map view, use the **Custom Maps** layer control (alongside Layers, POIs, and Geofences) to toggle custom map overlays. When one or more custom maps are enabled, a **Building Selector** sidebar appears for switching between maps and floors.
-## Data Endpoints
+## Setup examples
+| Department type | How to set it up |
+|---|---|
+| **Fire** | POI types: Hydrants (or use the Records hydrant layer), Knox boxes, Dry hydrants/draft sites, Staging areas; layers: district boundaries (KML from the county GIS), water main map. |
+| **EMS** | POI types: Hospitals (with ED phone numbers in the description), Landing zones, Nursing homes; destinations on calls point at hospital POIs. |
+| **SAR** | Layers: trail systems, search segments (GeoJSON from CalTopo/SARTopo), cell coverage; POI types: trailheads, huts, helispots. Location TTL 240+ minutes. |
+| **Emergency management** | Layers: flood zones, evacuation zones, shelters; POI types: shelters, PODs, fuel sites, sandbag stations. |
+| **Security** | POI types: Client sites, Gates, Cameras; personnel location TTL 15 minutes so stale markers drop. |
+| **Delivery / transit** | Depots and customer sites as POIs; routes drawn with the Routes module; vehicle trackers for live positions. |
+
+## Technical reference
+
+`MappingController`; routes `/User/Mapping/{Index,Layers,NewLayer,EditLayer,POIs,AddPOIType,AddPOI,EditPOI,ImportPOIs,LiveRouting,StationRouting}`; data via `api/v4/Mapping/GetMapDataAndMarkers` and `GetMayLayers` (web component `rg-map`). Permissions `CanSeePersonnelLocations`, `CanSeeUnitLocations` (group-lockable). Map provider (Mapbox / Leaflet-OSM / Google) is an installation setting.
+
+### Data Endpoints
| Endpoint | Purpose |
|----------|---------|
| `GetMapData` | All map markers and geofences based on flag settings |
@@ -98,8 +120,7 @@ On the main map view, use the **Custom Maps** layer control (alongside Layers, P
| `GetPoisForType` | POI list for a specific type |
| `GetCustomMaps` | Active custom maps with floor metadata for the overlay control |
-## Interactions with Other Modules
-
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Calls** | Call locations displayed as markers; zone names used as call locations from custom maps |
diff --git a/docs/web-app/messages.md b/docs/web-app/messages.md
index 6e6321f..47b97d9 100644
--- a/docs/web-app/messages.md
+++ b/docs/web-app/messages.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 11
+sidebar_position: 31
title: Messages
---
# Messages
-The Messages module provides an internal messaging system for department communication. It is managed by the `MessagesController`.
+**Messages** is Resgrid's internal mail: send a message to individuals, groups, roles or the whole department with optional **responses** (Yes / No / Maybe or custom), delivered by push, SMS and email according to each recipient's preferences. Use it for announcements, polls (*Can you cover Saturday?*) and anything that needs a record — real-time back-and-forth belongs in [Chat](chat).
+
+**Profile dropdown → Mailbox** or the envelope icon in the top bar. Compose, Inbox and Outbox are tabs on the page.
+
+
## Inbox
@@ -30,6 +34,8 @@ Displays sent messages.
**Authorization:** `Messages_Create` policy
+
+
### Send Modes
Messages support three sending modes:
@@ -88,16 +94,28 @@ Recipients can respond to messages with:
| Delete Multiple Outbox | DELETE | Comma-separated message IDs |
| Mark Messages as Read | PUT | Comma-separated message IDs |
-## Data Endpoints
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Volunteer fire** | Weekly *training this Tuesday* message with Yes/No responses to headcount attendance; send to the *Firefighter* role. |
+| **EMS** | Shift-coverage requests with responses; department-wide policy notices with read tracking. |
+| **SAR / CERT** | Deployment availability polls (*Available for a 48 h deployment starting tomorrow?*) to the whole department. |
+| **Emergency management** | Activation notices to ESF leads with acknowledgement responses. |
+| **Security / business** | Post orders changes to a site group; use distribution lists for client contacts. |
+## Technical reference
+
+`MessagesController`; routes `/User/Messages/{Inbox,Outbox,Compose,ViewMessage,MessageResponse}`; permission `CreateMessage`; event `MessageSentEvent`; module switch `MessagingDisabled`; delivery honours contact verification and ADP generic-content rules.
+
+### Data Endpoints
| Endpoint | Purpose |
|----------|---------|
| `GetInboxMessageList` | Inbox messages with read status and sender name |
| `GetOutboxMessageList` | Sent messages |
| `GetTopUnreadMessages` | Unread messages for top navigation widget |
-## Interactions with Other Modules
-
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Groups** | Messages can target entire groups |
diff --git a/docs/web-app/navigation.md b/docs/web-app/navigation.md
new file mode 100644
index 0000000..5499e14
--- /dev/null
+++ b/docs/web-app/navigation.md
@@ -0,0 +1,69 @@
+---
+sidebar_position: 2
+title: Navigation
+---
+
+# Finding Your Way Around
+
+
+
+## The screen
+
+| Region | What is there |
+|---|---|
+| **Left sidebar** | The modules: Home, Calls, Personnel, Units, Contacts, Mapping, Shifts, Records (or Logs), Reports, Documents, Calendar, Notes, Trainings, Work Orders, Checklists, Inventory. Modules that are switched off or that you lack permission for are hidden. Collapse the sidebar with the hamburger icon on small screens. |
+| **Your name (top-left)** | Profile menu: **Profile** (edit your details, contact methods, notification preferences), **Mailbox**, **Chat**, **Your Departments** (switch between departments you belong to), **Two-Factor Authentication**, **Logout**. |
+| **Top bar** | Unread **messages** and **active calls** icons, the **search box**, the **Department menu**, **Help**, language flag and logout. |
+| **Department menu (department name, top-right)** | Everything an administrator configures — see below. |
+| **Chat / Assistant** | The floating buttons at the bottom-right of every page. |
+| **Footer** | Version number. |
+
+## The Department menu
+
+Only administrators (and group administrators for a few items) see this menu.
+
+| Item | Page |
+|---|---|
+| Department Settings | Name, time zone, address, sorting, staffing/status resets, **Module Settings**, API keys, invites. |
+| Department Profile | Public profile, logo, short name (also used on record prints). |
+| Stations and Groups | [Groups & Stations](groups-stations) |
+| Call Import Settings | Email / SMS call import — [Call settings](department-settings#call-import-settings) |
+| Custom Statuses | [Custom Statuses](custom-statuses) |
+| Text Messaging | Department SMS number and inbound text handling |
+| Templates | [Call templates and call-note templates](templates) |
+| Protocols | [Dispatch protocols](protocols) |
+| Types | [Unit, call, priority, certification, document, note types](types-configuration) |
+| Distribution Lists | [Distribution Lists](distribution-lists) |
+| Workflows | [Workflows](workflows) |
+| User Defined Fields | [User Defined Fields](user-defined-fields) |
+| Security and Permissions | [Security & Permissions](security-permissions) (permissions, audit log, SSO, security policy, data protection) |
+| Chat Moderation | [Chat moderation](chat#moderation) |
+| Subscription and Billing | [Subscription & Billing](subscription-billing) |
+| Connect | [Connect](connect) |
+| Audio / Push-to-Talk | [Voice & Audio](voice-audio) |
+| Orders | [Resource Orders](resource-orders) |
+| Links | [Department Links](department-links) |
+| Notifications | [Notifications](notifications) |
+| Weather Alerts | [Weather Alerts](weather-alerts) |
+| Commands | [Command Definitions](command-definitions) |
+| Big Board / Dispatch | Open the web versions of the Big Board and Dispatch apps |
+
+## Search
+
+The search box finds calls, personnel, units, contacts, notes, documents, records and pages by name or number. Type at least two characters; results open in place. Records narrative search is included when your department's search index allows it.
+
+
+
+## Switching departments
+
+Members of more than one department switch with **Profile → Your Departments**. Everything on screen — roster, calls, settings — belongs to the *current* department.
+
+## Language
+
+The flag in the top bar switches the interface language (English, Spanish, French, German, Italian, Polish, Swedish, Ukrainian, Greek, Arabic). Personal notification messages use the language chosen in your profile.
+
+## Help
+
+**Help** links to the support portal, video tutorials, the blog, the status page and contact form. **Help → Setup report** (administrators) shows what is still missing from your department configuration, and the **dashboard tutorial** walks through the home page.
+
+
diff --git a/docs/web-app/notes.md b/docs/web-app/notes.md
index c6ca6cd..3618e91 100644
--- a/docs/web-app/notes.md
+++ b/docs/web-app/notes.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 16
+sidebar_position: 24
title: Notes
---
# Notes
-The Notes module provides a department knowledge base for storing and sharing information. It is managed by the `NotesController`.
+**Notes** are the department's bulletin board and knowledge base: short articles with a **category**, optional **expiry**, pinned or department-wide, readable on the web and in the apps. Use them for standing orders, gate codes, hydrant out-of-service notices, meeting minutes, or *how do I …* answers.
+
+**Left menu → Notes.** Categories come from **Department → Types → Note categories**.
+
+
## Note List
@@ -15,6 +19,8 @@ Displays all notes for the department.
**Authorization:** `CanUserAddNoteAsync` runtime check
+
+
### Note Fields
| Field | Required | Description |
@@ -51,8 +57,21 @@ Creates `AuditEvent` (NoteRemoved).
Categories are managed through the [Types & Configuration](types-configuration) module:
- `GetDepartmentNotesCategories` returns distinct categories for filtering
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Fire** | Categories: Standing orders, Road closures (with expiry), Hydrants out of service, Meeting minutes. |
+| **EMS** | Hospital diversion status (expiring notes), Protocol updates, Narcotics count procedure. |
+| **SAR** | Callout procedure, Radio channel plan, Cache combination (restrict who can view via permissions). |
+| **Emergency management** | Situation reports during activations (expire after the event), Contact updates. |
+| **Security** | Site-specific notes per client group, Alarm codes (prefer Records occupancies for gate codes). |
+
+## Technical reference
+
+`NotesController`; routes `/User/Notes/{Index,NewNote,View,Edit,Delete}`; permission `CreateNote`; event `NoteAddedEvent`; module switch `NotesDisabled`.
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Types** | Note categories managed in Types controller |
diff --git a/docs/web-app/notifications.md b/docs/web-app/notifications.md
index ec56a98..c6f2d45 100644
--- a/docs/web-app/notifications.md
+++ b/docs/web-app/notifications.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 20
+sidebar_position: 33
title: Notifications
---
# Notifications
-The Notifications module configures automated notification rules that trigger based on department events. It is managed by the `NotificationsController`.
+**Notifications** are the department's automatic alerts about *readiness* rather than incidents: *fewer than two drivers available*, *Engine 1 out of service*, *a member's staffing changed*, *inventory low*, *checklist missed*. Each notification picks an event, a threshold and who to tell (everyone, a group, a role, specific people), and delivers through push, SMS and email.
+
+**Department menu → Notifications.** Personal notification *preferences* (which channels you receive) are on your [profile](profile-account#notifications).
+
+
## Notification List
@@ -18,6 +22,8 @@ Displays all configured notification rules with resolved human-readable descript
### Notification Targeting
+
+
Notifications can target:
| Target | Description |
@@ -60,8 +66,21 @@ The notification list performs extensive resolution to display human-readable in
- Event type codes → Descriptive text
- Unit type IDs → Unit type names
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Volunteer fire** | *Role availability below N* for Driver/Operator (2) and Interior FF (4) → officers; *Unit status changed to Out of service* → chief and mechanic. |
+| **EMS** | *Unit availability below 1* per station → supervisor; *Inventory alerts* → logistics role. |
+| **SAR** | *Personnel staffing changed* summary → coordinator daily; *Group availability below N* for Technical team. |
+| **Emergency management** | *Weather alert* notifications by zone; *Document added* to the EOP category → all section chiefs. |
+| **Security** | *Unit status changed* (patrol out of service) → operations centre; *Checklist missed* → site supervisor. |
+
+## Technical reference
+
+`NotificationsController`; routes `/User/Notifications/{Index,New,Delete}`; model `DepartmentNotification` (event type, threshold, target group/role/users, channels); evaluated by the notification worker on status/staffing/unit/inventory/checklist events.
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Personnel Roles** | Role-based availability alerts |
diff --git a/docs/web-app/overview.md b/docs/web-app/overview.md
index 2e37152..5fd57f9 100644
--- a/docs/web-app/overview.md
+++ b/docs/web-app/overview.md
@@ -3,129 +3,69 @@ sidebar_position: 1
title: Web Application Overview
---
-# Resgrid Web Application — User Area Overview
-
-The Resgrid web application User Area is the primary interface for managing all aspects of a department's operations. It is built on ASP.NET Core with Razor views and follows an MVC (Model-View-Controller) architecture organized under the `User` area.
-
-## Architecture
-
-All controllers in the User Area inherit from `SecureBaseController`, which provides:
-
-- **`DepartmentId`** — the current user's active department
-- **`UserId`** — the current authenticated user ID
-- **`UserName`** — the current authenticated user's name
-- **Claims-based authorization** helpers for fine-grained permission checks
-
-### Authorization Model
-
-The system uses a **two-layer authorization model**:
-
-1. **Policy-based authorization** — ASP.NET `[Authorize(Policy = "...")]` attributes on controller actions (e.g., `Call_View`, `Personnel_Create`, `Department_Update`)
-2. **Imperative authorization** — Runtime checks via Resgrid's `IAuthorizationService` for granular permissions (e.g., `CanUserEditCall`, `CanUserViewUnit`, `CanUserRemoveUser`)
-
-Permission levels can be configured per department:
-| Level | Description |
-|-------|-------------|
-| **Everyone** | All department members |
-| **Department Admins** | Only department administrators |
-| **Department + Group Admins** | Department admins and station/group administrators |
-| **Admins + Select Roles** | Admins plus users in specific personnel roles |
-
-### Audit Trail
-
-Most mutating operations fire an `AuditEvent` through the `IEventAggregator` system, capturing:
-- Before and after JSON snapshots
-- IP address and User-Agent
-- Server/machine name
-- Timestamp and acting user
-
-### Department Scoping
-
-Every data query is scoped to the current user's `DepartmentId`, ensuring complete data isolation between departments.
-
-## Feature Areas
-
-The User Area is organized into the following major feature areas:
-
-| Feature | Description | Controller |
-|---------|-------------|------------|
-| [Dashboard](dashboard) | Main operations dashboard with personnel status | `HomeController` |
-| [Department Settings](department-settings) | Department configuration and administration | `DepartmentController` |
-| [Dispatch & Calls](dispatch-calls) | Call creation, management, and dispatch operations | `DispatchController` |
-| [Personnel](personnel) | Personnel management, roles, and roster | `PersonnelController` |
-| [Units](units) | Unit management, staffing, and state tracking | `UnitsController` |
-| [Groups & Stations](groups-stations) | Station groups, membership, and geofencing | `GroupsController` |
-| [Shifts](shifts) | Shift scheduling, signups, and trades | `ShiftsController` |
-| [Workshifts](workshifts) | Static workshift scheduling | `WorkshiftsController` |
-| [Mapping](mapping) | Interactive maps, layers, POIs, and routing | `MappingController` |
-| [Messages](messages) | Internal messaging system | `MessagesController` |
-| [Calendar](calendar) | Event scheduling and RSVP | `CalendarController` |
-| [Logs](logs) | Run logs, work logs, and activity tracking | `LogsController` |
-| [Reports](reports) | Comprehensive reporting suite | `ReportsController` |
-| [Documents](documents) | Document management and sharing | `DocumentsController` |
-| [Notes](notes) | Department notes and knowledge base | `NotesController` |
-| [Trainings](trainings) | Training creation, delivery, and quizzes | `TrainingsController` |
-| [Inventory](inventory) | Equipment and supply tracking | `InventoryController` |
-| [Contacts](contacts) | External contact management | `ContactsController` |
-| [Notifications](notifications) | Notification rules and alerts | `NotificationsController` |
-| [Custom Statuses](custom-statuses) | Custom personnel and unit status definitions | `CustomStatusesController` |
-| [Types & Configuration](types-configuration) | Call types, unit types, priorities, and categories | `TypesController` |
-| [Protocols](protocols) | Dispatch protocols with triggers and scoring | `ProtocolsController` |
-| [Forms](forms) | Custom form builder with automations | `FormsController` |
-| [Templates](templates) | Call quick templates and autofills | `TemplatesController` |
-| [Command Definitions](command-definitions) | Incident command structure definitions | `CommandController` |
-| [Department Links](department-links) | Inter-department data sharing | `LinksController` |
-| [Distribution Lists](distribution-lists) | Email distribution list management | `DistributionListsController` |
-| [Resource Orders](resource-orders) | Cross-department resource ordering | `OrdersController` |
-| [Subscription & Billing](subscription-billing) | Plan management and Stripe billing | `SubscriptionController` |
-| [Security & Permissions](security-permissions) | Permission configuration and audit logs | `SecurityController` |
-| [Profile & Account](profile-account) | User profile, schedules, and certifications | `ProfileController` |
-| [Voice & Audio](voice-audio) | Voice channels and audio streams | `VoiceController` |
-| [Connect](connect) | Public department profile and posts | `ConnectController` |
-| [Search](search) | Quick navigation search | `SearchController` |
-| [Workflows](workflows) | Event-driven automation engine with templates and external actions | `WorkflowsController` |
-| [Contact Verification](../configuration/contact-verification) | Contact method verification for anti-spam protection | `ContactVerificationController` (API) |
-
-## Event System
-
-The application uses an event aggregation system (`IEventAggregator`) to decouple operations. Key events include:
-
-| Event | Triggered By | Purpose |
-|-------|-------------|---------|
-| `CallAddedEvent` | Creating a new call | Broadcasts notifications to dispatched personnel |
-| `CallUpdatedEvent` | Updating or re-opening a call | Notifies personnel of changes |
-| `CallClosedEvent` | Closing a call | Records close state and notifies |
-| `CalendarEventAddedEvent` | Creating a calendar item | Notification delivery |
-| `CalendarEventUpdatedEvent` | Updating a calendar item | Notification delivery |
-| `ShiftCreatedEvent` | Creating a shift | Notification to personnel |
-| `ShiftTradeRequestedEvent` | Requesting a shift trade | Notifies potential traders |
-| `ShiftTradeFilledEvent` | Completing a shift trade | Confirms trade |
-| `AuditEvent` | Most write operations | Audit trail recording |
-| `SecurityRefreshEvent` | Permission changes | Cache invalidation |
-| `UnitAddedEvent` | Creating a unit | System integration, workflow triggers |
-| `DocumentAddedEvent` | Uploading a document | Notification delivery, workflow triggers |
-| `LogAddedEvent` | Creating a work log | Notification delivery, workflow triggers |
-| `NoteAddedEvent` | Creating a note | Workflow triggers |
-| `UserCreatedEvent` | Adding a user to department | Workflow triggers |
-| `UserAssignedToGroupEvent` | Assigning user to a group | Workflow triggers |
-| `UserStaffingEvent` | Personnel staffing change | Workflow triggers |
-| `UserStatusEvent` | Personnel status change | Workflow triggers |
-| `UnitStatusEvent` | Unit status change | Workflow triggers |
-| `ResourceOrderAddedEvent` | Creating a resource order | Workflow triggers |
-| `MessageSentEvent` | Sending a message | Workflow triggers |
-| `TrainingAddedEvent` | Creating a training | Workflow triggers |
-| `TrainingUpdatedEvent` | Updating a training | Workflow triggers |
-| `InventoryAdjustedEvent` | Adjusting inventory | Workflow triggers |
-| `CertificationExpiringEvent` | Certification nearing expiry | Workflow triggers (daily scheduled check) |
-| `FormSubmittedEvent` | Submitting a form | Workflow triggers |
-| `PersonnelRoleChangedEvent` | Changing user role assignment | Workflow triggers |
-| `GroupAddedEvent` | Creating a department group | Workflow triggers |
-| `GroupUpdatedEvent` | Updating a department group | Workflow triggers |
-
-## Queue System
-
-Time-sensitive operations like call dispatch use the `IQueueService` to enqueue asynchronous processing:
-
-- **Call Broadcast Queue** — Sends push notifications, SMS, and email to dispatched personnel
-- **CQRS Event Queue** — Handles cache clearing and other eventual-consistency operations
-- **Workflow Queue** — Processes workflow executions asynchronously (event → template rendering → action execution)
+# Resgrid Web Application — Overview
+
+The Resgrid web application is where your department is **set up** and where officers, dispatchers, records staff and administrators do most of their day-to-day work: creating and dispatching calls, keeping the roster and units current, scheduling, writing records and reports, tracking equipment, and configuring how the mobile apps behave.
+
+The four mobile apps — **Responder**, **Unit**, **Dispatch** and **Incident Command** — and the **Big Board** are described under [Apps](../apps/responder); everything in this section is about the web site.
+
+
+
+## A map of the modules
+
+| Area | Modules | Start here |
+|---|---|---|
+| **Operations** | [Dashboard](dashboard) · [Dispatch & Calls](dispatch-calls) · [Run Cards](run-cards) · [Mapping](mapping) · [Custom Maps](custom-maps) · [Indoor Maps](indoor-maps) · [Routes](routes) · [Weather Alerts](weather-alerts) · [Voice & Audio](voice-audio) · [Chat & Assistant](chat) | *Dispatch & Calls* |
+| **People & apparatus** | [Personnel](personnel) · [Units](units) · [Hardware GPS Tracking](unit-tracking) · [Groups & Stations](groups-stations) · [Custom Statuses](custom-statuses) · [Contacts](contacts) · [Shifts](shifts) · [Workshifts](workshifts) · [Calendar](calendar) | *Personnel* |
+| **Records & reporting** | [Records (RMS)](records/overview) · [Logs (legacy)](logs) · [Reports](reports) · [Documents](documents) · [Notes](notes) · [Trainings](trainings) | *Records overview* |
+| **Readiness & logistics** | [Checklists](checklists) · [Work Orders](work-orders) · [Inventory](inventory) · [Resource Orders](resource-orders) · [Communication Tests](communication-tests) | *Checklists* |
+| **Communication** | [Messages](messages) · [Chat](chat) · [Notifications](notifications) · [Distribution Lists](distribution-lists) · [Connect](connect) | *Messages* |
+| **Configuration** | [Department Settings](department-settings) · [Types & Configuration](types-configuration) · [Templates](templates) · [Protocols](protocols) · [Forms](forms) · [User Defined Fields](user-defined-fields) · [Workflows](workflows) · [Command Definitions](command-definitions) · [Department Links](department-links) · [Call Check-in Timers](call-checkin-timers) | *Department Settings* |
+| **Security & account** | [Security & Permissions](security-permissions) · [Advanced Data Protection](data-protection) · [Account Security](account-security) · [Profile & Account](profile-account) · [Subscription & Billing](subscription-billing) · [Help & Setup](help-setup) | *Security & Permissions* |
+
+New to Resgrid? Read [Navigation](navigation) first, then follow the [department setup guide](../setup-guides/overview) for your kind of organization.
+
+## Which modules you will see
+
+Not every module appears for every department:
+
+- **Module switches** — administrators can hide Messaging, Mapping, Shifts, Logs/Records, Reports, Documents, Calendar, Notes, Training, Inventory, Checklists and Maintenance under **Department Settings → Module Settings**.
+- **Feature flags** — some newer modules (Records, Checklists, Work Orders, Run Cards, Chat) are switched on per department by Resgrid (hosted) or by the operator (self-hosted) using the `Resgrid.Console --FeatureFlags` command.
+- **Plan and add-ons** — Work Orders need the **Readiness Pro** add-on; push-to-talk needs the **PTT** add-on; encryption needs the **Advanced Data Protection** add-on; SSO/SCIM need the Enterprise tier.
+- **Permissions** — most pages check a permission (view, create, edit, delete) that administrators configure under Security & Permissions; if you cannot see something, that is usually why.
+
+## How the pages are organised
+
+Every page in this section follows the same pattern:
+
+1. **What it is for** and where to find it.
+2. **Screenshots and a walkthrough** of the pages and forms, with every setting explained.
+3. **Setup examples** for different kinds of organization — fire, EMS, search & rescue, emergency management, incident management teams, CERT, private security, industrial emergency response, delivery and transit operators.
+4. A **technical reference** (routes, permissions, feature flags, services, events) for administrators, self-hosters and developers.
+
+## Technical reference
+
+### Architecture
+
+The web site is an ASP.NET Core MVC application (`Web/Resgrid.Web`). Pages for signed-in members live in the `User` area; every controller there inherits `SecureBaseController`, which exposes the current `DepartmentId`, `UserId` and claims-based authorization helpers. Newer interactive surfaces (chat, map, assistant, moderation) are React web components in `Areas/User/Apps` that call the REST API (`Web/Resgrid.Web.Services`, `api/v4`) through a same-origin **BFF** proxy (`/api/web-bff/*`), and receive realtime updates from the **Eventing** hub (`Web/Resgrid.Web.Eventing`, SignalR).
+
+### Authorization model
+
+Two layers:
+
+1. **Policy-based** — `[Authorize(Policy = "...")]` attributes on actions (`Call_View`, `Personnel_Create`, `Department_Update` …).
+2. **Imperative** — runtime checks through `IAuthorizationService` (`CanUserEditCall`, `CanUserViewUnit`, `CanUserRemoveUser` …) and, for Records, `IRecordsAuthorizationService`.
+
+Each permission can be set per department to **Everyone**, **Department admins**, **Department + group admins** or **Admins + selected roles**.
+
+### Audit trail and events
+
+Mutating operations raise `AuditEvent`s (before/after JSON, IP, user agent, machine, timestamp, actor) through the `IEventAggregator`, and domain events (`CallAddedEvent`, `RecordFinalized`, `ChecklistCompleted`, `WorkOrderCreated`, `UnitStatusEvent` …) that drive notifications and [Workflows](workflows). Time-sensitive work (call broadcast, workflow runs, chatbot processing, NERIS submission, migrations) is queued to the worker host.
+
+### Data scoping
+
+Every query is scoped to the current `DepartmentId`; group-scoped permissions and Records group scoping narrow visibility further inside a department. Department **links** allow controlled sharing between departments.
+
+### Key configuration
+
+Configuration is not in `appsettings.json` — it is static classes under `Core/Resgrid.Config` populated from `ResgridConfig.json` or `RESGRID__Class__Field` environment variables (see [Self-hosted](../self-hosted/installation) and [Reference → Docker](../reference/docker)).
diff --git a/docs/web-app/personnel.md b/docs/web-app/personnel.md
index 6ffd3a0..d2ae0ab 100644
--- a/docs/web-app/personnel.md
+++ b/docs/web-app/personnel.md
@@ -1,166 +1,105 @@
---
-sidebar_position: 5
+sidebar_position: 7
title: Personnel
---
-# Personnel Management
+# Personnel
-The Personnel module manages department members, their roles, certifications, and access. It is handled by the `PersonnelController`.
+The **Personnel** page is your roster: every member of the department with their current **status** (Standing by, Responding, On scene …), **staffing level** (Available, Unavailable, On shift …), station, roles and contact details. From here you add members, edit their details, set their status, and manage **roles** and **ranks**.
-## Personnel List
+
-**Authorization:** `Personnel_View` policy
+## Where to find it
-The main personnel index displays all department members with:
-- Full name and profile information
-- Current action status (responding, on-scene, etc.)
-- Current staffing level (available, unavailable, etc.)
-- Group/station assignment
-- Personnel roles
-- Admin/disabled/hidden status
+**Left menu → Personnel.** The page lists members grouped by station/group (or sorted by first/last name — see *Department Settings → Sorting*). Use the group tree on the left to filter, the search box to find someone, and the checkboxes to **set status** or **set staffing** for several people at once.
-### Visibility Controls
+Each row shows name, status, staffing, roles and ID number, with buttons to **View**, **Edit** (via the profile page), **Events** and **Delete**. Hidden members are only shown to administrators.
-The personnel list respects the **authorization visibility matrix**:
-- Users only see personnel they have permission to view
-- PII (email addresses) visibility is controlled by `CanViewPII()` check
-- Personnel marked as **hidden** are not shown to non-admin users
+## Adding people
-### Sorting
+Two ways:
-Personnel can be sorted by the department's configured sort order:
-- **Default** — System default
-- **First Name** — Alphabetical by first name
-- **Last Name** — Alphabetical by last name
-- **Group** — Organized by group/station
+- **Add a Person** — create one account now.
+- **Manage Invites** — send email invitations; the person creates their own login and lands in your department (see [Department Settings → Invites](department-settings#invites)).
-### Group Tree Filtering
+
-A sidebar tree view allows filtering personnel by group/station.
+| Field | Notes |
+|---|---|
+| **First / Last name** | Required. |
+| **Email address** | Required and unique across all of Resgrid. If the address already exists in another department the existing account is **added to your department** with its profile settings; the person switches departments from *Your Departments*. |
+| **Username / Password** | Username unique; password ≥ 8 characters with a digit, an uppercase and a lowercase letter. **Require password change** forces a new password at first login. |
+| **ID number** | Your own badge / employee number. |
+| **Mobile number / carrier** | For SMS. Carrier is needed for email-to-SMS gateways; UK numbers must match the carrier's prefix rules. |
+| **Group** | Station or group; **Is group admin?** grants group-level administration. |
+| **Roles** | Tick the [roles](#roles) the person holds. |
+| **Notify user** | Send the welcome email with login details. |
-## Adding Personnel
+New accounts start with every contact method **pending verification**; the member verifies email and phone from their profile before dispatches and messages are sent to those channels ([contact verification](../configuration/contact-verification)). Adding is blocked when the plan's personnel limit is reached.
-**Authorization:** `Personnel_Create` policy + subscription limit check
+## Viewing and editing a person
-### Prerequisites
-- Department must not have reached its subscription plan's personnel limit (`CanUserAddNewUser`)
-- Group administrators can only add users to their own group (when `CanGroupAdminsAddUsers` is enabled)
+**View** shows the profile, group, roles, department flags (admin, disabled, hidden), current staffing and status, certifications, events and — where enabled — the equipment issued to them. **Edit** (or the person's profile page) changes:
-### Required Fields
+| Section | Fields |
+|---|---|
+| **Account** | Name, email, username, password reset, language, time zone. |
+| **Contact details** | Mobile, home and work numbers, mobile carrier, home and mailing addresses (home address is used for proximity / ETA). |
+| **Department** | Group, group admin, roles, **administrator**, **disabled** (cannot log in), **hidden** (kept for history but not shown on lists). |
+| **Notification options** | Which channels (push, SMS, email, voice) the person receives calls, messages, notifications and chat on. |
+| **Call / message options** | Per-priority call alerting, quiet hours, message digest settings. |
-| Field | Required | Description |
-|-------|----------|-------------|
-| First Name | Yes | User's first name |
-| Last Name | Yes | User's last name |
-| Email | Yes | Must be unique across the system |
-| Username | Yes | Login username |
-| Password | Yes | Must meet strength requirements |
+
-### Optional Fields
+### Status and staffing
-| Field | Description |
-|-------|-------------|
-| Mobile Number | SMS contact (UK carrier rules apply) |
-| Mobile Carrier | Required for text messaging |
-| Group | Station/group assignment |
-| Roles | Personnel role assignments |
+From the personnel list (or the [Dashboard](dashboard)) you can set a member's **status** and **staffing** with an optional note and, for statuses that need one, a **destination** (station or call). Bulk-select rows to update many at once. Members set their own from the apps.
-### Creation Process
-1. Validates email uniqueness across the system
-2. Creates an `IdentityUser` account
-3. Assigns user to the department
-4. Sets group membership (if specified)
-5. Saves user profile
-6. Assigns personnel roles
-7. Optionally sends a welcome/creation notification email
-8. Fires an `AuditEvent`
+### Events
-:::info Contact Verification
-When an administrator creates a new user, all contact methods (email, mobile number, home number) are initialized in the **Pending** verification state. The new user must verify their contact methods from their profile page before they will receive dispatches, notifications, or messages via those channels. See [Contact Method Verification](../configuration/contact-verification) for details.
-:::
+**Events** lists every status, staffing and location change for the person; **Generate report** prints it. Administrators can **clear all statuses** for a person (used when a test account has polluted reports).
-## Viewing Personnel
+### Removing someone
-**Authorization:** `Personnel_View` policy + `CanUserViewUser` runtime check
+**Delete** removes the member from the department. Resgrid recommends **disabling** instead of deleting so history, logs and reports stay intact; underlying data is retained, so clear personal details first if you must delete. A member who still owns unfinished [Records](records/authoring) must have them reassigned first. Deleted members can be **reactivated** by adding them again with the same email.
-The view shows:
-- User profile details
-- Group assignment
-- All assigned roles
-- Department member state (admin, disabled, hidden)
-- Last known user state (staffing level)
-- Last action log (current status)
+## Roles
-## Deleting Personnel
+**Manage Roles** (`/User/Personnel/Roles`). A role is a qualification, position or team membership you dispatch by and report on: *Firefighter*, *EMT*, *Paramedic*, *Driver/Operator*, *Officer*, *Chief*, *Team Leader*, *K9 Handler*, *Safety Officer*, *Security Officer*, *Dispatcher*.
-**Authorization:** `Personnel_Delete` policy + `CanUserRemoveUser` runtime check
+
-- Group administrators can only remove users from their group (when `CanGroupAdminsRemoveUsers` is enabled)
-- Uses `IDeleteService.DeleteUserAsync` for proper cleanup
+- **Add Role** — name, description and initial members.
+- **Edit / View Role** — members in role; **Delete** removes the role (assignments are dropped).
-## Personnel Roles
+Roles are used by call dispatch (dispatch to a role), [run cards](run-cards) (role requirements), [notifications](notifications) (low-availability alerts), [shifts](shifts) (role quotas), [checklists](checklists) and [work orders](work-orders) (assignment), security permissions (*Admins + selected roles*) and reports.
-### Viewing Roles
-**Authorization:** `Role_View` policy
+## Ranks
-Lists all personnel roles defined for the department.
+**Personnel Ranks** are display titles (Chief, Captain, Lieutenant, Firefighter) shown with names and in the apps; unlike roles they carry no dispatch meaning.
-### Creating Roles
-**Authorization:** `Role_Create` policy
+## Setup examples
-Create a role with:
-- Role name
-- Initial member assignments from form selection
+| Department | Roles to create | Tips |
+|---|---|---|
+| **Volunteer fire** | Firefighter, Interior firefighter, Driver/Operator, Officer, Chief, EMT | Use group admin for station captains; hide inactive members instead of deleting. |
+| **Career fire** | By rank *and* qualification: Engineer, Paramedic, Hazmat tech, Rescue tech | Import via [SCIM](../enterprise/scim-provisioning) if you have an HR directory. |
+| **EMS** | EMT, AEMT, Paramedic, Supervisor, Dispatcher | Certifications with expiry dates on each person. |
+| **SAR** | Ground team, Team leader, K9 handler, Technical rope, Swiftwater, Medical, Drone pilot | Roles are what you dispatch by. |
+| **Emergency management** | EOC manager, Operations, Planning, Logistics, Finance, ESF-1 … ESF-15 leads, PIO | One group per EOC section. |
+| **CERT** | CERT member, Team leader, Program coordinator | Keep contact verification strict — many volunteers. |
+| **Security** | Security officer, Supervisor, Dispatcher, Site lead | Group per client site; hidden members for former contractors. |
+| **Industrial ERT** | Fire brigade, Hazmat, Confined space, First aid, Incident commander | Certifications for every qualification with expiry reminders. |
-### Editing Roles
-**Authorization:** `Role_Update` policy + `CanUserEditRole` runtime check
+## Technical reference
-Modify role name and member assignments.
-
-### Deleting Roles
-**Authorization:** `Role_Delete` policy + `CanUserEditRole` runtime check
-
-Remove a role from the department.
-
-## Data Endpoints
-
-### Personnel Grid Data
-
-| Endpoint | Parameters | Purpose |
-|----------|------------|---------|
-| `GetPersonnelForCallGrid` | `callId` | Personnel with ETA to call location |
-| `GetPersonnelForGridWithFilter` | `filterSelf` | Basic personnel list (optionally excluding self) |
-| `GetPersonnelList` | — | Full personnel list with admin/disabled/hidden state |
-| `GetPersonnelListPaged` | `perPage`, `page` | Paginated personnel list |
-
-### ETA Calculation
-
-When displaying personnel for a call, the system calculates **Estimated Time of Arrival**:
-1. Gets the user's last known GPS location
-2. Gets the call's GPS coordinates
-3. Uses `IGeoService.GetEtaInSecondsAsync` to calculate travel time
-4. Displays ETA alongside personnel information
-
-### Role Data
-
-| Endpoint | Purpose |
-|----------|---------|
-| `GetRoles` | All department roles |
-| `GetCertifications` | All certification types |
-| `GetRolesForUser` | Roles assigned to a specific user |
-
-## Interactions with Other Modules
-
-| Module | Interaction |
-|--------|-------------|
-| **Dashboard** | Personnel status displayed on main dashboard |
-| **Dispatch** | Personnel dispatched to calls |
-| **Groups** | Personnel belong to groups/stations |
-| **Shifts** | Personnel sign up for shifts |
-| **Custom Statuses** | Custom status levels shown for personnel |
-| **Mapping** | Personnel location shown on maps (permission-controlled) |
-| **Reports** | Personnel data used in roster and staffing reports |
-| **Trainings** | Personnel assigned to trainings |
-| **Profile** | Certifications and schedules managed per person |
-| **Security** | Visibility matrix controls who can see whom |
-| **Contact Verification** | Admin-created personnel start with Pending verification; communications are gated by verification status |
+| Item | Value |
+|---|---|
+| Controller | `PersonnelController`; profile editing in `HomeController.EditUserProfile` |
+| Routes | `/User/Personnel/{Index,AddPerson,ViewPerson,DeletePerson,ViewEvents,Roles,AddRole,EditRole,ViewRole,DeleteRole}` (`?userId=` / `?roleId=`) |
+| Policies | `Personnel_View/Create/Delete`, `Role_View/Create/Update/Delete` + `CanUserViewUser`, `CanUserRemoveUser`, `CanUserEditRole` |
+| Permissions | `AddPersonnel`, `RemovePersonnel`, `ViewPersonalInfo` (PII), `ViewGroupUsers`; department settings `CanGroupAdminsAddUsers` / `CanGroupAdminsRemoveUsers` |
+| Data endpoints | `GetPersonnelForGrid`, `GetPersonnelForCallGrid?callLat=&callLong=` (with ETA), `GetPersonnelList`, `GetPersonnelListPaged`, `GetRoles`, `GetMembersForRole?id=`, `GetPersonnelEvents?userId=`, `SetActionForUser`, `SetStaffingForUser`, `SetUserActionForMultiple`, `SetUserStaffingForMultiple` |
+| Events | `UserCreatedEvent`, `UserAssignedToGroupEvent`, `PersonnelRoleChangedEvent`, `UserStaffingEvent`, `UserStatusEvent`, `AuditEvent` |
+| Plan limits | `CanUserAddNewUser` — cached 14 days; see [Subscription & Billing](subscription-billing) |
+| Protected data | Contact details and personal info are ADP-protected fields |
diff --git a/docs/web-app/profile-account.md b/docs/web-app/profile-account.md
index 0204430..fdfced0 100644
--- a/docs/web-app/profile-account.md
+++ b/docs/web-app/profile-account.md
@@ -1,16 +1,22 @@
---
-sidebar_position: 32
+sidebar_position: 50
title: Profile & Account
---
# Profile & Account
-The Profile module manages user-specific settings including scheduled reports, staffing schedules, certifications, department membership, and avatars. It is managed by the `ProfileController`. Account deletion is handled by the `AccountController`.
+Your **profile** is where you keep your own details current — name, phone numbers, addresses, avatar, language, time zone — and decide **how Resgrid reaches you**: which channels for calls, messages and notifications, quiet hours, and verified contact methods. It also holds your **certifications**, **staffing schedules** (automatic status changes), **scheduled report deliveries**, and the departments you belong to.
+
+**Profile dropdown → Profile.** Administrators can open any member's profile from Personnel.
+
+
## Scheduled Reports
**Authorization:** `Profile_View` / `Profile_Update` policies
+
+
### Viewing Scheduled Reports
Lists configured scheduled report deliveries with type, active status, day schedule, and time.
@@ -32,6 +38,8 @@ Modify existing report delivery schedules.
### Creating Staffing Schedules
+
+
**Authorization:** `Profile_View` / `Profile_Update` policies
| Field | Required | Description |
@@ -59,6 +67,8 @@ Lists all staffing schedules for a user with custom state name resolution.
### Viewing Certifications
**Authorization:** `Profile_View` policy
+
+
Lists all certifications for a user.
### Adding Certifications
@@ -94,6 +104,8 @@ Administrators can reset passwords for other users:
### Viewing Departments
Lists all departments the user belongs to with default/active indicators.
+
+
### Joining a Department
Join a new department using a department join code:
1. Enter the department's link code
@@ -180,8 +192,20 @@ Verification codes expire after 30 minutes. You can request up to 3 codes per ho
If you change your email address, mobile number, or home number, the verification status for the changed field is automatically reset to **Pending**. You must re-verify the new contact information before communications resume on that channel.
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Volunteers** | Verify email *and* mobile so SMS dispatch works; set a staffing schedule *Unavailable Mon–Fri 08:00–17:00* if you cannot leave work; enable push for calls and email for messages. |
+| **Career staff** | Push + SMS for calls only on duty days via a staffing schedule; certifications with expiry so the training officer gets reminders. |
+| **Officers / admins** | Schedule the reports you read every month to your inbox; enable 2FA. |
+| **Members of several departments** | Use *Your Departments* to switch; notification preferences are per department. |
+
+## Technical reference
+
+`ProfileController`, `HomeController.EditUserProfile`; routes `/User/Profile/{Reporting,AddNewScheduledReport,EditScheduledReport,ViewSchedules,AddNewStaffingSchedule,EditStaffingSchedule,Certifications,AddCertification,EditCertification,YourDepartments,ResetPasswordForUser}`; contact verification `api/v4/ContactVerification/*`; avatar via `GetAvatar?id=`; deletion under `/User/Account/DeleteAccount`.
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Reports** | Scheduled report delivery uses report generation |
diff --git a/docs/web-app/protocols.md b/docs/web-app/protocols.md
index f872ffe..701ee59 100644
--- a/docs/web-app/protocols.md
+++ b/docs/web-app/protocols.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 23
+sidebar_position: 41
title: Protocols
---
@@ -7,6 +7,8 @@ title: Protocols
Dispatch Protocols define structured response procedures with trigger-based activation, assessment questions, and supporting attachments. The module is managed by the `ProtocolsController`.
+
+
## Protocol List
**Authorization:** `Protocol_View` policy
@@ -89,8 +91,17 @@ Attachments can be downloaded individually:
The `GetTextForProtocol` endpoint returns just the protocol name and text as JSON (returns "No Protocol Text Present" if empty).
-## Data Endpoints
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Fire** | Structure fire protocol triggered by type + priority: questions (occupants out? hydrant nearby?), instructions and attachments (pre-plan). |
+| **EMS** | Emergency medical dispatch style protocols per chief complaint with questions and pre-arrival instructions. |
+| **Security** | Alarm response protocol: verify with alarm company, key-holder contact, police notification. |
+## Technical reference
+
+### Data Endpoints
| Endpoint | Purpose |
|----------|---------|
| `GetProtocol` | Full protocol as JSON |
@@ -98,8 +109,7 @@ The `GetTextForProtocol` endpoint returns just the protocol name and text as JSO
| `GetProtocolAttachment` | Download attachment file |
| `GetTextForProtocol` | Protocol name and text only |
-## Interactions with Other Modules
-
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Dispatch** | Protocols attached to calls; dynamic matching during call creation |
diff --git a/docs/web-app/records/_category_.json b/docs/web-app/records/_category_.json
new file mode 100644
index 0000000..32d075a
--- /dev/null
+++ b/docs/web-app/records/_category_.json
@@ -0,0 +1,8 @@
+{
+ "label": "Records (RMS)",
+ "position": 20,
+ "link": {
+ "type": "generated-index",
+ "description": "The Records Management System: operational records, NERIS incident reports, definitions, prevention (occupancies, inspections, hydrants, permits, CRR), investigations, analytics, quality review, legal holds and public-records disclosures."
+ }
+}
diff --git a/docs/web-app/records/accountability.md b/docs/web-app/records/accountability.md
new file mode 100644
index 0000000..5609c8e
--- /dev/null
+++ b/docs/web-app/records/accountability.md
@@ -0,0 +1,31 @@
+---
+sidebar_position: 18
+title: Accountability
+---
+
+# Records Accountability
+
+**Records → Reports → Accountability** answers the officer's question *"who owes me a report?"*
+
+
+
+| Column | Meaning |
+|---|---|
+| **Open** | Unfinished records (drafts, ready for review, returned). |
+| **Overdue reviews** | Reviews past the review-due hours. |
+| **Returned, not corrected** | Records sent back to the author that have not been re-submitted. |
+| **Finalized in window** | Completed in the chosen window (default 30 days). |
+| **Avg. hours to finalize** | From creation to finalization. |
+| **Oldest open** | The age of the oldest unfinished record. |
+
+Pivot **by person**, **by station/group** or **by unit**; filter by owner or group; **Show open records** lists them.
+
+**Remind** sends the owner a reminder through their notification preferences (at most once a day per record); **Remind all** reminds every owner in the current view. The result shows how many were sent and skipped.
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Route | `/User/Records/Accountability?pivot=person|group|unit&days=30&owner=&group=` |
+| Service | `IRecordsAccountabilityService` |
+| Reminders | Delivered as system messages / push through the notification pipeline; audited |
diff --git a/docs/web-app/records/analytics.md b/docs/web-app/records/analytics.md
new file mode 100644
index 0000000..a273caf
--- /dev/null
+++ b/docs/web-app/records/analytics.md
@@ -0,0 +1,41 @@
+---
+sidebar_position: 12
+title: Analytics
+---
+
+# Records Analytics
+
+Dashboards computed on demand over **finalized** records. A group-scoped viewer sees only the records they can open; department administrators see the whole department. Every dashboard takes a date range and an optional station group.
+
+Feature flag: `Records.Analytics`. Menu: **Records → Analytics**.
+
+
+
+## Dashboards
+
+| Dashboard | What it answers |
+|---|---|
+| **Executive summary** (Index) | Headline figures: records finalized, incident reports, personnel hours, NERIS acceptance rate, queues and obligations (open drafts, awaiting review, overdue now, went overdue in window), lifecycle counts (amended, voided, cancelled), records by weekday and hour heat-map, prior-period comparison. |
+| **Response performance** | Turnout, travel, total response and first-arrival times (average, median, 90th percentile) with configurable **turnout / travel targets** in seconds and the share within target; by call type, incident type, station group, hour of day and month; time on scene and unit hours on scene. |
+| **Workload** | Records by definition, by person, by unit and by station group; personnel hours and hours per member; training records and hours; median hours to finalize; median review turnaround; return rate. |
+| **Accreditation** | The figures accreditation bodies (e.g. CFAI) ask for: response-time compliance against targets, training hours, inspections completed on schedule, hydrants tested within 12 months, occupancies inspected within 12 months, CRR audience reached. |
+| **Readiness** | Composed from Checklists, Work Orders and Inventory (each module authorizes you itself): checklist completion and on-time rate, expected/missed checks by day, unit readiness board, work orders open by priority and age, mean time to repair, safety holds, equipment issued / out for repair / expiring within 30 days, readiness packets captured. |
+| **Community risk** | Occupancy risk profile (hazmat on site, no sprinklers, vacant, occupants needing assistance), inspections pass rate and days to correction, open violations by severity, permits issued / denied / expired, hydrants by flow class and tested within 12 months, CRR activities and audience. |
+
+
+
+Each dashboard can be printed; underlying rows come from [saved reports](reports-and-exports) when you need the data itself.
+
+## Setup tips
+
+- Response performance needs **unit times** on records (dispatched / en route / on scene). Departments using the Unit app get these automatically; otherwise enter them on the Run or incident report.
+- Set your **turnout and travel targets** once (they persist in the URL you bookmark) to match your standard of cover.
+- Readiness figures are empty until Checklists / Work Orders / Inventory are in use.
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/RecordsAnalytics/{Index,ResponsePerformance,Workload,Accreditation,Readiness,CommunityRisk}?start=&end=&stationGroupId=&definitionKey=&turnoutTargetSeconds=&travelTargetSeconds=` |
+| Service | `IRecordsAnalyticsService` (computed on demand; no materialized cubes) |
+| Flag | `Records.Analytics` (module says *This module is not enabled* when off) |
diff --git a/docs/web-app/records/authoring.md b/docs/web-app/records/authoring.md
new file mode 100644
index 0000000..5b2e93e
--- /dev/null
+++ b/docs/web-app/records/authoring.md
@@ -0,0 +1,111 @@
+---
+sidebar_position: 3
+title: Authoring Records
+---
+
+# Authoring Records
+
+This page covers the day-to-day work of writing, finishing and correcting records: run reports after a call, training records, work and meeting records, unit activity, and any department-designed form. NERIS incident reports have their own page — see [NERIS incident reports](incident-reports).
+
+## Creating a record
+
+**Records → All records → New Record**, then choose the **definition** (record type). Some types can also be started from elsewhere:
+
+- From a **call** — *View call → Records* offers *Run* and the NERIS incident report pre-linked to that call.
+- From a **unit** — *Units → Logs* starts a **Unit activity** record.
+- From the **Responder / Unit / Incident Command / Dispatch apps** when Field Records is enabled for that app.
+
+
+
+### Built-in (locked) record types
+
+| Type | Number prefix | Typical use | Notable fields |
+|---|---|---|---|
+| **Run** | RUN | The department's report of a response. | Call link (with a call snapshot), narrative, participants with roles, units with dispatched / en-route / on-scene / released / in-quarters times, other agencies, attachments. |
+| **Training** | TRN | A drill, class or course. | Course, course code, instructors, location, start/end, participants, other personnel. |
+| **Work** | WRK | Station or equipment work detail. | Narrative, participants, units, station/group. |
+| **Meeting** | MTG | Business, officers', committee meetings. | Meeting type, facilitator, location, attendees. |
+| **Coroner** | COR | Coroner / medical-examiner notification (restricted class). | Case number, body location, pronounced deceased by, investigator, initial report / condition, cause. |
+| **Callback** | CBK | Personnel called back to duty. | Contact name/number, destination, participants. |
+| **Unit activity** | UNT | One unit's activity for a call or period (replaces *Unit Logs*). One record per unit per call. | Unit, activity time, narrative, crew. |
+
+Locked types cannot be redesigned, but you can add department fields to them with [User Defined Fields](../user-defined-fields) (entity type *Record*, scoped to a definition). UDF values are stored, printed and reportable but are never included in a standardized export.
+
+### Filling in the form
+
+- **Station / group** anchors the record for group-scoped visibility and per-group numbering.
+- **Call** — choose an active or archived call. If a record of the same type already exists for that call you will see a *duplicate warning* and must give a reason for a second one (or the definition may allow only one).
+- **Historical calls** — for a past incident that was never dispatched through Resgrid, save the draft and use **Create a call for this run**: it creates a *closed* call (dispatching nobody) and links it.
+- **Participants** — add members with a role and the unit they were on; the unit defaults from their current assignment.
+- **Narrative** is required on most types.
+- **Attachments** — files are virus-scanned; each file has a **classification** (*Restricted* or *Unrestricted operational content*) that also covers its name and description. Photo location metadata is stripped on upload unless the definition keeps it.
+- Fields marked with a lock are **restricted** and visible only to members with *View restricted records*.
+- Department definitions may show or require fields as you type (rules).
+
+**Save draft** keeps working; drafts autosave and can be resumed from any device. **Save and finalize** writes the immutable revision in one step (Quick entry preset).
+
+## Review, approval and finalization
+
+The definition's **lifecycle preset** decides the path:
+
+| Preset | Path | Who does what |
+|---|---|---|
+| **Quick entry** | Draft → Finalized | The author, holding *Create* and *Finalize records*. Fastest — preserves the speed of the old Logs flow. |
+| **Review required** | Draft → Ready for review → Finalized (or → Returned → Draft) | Author submits for review; a member with *Review records* finalizes or **returns for correction** with a reason code. Review due hours drive the *overdue* queue. |
+| **Approval / acknowledgement** | Draft → Ready for review → Approved → Finalized | Adds an approver (with *Approve records*) who may not be the author. |
+
+At finalization the author may be asked to **attest** (*I attest that this record is accurate and complete…*) and, for some definitions, to sign.
+
+
+
+## After finalization
+
+The details page shows the record as it stands, the **call snapshot** (the call as it was when linked), participants, units, attachments and the **History** of revisions with checksum, transition and actor. From it you can:
+
+| Action | Effect |
+|---|---|
+| **View revision / Compare with previous** | Opens a specific revision, or a side-by-side diff (restricted fields show *values withheld* if you lack access). |
+| **Print / Save as PDF** | Uses the department [print layout](settings#print-layout) and the pinned revision. Prints carry a provenance footer (printed by / on, layout version). |
+| **Export** | JSON of the revision. |
+| **Amend** | Opens an amendment draft. The last finalized revision stays authoritative until the amendment is finalized; **Abandon amendment** discards it. |
+| **Void** | Marks the record invalid with a reason code and text. Terminal. |
+| **Reassign** | Transfers ownership of an *unfinished* record to another member (audited; author and history unchanged). |
+| **Cancel draft** | Abandons an unfinished record and releases its number. |
+
+## Evidence
+
+Records can **capture evidence** from other modules as bounded, checksummed snapshots that never change (a correction is a new capture):
+
+| Evidence source | What is captured |
+|---|---|
+| **Dispatch decision** | The run-card activation and recommendations recorded for the call. |
+| **Unit tracking fixes** | Up to 24 GPS fixes per unit for up to 20 units in a window of at most 24 hours. |
+| **Certifications at the incident time** | Qualification status of chosen personnel (certificate numbers and files stay in Certifications). |
+| **Supplies and controlled substances used** | Inventory consumption already recorded against the call. |
+| **Promoted incident messages** | Selected chat messages (with thread replies) from an incident channel. |
+| **Readiness at the time of the call** | The Checklists readiness packet. |
+| **Module projection** | A bounded snapshot from another module: personnel check-in, resource summary, qualifications, command summary. |
+
+Open the record → **Evidence**, choose the source, give a reason (required on official records) and **Capture**. Draft captures become part of the signed revision; a **verified manifest** can be downloaded for each artifact.
+
+
+
+## Protected data
+
+When the department is enrolled in [Advanced Data Protection](../data-protection), narrative, participant and other classified fields are stored encrypted. The page shows a **Protected record** banner; press **Verify and open** to reveal them for the session. Saving a form also needs verification, so verify *before* editing.
+
+## Tips
+
+- Finalize promptly — the accountability report and reminders are driven by open records.
+- Use **Return for correction** with a clear reason code instead of editing someone else's draft.
+- Never finalize with placeholder text; amendments are visible forever in history.
+- Restricted attachments (photos of victims, PII documents) must be classified *Restricted* at upload.
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/Records/New?definitionKey=&callId=`, `/User/Records/Edit/{id}`, `/User/Records/Details/{id}`, `/User/Records/Revision/{id}?revisionId=`, `/User/Records/Diff/{id}?from=&to=`, `/User/Records/Print/{id}`, `/User/Records/Export/{id}`, `/User/Records/NewRunCall/{id}`, `/User/RecordEvidence/Index?recordId=&recordKind=`, `/User/RecordDocuments/{Revision,Export,Diff,PrintDiff}` |
+| Cardinality | *Single authoritative per call* (NERIS), *Multiple per call* (Run, Work, Coroner, Callback, department definitions), *One per subject per call* (Unit activity). Enforced on create; void/cancel releases the slot. |
+| Concurrency | Drafts use ETag merge; a stale save shows *This record was changed by someone else…*. |
+| Attachments | Scanned by the scanning provider before they are readable; `RmsAttachment.Classification` controls visibility. |
diff --git a/docs/web-app/records/community-risk-reduction.md b/docs/web-app/records/community-risk-reduction.md
new file mode 100644
index 0000000..6bcf06e
--- /dev/null
+++ b/docs/web-app/records/community-risk-reduction.md
@@ -0,0 +1,46 @@
+---
+sidebar_position: 10
+title: Community Risk Reduction
+---
+
+# Community Risk Reduction (CRR)
+
+Record the outreach and prevention work your department does — smoke-alarm installs, school visits, station tours, public education, car-seat checks, senior fall-prevention visits — so it counts toward accreditation, grant reporting and the community-risk dashboard.
+
+Feature flag: `Records.Prevention.Crr`. Menu: **Records → Community risk reduction**.
+
+
+
+## Recording an activity
+
+**New activity**:
+
+| Field | Notes |
+|---|---|
+| **Title / Kind** | Smoke alarm installation, public education, station tour, home safety visit, school program, media, other. |
+| **Occurred on / Location / Coordinates / Occupancy** | Where and when; link to an [occupancy](occupancies) when it was at a tracked property. |
+| **Audience** | Number of people reached. |
+| **Hours** | Staff hours spent. |
+| **Staff** | Members who took part. |
+| **Smoke alarms installed** | Count. |
+| **Outcome** | Free text. |
+
+
+
+The list shows a **summary for the period** (activities, audience reached, hours, smoke alarms) and feeds the **Community risk** analytics dashboard.
+
+## Setup examples
+
+| Department | Use |
+|---|---|
+| **Fire / accreditation (CFAI)** | Log every public-education contact; export the period summary for the CRR standard of cover. |
+| **EMS** | Community paramedicine visits and CPR classes as *Public education*. |
+| **CERT / emergency management** | Preparedness fairs, neighbourhood training, sandbag distribution events. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/RecordCrr/{Index,Edit}` |
+| Model | `RmsCrrActivity` |
+| Flag / permission | `Records.Prevention.Crr`; `RecordsPreventionAdmin` to create/edit |
diff --git a/docs/web-app/records/dashboard-and-queue.md b/docs/web-app/records/dashboard-and-queue.md
new file mode 100644
index 0000000..f83a4c7
--- /dev/null
+++ b/docs/web-app/records/dashboard-and-queue.md
@@ -0,0 +1,77 @@
+---
+sidebar_position: 2
+title: Dashboard & Work Queue
+---
+
+# Records Dashboard & Work Queue
+
+## Records dashboard
+
+**Records → Records dashboard** is the "what needs doing" page for officers and records staff.
+
+
+
+| Tile | Shows |
+|---|---|
+| **Incomplete reports** | NERIS incident reports started but not finalized. |
+| **Awaiting review** | Records submitted for review and not yet approved. |
+| **Rejected** | Reports rejected by NERIS and not yet corrected. |
+| **Overdue** | Obligations past their due date (reviews, approvals, records requests). |
+| **Incident reports** | Counts by state: incomplete, awaiting review, submitted, accepted, rejected, analyses awaiting filing. |
+| **Operational records** | Drafts, awaiting review, returned for correction. |
+| **Records requests** | Open and overdue public-records requests. |
+| **Crosswalk coverage** | How many local call types map to a NERIS incident type; unmapped types must be classified by hand on every report. |
+
+Each tile links to the filtered queue. If a source is unavailable the dashboard shows *Some counts could not be produced* rather than failing.
+
+## All records (the work queue)
+
+**Records → All records** lists every record you are allowed to see.
+
+
+
+### Filtering and search
+
+| Control | Notes |
+|---|---|
+| **Search records** | Record numbers, summaries and other safe fields. Narrative text is included when the department's search index allows it (it is withdrawn under Advanced Data Protection). |
+| **Records for year** | Defaults to the current year; *All years* is available. |
+| **Type** | A definition (Run, Training, NERIS incident, your own definitions …). |
+| **State** | Draft, Ready for review, Returned, Approved, Finalized, Amended, Voided, Cancelled, Submitted, Accepted, Rejected. |
+| **Owner / Group** | Who owes the record; which station/group it is anchored to. |
+
+### Row actions
+
+Each row shows record number, type, state, summary, occurred date and author, with **View** (details), **Edit** (drafts and returned records you own or may edit) and the revision history.
+
+### Bulk actions
+
+Select rows (or *Select all on this page*) to:
+
+- **Assign for review** — pick a reviewer and a reason; each record moves to *Ready for review*.
+- **Compile a packet** — a **compiled PDF** or **zip bundle** of the selected finalized records, with a title and an audited purpose, optionally emailed to an address. Packets stay downloadable for 30 days. There is no bulk void or delete.
+
+### Exporting the list
+
+**Reports → Export this list → CSV / JSON** exports the current filter (capped at a maximum row count; narrow the filter to export more). Every export is audited and respects restricted-field rules.
+
+## Accountability
+
+**Reports → Accountability** answers *who owes a report*: open records, overdue reviews and returned-but-not-corrected records pivoted **by person**, **by station/group** or **by unit** over a window (default 30 days), with average hours to finalize and the oldest open record. **Remind** sends the owner a reminder (at most once a day per record); **Remind all** does it for everyone in the view.
+
+
+
+## Field Records rollout
+
+**Manage → Field Records rollout** (administrators) shows how each operational app — Responder, Unit, Incident Command, Dispatch — is doing with Records: whether the flag is on, who is on a usable version, records started/finalized/abandoned in the app, catalog refusals, sync conflicts and attachment failures. Counts only; it never shows record content.
+
+## Release health
+
+**Manage → Release health** is an operations page for the first weeks after activation: legacy write attempts blocked, event-outbox lag, workflow runs, attachment scan state and prevention counters.
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/Records/Dashboard`, `/User/Records/Index?year=&definitionKey=&state=&q=&owner=&group=&page=`, `/User/Records/ExportList?format=csv|json`, `/User/Records/Bulk` (POST), `/User/Records/Accountability?pivot=person|group|unit&days=`, `/User/Records/FieldRollout`, `/User/RecordsHealth/Index` |
+| Services | `IRecordsService`, `IRecordsSearchService`, `IRecordsBulkPacketService`, `IRecordsAccountabilityService` |
diff --git a/docs/web-app/records/definitions.md b/docs/web-app/records/definitions.md
new file mode 100644
index 0000000..4557cc1
--- /dev/null
+++ b/docs/web-app/records/definitions.md
@@ -0,0 +1,114 @@
+---
+sidebar_position: 5
+title: Definitions & Templates
+---
+
+# Record Definitions & Templates
+
+A **definition** describes a form your department fills out: its sections and fields, the rules that show or require fields, how records are numbered, who reviews or approves, how long records are kept, and which apps may author them. Publishing freezes a version; every record pins the version it was written on.
+
+**Records → Manage → Definitions** (requires *Manage record definitions*).
+
+
+
+## Locked vs department definitions
+
+| | Locked (system) definitions | Department definitions |
+|---|---|---|
+| Examples | Run, Training, Work, Meeting, Coroner, Callback, Unit activity, NERIS incident | Security patrol log, SAR clue report, EOC shift log, ICS 214, your own inspection form |
+| Who designs | Resgrid (product) | Your department |
+| What you can change | Lifecycle preset, reviewer/approver roles, due hours, numbering, retention, client surfaces, print layout; extend with User Defined Fields | Everything |
+| Export behaviour | Standardized exports never include department fields | Included in department exports and saved reports |
+
+## Creating a definition
+
+**New definition** offers three starting points:
+
+- **Start from template** — browse the template packs (below), preview sections and fields, choose the jurisdiction profile (`generic`, `us`, `ca`) and locale, and **Use this template**.
+- **Clone existing definition** — copy one of your own definitions (or a locked one's layout) under a new key.
+- **Blank definition** — start from an empty schema.
+
+The **key** (lower-case letters, digits, dots and dashes; may not start with `system.`) cannot change after creation — apps, exports and workflows depend on it.
+
+
+
+### Template packs
+
+| Pack | Templates | Category |
+|---|---|---|
+| **Operational report templates** | Security Patrol Log · Security Incident Report · Delivery Run Report · Bus/Route End-of-Day Summary · General Shift/Activity Summary · Job/Service Completion | Security, Delivery, Transit, Operations, Field service |
+| **CERT Operations Pack** | CERT Damage Assessment · CERT Assignment Tracking · CERT Activity / Communications Log | CERT |
+| **SAR Mission Pack** | SAR Mission Summary · SAR Segment Debrief (coverage / POD) · SAR Clue Report | SAR |
+| **Disaster Field Assessment and Mass Care Pack** | Rapid Needs / Initial Damage Assessment (infrastructure impact, Community Lifelines) | Disaster |
+| **EOC Coordination Pack** | EOC Duty / Shift Log · Agency / ESF Status Report | EOC |
+| **HAZMAT Response Pack** | HAZMAT Release / Response (size-up, product, monitoring, decon, notifications, critique) | HAZMAT |
+| **Industrial Operations and Process Safety Pack** | Operator / Control-Room Shift Handover · Incident / Near Miss | Industrial |
+| **Exercise, Drill and AAR/IP Pack** | After-Action Report / Improvement Plan (links to Work Orders, Checklists, training) | Exercise |
+| **Mutual Aid and Deployment Pack** | Deployment (External Order) | Mutual aid |
+| **Incident Support (ICS Logistics, Finance and Administration)** | ICS 202, 203, 204, 205, 205A, 206, 207, 208, 209, 210, 211, 213, 213RR, 214, 215, 215A, 217A, 218, 219, 220, 221, 225, 260; OF-286, OF-288, OF-294, OF-296, OF-297, OF-315; SF-261; Incident Action Plan package; ICS Canada variants | Incident support / Incident business |
+
+Templates marked **Preview** are usable but still being validated with departments. Each template shows its sources and review date; after you create from one, the editor shows **differences from the template** as it evolves.
+
+## The definition editor
+
+
+
+### Settings
+
+| Setting | Meaning |
+|---|---|
+| **Name / Category / Description / Owner** | Display metadata. |
+| **Lifecycle preset** | Quick entry, Review required, Approval / acknowledgement. |
+| **Reviewer roles / Approver roles** | Personnel roles allowed to review / approve. Approvers may not approve their own records. |
+| **Review due (hours) / Approval due (hours)** | Drive the overdue queue and reminders. |
+| **Require author attestation at finalize** | Adds the attestation statement. |
+| **Numbering** | Prefix, sequence width, when the number is assigned, sequence per station, sequence per incident, reset yearly. |
+| **Records per call** | *Multiple per call*, *One authoritative per call*, or *One per subject per call*. |
+| **Permitted subjects** | What a record may be about (contact, unit, call, person …). |
+| **Classification / Retention (years)** | Restricted classes default to permanent retention; `0` = permanent. |
+| **Client surfaces / Allow offline / Allow attachments** | Which apps (Responder, Unit, Incident Command, Dispatch) may author it, whether offline drafts are allowed. |
+| **Keep photo coordinates on attachments** | Off by default; turn on only for damage assessments, clue reports and similar. |
+| **Migration map (JSON)** | How values move from an older version to this one. |
+
+### Schema
+
+The schema is a JSON document of **sections**, each holding **fields** with a key, label, type and optional rules. The **Fields** table below the editor reflects the last saved draft.
+
+| Field types | ShortText, LongText, Number, Boolean, Date, DateTime, Select, MultiSelect, Person, Unit, Contact, Address, Coordinates, Attachment, Signature, Reference |
+|---|---|
+| Section kinds | Plain sections and **repeating** row groups (checkpoints, involved persons, violations …) with a row limit |
+| Rules | *Show when*, *Require when*, value ranges, restricted classification per field |
+
+**Validate** checks the schema; **Save draft** stores it; **Review impact & publish** shows what publishing affects — open drafts on the current version, finalized records on earlier versions, breaking changes and client readiness — before **Publish**. Published versions are read-only; **Open new draft** starts the next version. **Migrate open drafts** moves drafts to the newer version (unmapped values are dropped).
+
+### History, compare and retire
+
+- **History** lists every version with state, published date and change notes; **Compare** shows the diff between two versions.
+- **Retire** stops new records; existing records stay readable.
+
+## Print layout
+
+**Print layout** (per definition) orders, renames or hides sections and fields for print and PDF, adds page breaks, places the signature block (at the end / inline / hidden) and attachment list (table / list / hidden), and can override the department letterhead for this definition. Every save is a new layout version stamped in the print footer.
+
+## Setup examples
+
+| Department type | Definitions to create |
+|---|---|
+| **Fire** | Keep the locked types; add UDFs to Run (e.g. *Mutual aid given/received*, *Water used*). Add *After-Action Report* for major incidents. |
+| **EMS** | Run + Unit activity for operations; *Controlled Substance Discrepancy* (blank, Approval preset, restricted). |
+| **SAR** | SAR Mission Pack (all three), Exercise AAR, ICS 214 for team members, ICS 211 for check-in. |
+| **Emergency management / EOC** | EOC Duty / Shift Log (Quick entry), Agency / ESF Status Report (Review required), Rapid Needs Assessment, ICS 209, 213RR, 260. |
+| **Incident management team** | The whole Incident Support pack; number ICS forms *per incident*. |
+| **Security company** | Security Patrol Log (Quick entry, prefix PAT, sequence per site) and Security Incident Report (Review required, restricted involved-persons rows). |
+| **Delivery / transit / field service** | Delivery Run Report, Bus/Route End-of-Day, Job/Service Completion; permitted subjects *contact* and *unit*. |
+| **Industrial** | Shift Handover (Quick entry, one per unit per shift) and Incident / Near Miss (Approval preset, HSE role as approver). |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/RecordDefinitions/{Index,Templates,Create,Edit,Impact,History,Layout}` |
+| Model | `RmsDefinition` / `RmsDefinitionVersion` (schema JSON), `RmsTemplatePack`, jurisdiction profiles seeded by M0162 |
+| Services | `IRecordDefinitionsService`, `IRecordTemplatePacksService` |
+| Permissions | `ManageRecordDefinitions` (62), `PublishRecordDefinitions` (63) |
+| API | `api/v4/RecordDefinitions/*` — the apps download the published catalog; *Catalog requests refused* on the rollout page usually means an app version below the definition's minimum |
diff --git a/docs/web-app/records/deployments.md b/docs/web-app/records/deployments.md
new file mode 100644
index 0000000..9db67b6
--- /dev/null
+++ b/docs/web-app/records/deployments.md
@@ -0,0 +1,62 @@
+---
+sidebar_position: 15
+title: Deployments & Connectors
+---
+
+# Deployments & External Connectors
+
+**Deployments** track the external resource orders your department fills — a strike team sent on a wildland assignment through IROC, a crew loaned under EMAC, a Canadian request through CIFFC — from the order through mobilization, release and close-out. The ordering system stays authoritative: the order document is stored as an **immutable, checksummed snapshot** and nothing is ever written back.
+
+:::note Preview feature
+Deployments and connectors are a **Preview** feature. Fixtures were built from published IROC, CIFFC and EMAC documentation, not live integrations. Verify against your ordering system.
+:::
+
+Menu: **Records → Manage → Deployments**.
+
+
+
+## Recording a deployment
+
+**New deployment**:
+
+| Field group | Contents |
+|---|---|
+| **Order** | Order number, incident, country / subdivision, ordering and dispatch offices. |
+| **Agencies** | Requesting, receiving and sending agency; the **department role** — *Filling the order*, *Requesting resources* or *Hosting incident*. |
+| **Cost** | Cost code, agreement reference, currency / units / time zone. |
+| **Order artifact** | Upload the order document (PDF, JSON or CSV) from the source system; stored as a snapshot with source system and version. |
+| **First fill (optional)** | Request number, resource, position, trainee, assigned person, home unit, host agency, needed on. |
+
+From the deployment page add further **fills**, update their status (requested → assigned → mobilized → released → returned, or declined with a reason), **record a new snapshot** when the order changes (the previous snapshot is kept and superseded) and finally **close out** (every accepted fill must be *Returned* first).
+
+## External connectors
+
+**Records → Manage → Deployments → External connectors** reads orders automatically from a source that serves the **Resgrid Mutual-Aid Order Feed v1** (JSON). Screen-scraping is not supported.
+
+| Setting | Notes |
+|---|---|
+| **Connector name / Feed provider / Source system / Feed root (https)** | Where to read. |
+| **Credential kind / header name / credential** | Encrypted at rest, never shown again. |
+| **Read authority granted** | Write authority is never granted in this release. |
+| **Poll interval (minutes) / Requests per hour** | Request limits. |
+| **Source terms** | Acknowledge the source's terms before the connector can be enabled. |
+| **Inbound push endpoint / Inbound token** | For sources that push; the token is shown once. |
+
+Every read lands as a new snapshot; **Reconciliation** lists where the source and your record disagree (source released but a fill not returned, request exists in the source but not locally …) and a coordinator decides — nothing is applied automatically. The **Run log** shows each poll's outcome and counts.
+
+## Setup examples
+
+| Department | Use |
+|---|---|
+| **Wildland / type 3 IMT** | One deployment per resource order; fills per crew member; snapshots when IROC updates the order. |
+| **State EMA** | Role *Requesting resources* for EMAC missions received; *Hosting incident* for incoming teams. |
+| **Municipal fire** | Mutual-aid strike team deployments with cost codes for FEMA reimbursement. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/RecordDeployments/{Index,New,Details,Artifact}`, `/User/RecordDeploymentConnectors/{Index,New,Edit}` |
+| Model | `RmsExternalOrder`, `RmsExternalOrderFill`, `RmsExternalOrderSnapshot`, `RmsExternalOrderConnector` |
+| Feed contract | `docs/architecture/rms-mutual-aid-order-feed-v1.md` (Core repository) |
+| Config | Connectors can be switched off per installation (*External connectors are switched off*). |
diff --git a/docs/web-app/records/hydrants.md b/docs/web-app/records/hydrants.md
new file mode 100644
index 0000000..442a42f
--- /dev/null
+++ b/docs/web-app/records/hydrants.md
@@ -0,0 +1,60 @@
+---
+sidebar_position: 8
+title: Hydrants & Water Sources
+---
+
+# Hydrants & Water Sources
+
+Track every hydrant and water source in your district: location, owner, main size, flow tests with the **NFPA 291 flow class**, maintenance history and in/out-of-service status — shown on a colour-coded map and available to the apps and dispatch.
+
+Feature flag: `Records.Prevention.Hydrants`. Menu: **Records → Hydrants**.
+
+
+
+## The hydrant list and map
+
+The header shows *N hydrants, N out of service, N due for a flow test*. The **Map** colours each hydrant by flow class (black = out of service). Filter, search by number or address, or open one for details.
+
+## Adding hydrants
+
+**New hydrant** or **Import hydrants** (CSV with a header row: `number, latitude, longitude, type, address, main_size, flow_gpm, owner` — existing numbers are updated).
+
+
+
+| Field | Notes |
+|---|---|
+| **Hydrant #** | Your identifier; unique per department. |
+| **Type** | Dry barrel, wet barrel, standpipe, draft site, tank, cistern … |
+| **Address / Coordinates / Point of interest** | Position; can be linked to a map POI. |
+| **Owner / Owner name** | Municipal, private, utility. |
+| **Main size (in)** | Water main diameter. |
+| **Flow (gpm), Static / Residual (psi)** | The last known values. Recording a flow test updates them automatically. |
+
+## Flow tests and maintenance
+
+On the details page:
+
+- **Record flow test** — enter static pressure, residual pressure, pitot pressure and outlet diameter. Flow is computed as `29.83 × c × d² × √pitot`, rounded to 10 gpm, and the NFPA 291 class (AA / A / B / C) is set from it.
+- **Record maintenance** — date, kind (flush, paint, repair, replace cap …) and note.
+- **Take out of service / Return to service** — with a reason; out-of-service hydrants are black on every map and flagged to crews.
+
+
+
+Analytics reports hydrants **tested in the last 12 months**, **in service** and **by flow class**.
+
+## Setup examples
+
+| Department | Notes |
+|---|---|
+| **Municipal fire** | Import from the water utility's GIS export; schedule annual flow tests by district; use *Owner* to distinguish private hydrants. |
+| **Rural / wildland** | Add draft sites, cisterns and tanks as water sources with their capacity in the notes; flow tests optional. |
+| **Industrial site** | Plant hydrants and monitors keyed to the site grid; maintenance log for the fire-water system. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/RecordHydrants/{Index,Details,Edit}` |
+| Model | `RmsHydrant`, `RmsHydrantFlowTest`, `RmsHydrantMaintenance` |
+| Flag / permission | `Records.Prevention.Hydrants`; `RecordsPreventionAdmin` to edit |
+| Apps | Hydrant layer is available to the Unit and Responder maps and to the dispatch call map. |
diff --git a/docs/web-app/records/incident-reports.md b/docs/web-app/records/incident-reports.md
new file mode 100644
index 0000000..7cf2a5b
--- /dev/null
+++ b/docs/web-app/records/incident-reports.md
@@ -0,0 +1,111 @@
+---
+sidebar_position: 4
+title: NERIS Incident Reports
+---
+
+# NERIS Incident Reports
+
+**NERIS** (National Emergency Response Information System) is the US national fire-incident reporting standard that replaced NFIRS on 2026-01-31. Resgrid keeps **one authoritative incident report per call**, starts it from the dispatched call so most facts are prefilled with their source recorded, validates it against the pinned NERIS contract, and (when enabled) submits it to NERIS and tracks the destination's answer.
+
+:::info Outside the US?
+You can still author and finalize incident reports for your own records. Submission simply stays off (*NERIS submission is not enabled for this department*).
+:::
+
+
+
+## Where to find it
+
+**Records → All records → Incident reports** (or the *Incident reports* tile on the dashboard). The queue lists reports by year and state: *Incomplete*, *Awaiting review*, *Submitted*, *Accepted*, *Rejected*, *Corrected*.
+
+## Starting a report
+
+1. **Start from call** — choose an active or closed call. Only closed calls that do not already have a report are offered; if the call already has one you are taken to it.
+2. The report opens **prefilled** from the call: dispatch times (created, answered, received at dispatch, unit dispatched / en route / on scene / cleared), address, coordinates, dispatch incident code and determinant, units and their NERIS unit IDs, and the NERIS incident type from the **call-type crosswalk**.
+3. Every prefilled value carries its **provenance** — *Dispatch*, *App*, *Derived*, *Imported* — and if you correct it the original stays beside the corrected value.
+
+You can also start one from **View call → Incident report** in Dispatch.
+
+## Working through the report
+
+
+
+The form follows the NERIS sections:
+
+| Section | Content |
+|---|---|
+| **Dispatch times & center** | Call created / answered / received, incident cleared, dispatch center, determinant code, dispatch incident code. |
+| **Incident types** | Primary and secondary NERIS type codes; special modifiers. Choosing types opens the **conditional sections** that apply. |
+| **Location** | Street number, street, municipality, county, state, postal code, country, place type, location use, cross street, coordinates. |
+| **Units & responses** | Per unit: NERIS unit ID, staffing, response mode, dispatched / en route / staged / on scene / canceled en route / cleared. |
+| **Mutual aid** | Direction, aid type, agency and its NERIS ID, non-fire agencies. |
+| **Actions & tactics** | Tactic, unit, time; impediment and outcome narratives. |
+| **Disposition & people** | Disposition, people present, displaced, animals rescued. |
+| **Casualties & rescues** | Civilian / firefighter casualties, injuries, fatalities, cause, action at the time; rescue type, mode, path, elevation. |
+| **Conditional sections** | Fire detail, structure-fire location and origin, outdoor fire, hazardous situation, chemical / product released, medical (patient care), alarms and suppression systems, electrical / power-generation / CSST / home-oxygen hazards, battery involvement … shown only when the incident types require them. |
+| **Exposures, properties, vehicles** | Exposed items, property details (construction, storeys, sprinklers, year built, values and losses), vehicles (make, model, VIN, plate, body style, powertrain). |
+| **Resources** | Department-only resource notes — kept on the department record, never sent to NERIS. |
+| **Department custom fields** | User Defined Fields you attached to the NERIS definition. Captured and printed, never transmitted. |
+| **Attachments** | Files with restricted / unrestricted classification. |
+
+**Save and validate** runs the NERIS rules locally and lists **validation issues** by severity, rule and source. Errors block finalization; warnings do not. **Validate with NERIS** sends a validation-only request to the destination when the profile is configured.
+
+### Review and attestation
+
+Incident reports follow the *Review required* or *Approval* preset configured in [Records settings](settings). The officer submits for review; the reviewer finalizes or returns for correction. Finalization records the **attestations** (signer, signed on).
+
+## Submitting to NERIS
+
+When the department's **NERIS settings** are configured and *Enable NERIS submission* is on:
+
+- **Submit to NERIS** queues the finalized revision. With *Submit automatically when a report is finalized* on, this happens at finalize.
+- The **Submission** panel shows state (*Queued → In flight → Accepted / Rejected / Failed / Superseded*), attempts, queued/sent/completed times, the destination status, issues and the payload that was sent.
+- **Rejected** — correct the fields and **Correct and resubmit**; a new revision and idempotency key are created and earlier responses remain in the exchange history.
+- **Submission history and recovery** lets an administrator **bind an unsent submission**, **verify an existing destination filing** by its identifier, or **record a verified absence** after NERIS support confirms nothing was created.
+
+
+
+## Incident analysis
+
+For fire and hazmat incidents NERIS takes a separate **incident analysis** (cause, origin, spread, investigation findings) filed *after* the incident itself is accepted. **Open the analysis** from the report; it has its own lifecycle and is queued automatically once the incident has a NERIS ID. Analyses waiting for that ID appear on the dashboard as *Analyses awaiting filing*.
+
+## NFIRS (historical) view
+
+**NFIRS view** on a report shows how the retired NFIRS Basic Module fields would be populated from the data you hold, and which NERIS fact carries each one. It is read-only and exists for departments that still receive NFIRS-shaped requests from insurers or states.
+
+## NERIS settings
+
+**Records → Manage → Incident report settings** (administrators):
+
+
+
+| Setting | Notes |
+|---|---|
+| **NERIS entity ID / Entity name** | Your department's NERIS identity. |
+| **Environment / API base URL override** | Production or test environment. |
+| **Grant type, Username/Password or Client ID/Secret** | Stored encrypted per department and never shown again. Leave blank to keep the stored credential. |
+| **Enable NERIS submission for this department** | Master switch. |
+| **Submit automatically when a report is finalized** | Otherwise an officer presses *Submit to NERIS*. |
+| **Allow protected incident content to be sent to NERIS** | Required under Advanced Data Protection; without it protected submissions fail closed. |
+| **Call type crosswalk** | Map each dispatch call type to the NERIS incident type it prefills. Unmapped types leave the incident type for the author to choose — the dashboard reports coverage. |
+| **Status** | Contract version, last token issued, last successful call, last error, submission queue counts. |
+
+Self-hosted operators can switch NERIS off system-wide (*NERIS submission is switched off system-wide*).
+
+## Setup examples
+
+| Department | Recommended configuration |
+|---|---|
+| **US career / combination fire** | Map every call type in the crosswalk; *Review required* preset with the shift officer as reviewer; auto-submit on finalize; review due 24 h so incomplete reports show on the dashboard next shift. |
+| **US volunteer fire** | Same crosswalk; *Quick entry* if the chief writes all reports, otherwise *Review required* with officers as reviewers; auto-submit off until the first few reports are checked. |
+| **Fire-based EMS** | Medical incident types map to the patient-care section; keep patient detail in restricted fields; ADP recommended. |
+| **Non-US** | Leave NERIS disabled; use incident reports as the department's own standardized incident record, or design a department definition instead. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/IncidentReports/{Index,ForCall,Details,Edit,Settings,Payload,ExchangeHistory,ContractSchema,NfirsLegacy,EvidenceManifest,Attachment}`, `/User/IncidentAnalysis/{Details,Edit}`, `/User/RecordSubmissions/Details?submissionId=` |
+| Definition key | `system.neris-incident` (single authoritative per call) |
+| Provider | `Resgrid.Providers.Neris` — contract pinned per department profile; submission worker delivers queued revisions with idempotency keys |
+| Permissions | `SubmitRecords` (56) for submission; standard lifecycle permissions otherwise |
+| Workflow | `RecordFinalized` / `RecordAmended` events carry the safe projection; NERIS acceptance/rejection is visible on the record and dashboard |
diff --git a/docs/web-app/records/inspections.md b/docs/web-app/records/inspections.md
new file mode 100644
index 0000000..47f7a6d
--- /dev/null
+++ b/docs/web-app/records/inspections.md
@@ -0,0 +1,55 @@
+---
+sidebar_position: 7
+title: Inspections
+---
+
+# Inspections
+
+Fire and life-safety inspections of [occupancies](occupancies): programs that define *what* is inspected and *how often*, code sets the inspection is checked against, the inspection itself with a checklist, and the violations that come out of it with correction windows, notices and re-inspections.
+
+Feature flag: `Records.Prevention.Inspections` (requires occupancies). Menu: **Records → Inspections**.
+
+
+
+## Setting up
+
+### Code sets
+
+**Inspections → Code sets** hold the fire and building codes you inspect against (e.g. *IFC 2021*, *NFPA 1*, a local ordinance). Each **section** carries the section number, title, text, a **default severity** (1–4) and **correction days** used when a violation cites it. Sections can be typed in or **imported from CSV** (`section, title, text, severity, correction_days`).
+
+
+
+### Inspection programs
+
+**Inspections → Programs** pair a **checklist** with a **frequency (months)** and the **occupancy types** it applies to. The checklist is one item per line: `key | text | required (y/n) | code section id`. Enable the program and use **Generate due inspections** to create scheduled inspections for every occupancy that is due.
+
+
+
+## Performing an inspection
+
+1. **Schedule** — from the occupancy page or by generating due inspections. The inspection gets a number, program, inspector and scheduled date.
+2. **Start inspection** — records the start time.
+3. Work through the **checklist**: mark each item *Passed*, *Failed* or *N/A* with a note. Failed items automatically create **violations** citing the code section, with severity and a due date from the section's correction days.
+4. **Complete inspection** — enter notes and the typed **signature name** of the person attesting.
+5. Handle violations: **Issue notice** (with a notice reference), record **corrective action**, **Schedule re-inspection** (linked as *re-inspection of* the original).
+6. **Close inspection** when everything is resolved, or **Cancel** (the record stays in history).
+
+Violations remain open on the occupancy until corrected; the occupancy list and analytics count **open violations** and **re-inspections required**.
+
+## Setup examples
+
+| Department | Programs |
+|---|---|
+| **Fire prevention bureau** | *Annual business inspection* (12 months, mercantile/business/assembly types), *Care facility* (6 months), *Hazmat* (12 months) with IFC code set; *Re-inspection* handled through the built-in re-inspection flow. |
+| **Volunteer fire** | *Pre-plan walk-through* (24 months, all types) with a short checklist — no code citations needed. |
+| **Facilities / security** | *Fire extinguisher & exit route* (1 month), *Emergency lighting* (3 months) on client sites. |
+| **Industrial** | *Process area safety inspection* (1 month) with internal standard sections in a code set. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/RecordInspections/{Index,Details,Programs,CodeSets}` |
+| Model | `RmsInspectionProgram`, `RmsCodeSet`, `RmsCodeSection`, `RmsInspection`, `RmsInspectionItem`, `RmsViolation` |
+| Flag / permission | `Records.Prevention.Inspections`; `RecordsPreventionAdmin` to configure; inspectors need record create |
+| Analytics | Pass rate, days scheduled → completed, open violations by severity, re-inspections (see [Analytics](analytics)) |
diff --git a/docs/web-app/records/investigations.md b/docs/web-app/records/investigations.md
new file mode 100644
index 0000000..17ae118
--- /dev/null
+++ b/docs/web-app/records/investigations.md
@@ -0,0 +1,52 @@
+---
+sidebar_position: 11
+title: Investigations
+---
+
+# Investigations
+
+Fire and arson investigations, cause-and-origin work and any other case that needs **restricted, need-to-know access**. A case is visible only to its **members**, every read is written to an **access audit**, evidence items carry an append-only **chain of custody**, and findings must be **approved by someone other than their author** before they can be recommended as an amendment to the incident report.
+
+Feature flag: `Records.Investigations`; requires the *View restricted records* permission **and** case membership. Menu: **Records → Investigations**.
+
+
+
+## Opening a case
+
+**Open case** — you become the **lead investigator**. Give the case a title, kind (fire cause & origin, arson, explosion, fatality, hazmat, other), an optional linked **occupancy** and **call**, jurisdiction and reference number. Add **members** afterwards; only members can read the case.
+
+
+
+## Working a case
+
+
+
+| Panel | What it does |
+|---|---|
+| **Case members** | Add / remove members and their role. |
+| **Linked incidents** | Link an incident report; linking **pins the incident revision** at that moment — findings never change the incident report. |
+| **Evidence** | Evidence number, kind, collected from / on, storage location, current custodian. **Transfer custody** records who gave, who received, why, when and the resulting state (including transfer to an external party such as a lab). |
+| **Case notes** | Dated notes with subject and body. |
+| **Referrals** | Referrals to law enforcement, insurers, prosecutors, with agency and status. |
+| **Findings** | Cause classification (accidental, natural, incendiary, undetermined), cause detail, origin description, incident summary, **recommends amendment**. **Record findings** sends them for approval; a reviewer or the lead (other than the author) **approves** or **returns** them. |
+| **Access audit** | Who opened the case and when. |
+| **Export packet** | A packet of the case for the prosecutor or insurer. |
+
+**Close case** makes notes read-only (a closure reason is required); **Reopen case** is available to the lead.
+
+## Setup examples
+
+| Department | Notes |
+|---|---|
+| **Fire department with investigators** | Investigators role granted *View restricted records*; every fire with loss opens a case linked to the NERIS report; findings drive the NERIS incident analysis. |
+| **Small department** | Open a case only for suspicious fires; add the county fire marshal as a member when handing over. |
+| **Security / industrial** | Internal incident investigations (theft, process-safety events) with HSE as lead. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/RecordInvestigations/{Index,Details,Open,Custody,Export}` |
+| Model | `RmsInvestigationCase`, `RmsInvestigationMember`, `RmsInvestigationEvidence`, `RmsCustodyTransfer`, `RmsInvestigationNote`, `RmsInvestigationReferral`, `RmsInvestigationFindings`, `RmsAccessAudit` |
+| Flag / permission | `Records.Investigations`; `ViewRestrictedRecords` (59) + case membership; `RecordsPreventionAdmin` is **not** sufficient |
+| Protected data | Case content is always protected-classified; under ADP it is encrypted at rest. |
diff --git a/docs/web-app/records/legal-holds-and-disclosures.md b/docs/web-app/records/legal-holds-and-disclosures.md
new file mode 100644
index 0000000..cd4cab6
--- /dev/null
+++ b/docs/web-app/records/legal-holds-and-disclosures.md
@@ -0,0 +1,62 @@
+---
+sidebar_position: 16
+title: Legal Holds & Records Requests
+---
+
+# Legal Holds & Public-Records Requests
+
+Two compliance workflows that most departments meet sooner or later: **preserving** records for litigation, an investigation or a records request, and **producing** records in response to a public-records (FOIA / state sunshine law) request with the right redactions and a statutory clock.
+
+## Preservation (legal) holds
+
+**Records → Legal holds** (requires *Manage legal holds*). A hold prevents retention purge and voiding for its scope. A hold on a record also protects its incident analysis and evidence; releasing a disclosure does **not** release the hold.
+
+
+
+**Place preservation hold**:
+
+| Field | Notes |
+|---|---|
+| **Scope** | A **specific record identifier**, or a **definition scope** with an optional **preserved period** (UTC; leave both dates blank for every date), optionally including the **NERIS incident and analysis**. |
+| **Basis for the hold** | Litigation, Investigation, Public records request, Other. |
+| **Authority or case reference / Preservation instructions** | Recorded with the hold. |
+
+Holds list who placed and released them; **Release hold** requires the authority and reason for release.
+
+## Records requests (disclosures)
+
+**Records → Manage → Records requests** (requires *Manage record disclosures*). A request carries a statutory clock, so it is tracked here rather than answered ad hoc.
+
+
+
+### Workflow
+
+1. **Log a records request** — reference, requester name / organisation / contact details, received on, **statutory due date** (blank uses the department's clock), what was asked for (**scope narrative**).
+2. **Save the scope** — the records the request resolves to (a preview lists them). The scope freezes once anything has been produced against it.
+3. **Review** the records with a **redaction profile**: *Standard* (withhold restricted content), *No personal identifiers* (also withhold participant identities) or *Full disclosure*. Attachments can be reviewed with the same profile.
+4. **Produce** — creates an immutable, checksummed production artifact (zip or PDF). A later amendment cannot change what was produced; **Verify the checksum** confirms a stored production is intact.
+5. **Release** — the release approver (department setting) releases the production to the requester and the release is recorded.
+6. **Close the request** with a reason.
+
+The dashboard counts open and **overdue** requests. Requester identity can be restricted so that only the disclosure officer sees it.
+
+### Disclosure defaults
+
+In [Records settings](settings): **statutory response clock (days)**, **default redaction profile** and **release approver** (a member, or any department administrator).
+
+## Setup examples
+
+| Department | Notes |
+|---|---|
+| **US municipal fire / EMS** | Clock per state law (e.g. 10 business days); default profile *No personal identifiers* for EMS; city attorney as release approver. |
+| **Canadian department** | Clock per provincial FOI act (30 days); *Standard* profile. |
+| **Private company** | Use the workflow for subpoenas and insurer requests; *Full disclosure* reserved for counsel. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/RecordLegalHolds/Index?recordId=`, `/User/Disclosures/{Index,Details,Review,ReviewAttachment,Download}` |
+| Model | `RmsLegalHold`, `RmsDisclosure`, `RmsDisclosureProduction` |
+| Permissions | `ManageRecordLegalHold` (66), `ManageRecordDisclosures` (65), `ShareRecordsExternally` (58) for release |
+| Retention | Retention purge skips any record under an active hold. |
diff --git a/docs/web-app/records/occupancies.md b/docs/web-app/records/occupancies.md
new file mode 100644
index 0000000..66aeacc
--- /dev/null
+++ b/docs/web-app/records/occupancies.md
@@ -0,0 +1,72 @@
+---
+sidebar_position: 6
+title: Occupancies & Pre-plans
+---
+
+# Occupancies & Pre-plans
+
+An **occupancy** is a building, site or property your department may respond to: its identity and location, structure, fire-protection systems and utilities, hazards, tactical notes, emergency contacts, and the history of inspections, permits and incidents at that address. It is the "property master" that inspections, permits, hydrants, investigations and CRR activities hang off — and, once you switch ownership, the home of your **pre-plans**.
+
+Feature flag: `Records.Prevention.Occupancy`. Menu: **Records → Occupancies**.
+
+
+
+## The occupancy list
+
+Search by number, name or address; filter by status, **review overdue** and **hazmat on site**. Each row links to the details page. **New occupancy** opens the editor.
+
+## Creating and editing an occupancy
+
+
+
+| Section | Fields |
+|---|---|
+| **Identity and location** | Name, occupancy type, address (street, municipality, state, postal code, country), coordinates, parcel ID, linked point of interest, occupancy hours, emergency contact and number, review due date. |
+| **Structure** | Construction type, storeys, square feet, year built, roof type, occupant load, occupants needing assistance, required fire flow. |
+| **Fire protection and utilities** | Sprinklers, standpipe, FDC location, fire alarm (panel location, alarm company), Knox box, gate code, water / gas / electric shutoffs, utility notes, nearest hydrant, water supply notes. |
+| **Access** | Access notes. |
+| **Hazards and tactics** | Hazmat on site, general hazard notes, tactical summary. Individual **hazards** (title, type, severity, *Alert crews*) are added from the details page. |
+
+Hazards flagged *Alert crews* are pushed to the apps and the dispatch **alert notes** for calls at that address.
+
+## The occupancy details page
+
+
+
+- **Hazards** — add / remove hazards.
+- **Inspections** — schedule an inspection from a program; list of past inspections with result and open violations.
+- **Permits** — permits issued against the occupancy; **New permit**.
+- **Linked contacts** — the owner, manager or company from [Contacts](../contacts).
+- **Mark reviewed** — records the pre-plan review date (the list flags occupancies whose review date has passed).
+- **Merge into** — merges a duplicate into a target occupancy; hazards, links and history move and this record becomes a pointer.
+- **Delete** — inspections, permits and hazards keep their history but lose the parent.
+
+The occupancy also feeds the **Contacts pre-plan summary** and the dispatch projection the apps use.
+
+## Pre-plan crosswalk and ownership
+
+Before Records existed, pre-plan data lived on [Contacts](../contacts) (addresses, hazards, attachments) and on map points of interest. **Records → Occupancies → Pre-plan crosswalk** helps you move it:
+
+1. **Run inventory** scans Contacts pre-plans, contacts with addresses and POIs, groups them by address and proximity, and proposes occupancy **candidates** with a match confidence.
+2. Decide every candidate: **Link** to the suggested occupancy, **Create a new occupancy from this source**, or **Reject**.
+3. When every candidate is decided and no pre-plan is unreconciled, **Switch write ownership to Records**. From then on pre-plans are edited only as occupancies; Contacts pages and the apps read projections. Rollback is a database restore, not a toggle.
+
+
+
+## Setup examples
+
+| Department | Approach |
+|---|---|
+| **Fire** | Import your target hazards first (schools, care homes, industrial sites, high-rises), then run the crosswalk on existing Contacts pre-plans. Set a review due date 12 months out; the list will flag overdue reviews. |
+| **Industrial site / campus** | One occupancy per building; hazards for each process area with *Alert crews*; link to indoor maps for floor plans. |
+| **Security / facilities** | Client sites as occupancies with gate codes, alarm company and access notes; inspections for fire-extinguisher or exit-route checks. |
+| **Emergency management** | Shelters, EOC alternates, critical infrastructure with occupant load and utility shutoffs. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/RecordOccupancies/{Index,Details,Edit,Crosswalk}` |
+| Model | `RmsOccupancy`, `RmsOccupancyHazard`, `RmsOccupancyContactLink`, `OccupancyDispatchProjectionV1` |
+| Flag / permission | `Records.Prevention.Occupancy`; write requires `RecordsPreventionAdmin` (69), read requires record view |
+| Ownership switch | `RmsPreplanOwnership` — append-only; Contacts pre-plan editing is denied once switched |
diff --git a/docs/web-app/records/overview.md b/docs/web-app/records/overview.md
new file mode 100644
index 0000000..f747c37
--- /dev/null
+++ b/docs/web-app/records/overview.md
@@ -0,0 +1,128 @@
+---
+sidebar_position: 1
+title: Records Overview
+---
+
+# Records (RMS) — Overview
+
+**Records** is Resgrid's records management system. It replaces the older *Logs* module and grows well beyond it: typed operational records (run, training, work, meeting …), **NERIS** incident reporting for US fire departments, department-designed forms, fire-prevention records (occupancies, inspections, hydrants, permits, community risk reduction), restricted investigation cases, quality review, analytics, legal holds and public-records disclosure — all with immutable revision history and audit trails.
+
+
+
+## Who it is for
+
+| If you are… | Records gives you… |
+|---|---|
+| A **fire department** (US) | NERIS incident reports started straight from the dispatched call, run/training/work records, hydrants, occupancies and inspections, CRR activity, investigations, accreditation analytics. |
+| A **fire department outside the US** | Everything above except NERIS submission (reports can still be authored and kept locally), plus templates in French, and jurisdiction profiles for Canada. |
+| **EMS** | Run records, training and meeting records, controlled-substance evidence capture, unit activity, quality review of finalized records. |
+| **SAR / CERT / emergency management** | Mission summaries, segment debriefs, clue reports, damage assessments, EOC shift logs, ESF status reports, ICS forms (202–225), mutual-aid deployments. |
+| **Security, delivery, transit, field service, industrial** | Patrol logs, incident reports, delivery-run and route end-of-day summaries, job completion, shift handover, near-miss reports — from the template library or your own designer-built definitions. |
+
+## Where to find it
+
+When Records is enabled the left menu shows **Records** in place of *Logs* (never both). It expands into:
+
+| Menu item | Page |
+|---|---|
+| **Records dashboard** | Queues that need attention: incomplete incident reports, awaiting review, rejected by NERIS, overdue obligations, open records requests, crosswalk coverage. |
+| **All records** | The searchable, filterable work queue of every record you may see, plus **New Record**. |
+| **Legal holds** | Preservation holds (visible with the *Manage legal holds* permission). |
+| **Occupancies / Inspections / Hydrants / Permits / Community risk reduction** | Prevention module pages (each behind its own feature flag). |
+| **Investigations** | Restricted case files (members only). |
+| **Analytics** | Response performance, workload, executive, accreditation, readiness and community-risk dashboards. |
+
+From **All records** the toolbar offers **Reports** (export this list, saved reports, analytics, accountability, quality review) and **Manage** (records requests, deployments, definitions, report exports, release health, field rollout, settings).
+
+## Turning it on: activation
+
+Records ships **off**. Two steps switch a department over:
+
+1. **Feature flag** — `Records.System` must be enabled for the department (hosted customers: ask Resgrid support; self-hosted: `Resgrid.Console --FeatureFlags --Key=Records.System --DepartmentId=N --On`). Prevention, investigations, quality review and analytics each have their own flag (`Records.Prevention.*`, `Records.Investigations`, `Records.QualityReview`, `Records.Analytics`).
+2. **Activate** — a department administrator opens **Records → Activate Records**, reviews how existing *Logs* permissions map to Records permissions, optionally locks *See other groups' Records* to the viewer's own group, enters a reason and acknowledges that activation cannot be reversed once a record is finalized.
+
+
+
+After activation:
+
+- Existing Logs and Unit Logs stay readable in the **Logs** module (list, search, detail, attachments, print, export) but can no longer be created, edited or deleted anywhere — web, apps, API or workflows.
+- New records are created only in Records. Nothing is dual-written.
+- Records does not import legacy logs; historical reporting spans both modules.
+
+:::caution Rollback
+Rollback is an operator runbook, not a toggle. It is only clean while *no* record has been finalized. Once a record is finalized, attested, amended or submitted the department stays on Records; problems are fixed forward (retire a definition, amend a record) or by restoring the whole department from backup.
+:::
+
+## Key concepts
+
+| Concept | Meaning |
+|---|---|
+| **Definition** | The form a record follows: sections, fields, rules, numbering, lifecycle preset, reviewers/approvers, retention, classification. **Locked system definitions** (Run, Training, Work, Meeting, Coroner, Callback, Unit Activity, NERIS incident report) cannot be redesigned but can be extended with [User Defined Fields](../user-defined-fields). **Department definitions** are yours to design from templates or from scratch. |
+| **Record** | One filled-in instance of a definition. Has a record number, state, owner, author, participants, units, call link, attachments and revision history. |
+| **Lifecycle preset** | *Quick entry* (Draft → Finalized), *Review required* (Draft → Ready for review → Finalized, with a *Returned* loop), *Approval / acknowledgement* (adds an *Approved* step by someone other than the author). |
+| **Revision** | An immutable, checksummed snapshot written at **finalize**, **amend** and **void**. Prints and exports always come from a pinned revision. |
+| **Amendment** | The only way to change a finalized record. The prior revision is kept verbatim and the diff is viewable. |
+| **Void** | Marks a finalized record as invalid (with reason). History is retained. |
+| **Restricted section / field** | Content that only members with *View restricted records* (or case membership) can see. Coroner and investigation classes are restricted by default. |
+| **Group scope** | Optionally limits visibility to the viewer's own station/group. Authors, owners, reviewers, named participants, responding unit crews and department administrators always see a record. |
+
+## Record states
+
+```
+Draft ─► Ready for review ─► Approved ─► Finalized ─► Amended
+ ▲ │ │
+ └── Returned ┘ └► Voided
+Draft ─► Cancelled
+NERIS reports additionally: Submitted → Accepted / Rejected → Corrected
+```
+
+- **Draft** is the only state that autosaves and merges concurrent edits.
+- **Returned** re-opens as Draft on the next save.
+- **Finalize** writes a revision and (if the definition requires it) an author attestation.
+- **Cancelled** abandons an unfinished record and releases its number.
+
+## Pages in this section
+
+- [Dashboard & work queue](dashboard-and-queue) — finding, filtering, bulk actions, exports.
+- [Authoring records](authoring) — creating, editing, finalizing, amending, attachments, evidence.
+- [NERIS incident reports](incident-reports) — the US national incident reporting standard.
+- [Definitions & templates](definitions) — designing your own forms.
+- [Prevention: occupancies & pre-plans](occupancies) · [Inspections](inspections) · [Hydrants](hydrants) · [Permits](permits) · [Community risk reduction](community-risk-reduction)
+- [Investigations](investigations) — restricted case files with chain of custody.
+- [Analytics](analytics) · [Quality review](quality-review) · [Accountability](accountability)
+- [Saved reports & exports](reports-and-exports) — CSV/JSON, saved reports, report exports for agencies.
+- [Deployments & connectors](deployments) — mutual-aid orders your department fills.
+- [Legal holds & records requests](legal-holds-and-disclosures)
+- [Records settings](settings) — numbering, retention, group visibility, print layout, NERIS, disclosure defaults.
+
+## Permissions
+
+Records has its own permission set under **Department → Security & Permissions** (each can be *Everyone*, *Department admins*, *Department + group admins*, or *Admins + selected roles*):
+
+| Permission | Purpose |
+|---|---|
+| Create records · Delete records | Author drafts; delete unfinished records. |
+| Review records · Approve records · Finalize records · Amend records | Lifecycle transitions. Approvers may not approve their own record. |
+| Submit records | Send NERIS reports. |
+| Export records · Share records externally | CSV/JSON/PDF exports; packets emailed outside the department. |
+| View restricted records | Restricted sections, Coroner class, investigation cases (with membership). |
+| View legacy records | The read-only Logs module after activation. |
+| See other groups' records | Cross-group visibility when group scoping is on. |
+| Manage record definitions · Publish record definitions | The designer. |
+| Manage record reports | Saved reports and report exports. |
+| Manage record disclosures · Manage legal holds | Public-records workflow and preservation holds. |
+| Reassign record drafts | Move an unfinished record to another owner. |
+| Prevention administration | Occupancies, programs, code sets, hydrants, permit types, CRR. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Controllers | `RecordsController`, `RecordDefinitionsController`, `IncidentReportsController`, `IncidentAnalysisController`, `RecordDocumentsController`, `RecordEvidenceController`, `RecordLegalHoldsController`, `DisclosuresController`, `RecordOccupanciesController`, `RecordInspectionsController`, `RecordHydrantsController`, `RecordPermitsController`, `RecordCrrController`, `RecordInvestigationsController`, `RecordsAnalyticsController`, `RecordsQualityController`, `RecordSavedReportsController`, `RecordsExportTemplatesController`, `RecordDeploymentsController`, `RecordDeploymentConnectorsController`, `RecordsHealthController`, `RecordsInventoryController`, `RecordSubmissionsController` |
+| Feature flags | `Records.System`, `Records.Field.{Responder,Unit,IncidentCommand,Dispatch}`, `Records.Prevention.{Occupancy,Inspections,Hydrants,Permits,Crr}`, `Records.Investigations`, `Records.QualityReview`, `Records.Analytics` |
+| Cutover fact | `RmsDepartmentCutover` (activation is append-only; not a department setting) |
+| Permissions | `PermissionTypes` 50–67 and 69 (`CreateRecord` … `ReassignRecordDrafts`, `RecordsPreventionAdmin`) |
+| Definition keys | `system.run`, `system.training`, `system.work`, `system.meeting`, `system.coroner`, `system.callback`, `system.unit-activity`, `system.neris-incident`; department keys may not start with `system.` |
+| Workflow events | `RecordCreated`, `RecordFinalized`, `RecordAmended`, `RecordVoided` (+ `LogAdded` compatibility projection during the transition window) |
+| API | `api/v4/Records/*`, `api/v4/RecordDefinitions/*`, `api/v4/IncidentReports/*`, `api/v4/RecordExportTemplates/*` — used by the Field Records surfaces in the Responder, Unit, Incident Command and Dispatch apps |
+| Search | Records are indexed by the unified search worker; narrative search is withdrawn when the department is enrolled in [Advanced Data Protection](../data-protection). |
diff --git a/docs/web-app/records/permits.md b/docs/web-app/records/permits.md
new file mode 100644
index 0000000..8c7e912
--- /dev/null
+++ b/docs/web-app/records/permits.md
@@ -0,0 +1,51 @@
+---
+sidebar_position: 9
+title: Permits & Plan Review
+---
+
+# Permits & Plan Review
+
+Operational permits (open burning, fireworks, hot work, tents, hazmat storage, special events …) and construction plan review, tracked per [occupancy](occupancies) with applicant details, state transitions, conditions, fees and expiry.
+
+Feature flag: `Records.Prevention.Permits` (requires occupancies). Menu: **Records → Permits**.
+
+
+
+## Permit types
+
+**Permits → Permit types** defines what you issue: name, **code**, **validity (days)** used to compute the expiry from the issue date, whether it **requires plan review**, a **conditions template** pre-filled on new permits and a **fee** (reference only — invoicing is recorded, not collected, here).
+
+
+
+## Issuing a permit
+
+**New permit** (from the list or from an occupancy):
+
+| Field | Notes |
+|---|---|
+| **Permit type / Occupancy** | What and where. |
+| **Applicant, e-mail, phone, contact** | Who applied; can link a [Contact](../contacts). |
+| **Conditions** | Starts from the type's template. |
+| **Expires on** | Leave blank to use the type's validity from the issue date. |
+
+**Submit application** moves it to *Applied*. From the details page an officer **changes state** — *Under review → Issued* (or *Denied* with a decision reason), later *Expired* or *Revoked* — and can **record a fee** (amount, paid on, invoice reference) and, for types that require it, **record plan review** cycles (cycle number, outcome, reviewer notes, reviewed on).
+
+
+
+The list filters by state, type and **expiring soon**; analytics reports issued / denied / expired / revoked counts and average days from applied to issued.
+
+## Setup examples
+
+| Department | Permit types |
+|---|---|
+| **Fire marshal** | Open burn (30 days), Fireworks display (1 day, requires plan review), Tent / membrane structure (30 days), Hot work (7 days), Hazmat storage (365 days). |
+| **Small volunteer department** | Burn permit only; Quick issue; expiry 3 days. |
+| **Industrial / facilities** | Hot-work permit (1 day) and Confined-space entry (1 day) used as an internal permit-to-work log. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/RecordPermits/{Index,Details,Edit,Types}` |
+| Model | `RmsPermitType`, `RmsPermit`, `RmsPermitPlanReview`, `RmsPermitFee` |
+| Flag / permission | `Records.Prevention.Permits`; `RecordsPreventionAdmin` for types and state changes |
diff --git a/docs/web-app/records/quality-review.md b/docs/web-app/records/quality-review.md
new file mode 100644
index 0000000..a091385
--- /dev/null
+++ b/docs/web-app/records/quality-review.md
@@ -0,0 +1,42 @@
+---
+sidebar_position: 13
+title: Quality Review
+---
+
+# Quality Review
+
+An optional post-finalization **QA/QI** process: rubrics define scoring criteria, a deterministic sample of finalized records is drawn per rubric and period, reviewers score each record 0–4 per criterion, and trends are charted by author, unit, definition and criterion. Reviews never change the record — a reviewer can only **recommend an amendment**, which flows through the normal amendment path.
+
+Feature flag: `Records.QualityReview`. Menu: **Records → Reports → Quality review**.
+
+
+
+## Rubrics
+
+**Rubric → New rubric** (department administrators): name, the **definition** it applies to, **sample size** per sampling run, and the **criteria** — one per line as `key | text | weight`. The weighted total becomes a percentage.
+
+
+
+## Sampling and scoring
+
+- **Sample** draws the configured number of finalized records for the rubric and period. Selection is deterministic — re-running for the same period gives the same records.
+- **Reviews to score** lists sampled records waiting for a reviewer. Open one, score each criterion 0–4, add a reviewer note and optionally tick **Recommend an amendment**.
+- **Trends** shows average score and review counts by author, by unit, by definition and by criterion since a chosen date, and how many reviews recommended amendments.
+
+
+
+## Setup examples
+
+| Department | Rubric ideas |
+|---|---|
+| **EMS** | *Run report QA*: chief complaint documented, times complete, narrative matches interventions, protocol cited, signatures present. Sample 10 per month. |
+| **Fire** | *NERIS incident QA*: incident type correct, actions/tactics complete, unit times plausible, narrative quality. |
+| **Security** | *Incident report QA*: classification, involved persons, evidence attached, supervisor notified. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/RecordsQuality/{Index,Rubric,Review,Trends,Download}` |
+| Model | `RmsQualityRubric`, `RmsQualitySample`, `RmsQualityReview` |
+| Flag / permission | `Records.QualityReview`; rubric management requires department admin; scoring requires `ReviewRecords` |
diff --git a/docs/web-app/records/reports-and-exports.md b/docs/web-app/records/reports-and-exports.md
new file mode 100644
index 0000000..cbfff89
--- /dev/null
+++ b/docs/web-app/records/reports-and-exports.md
@@ -0,0 +1,75 @@
+---
+sidebar_position: 14
+title: Saved Reports & Exports
+---
+
+# Saved Reports & Report Exports
+
+Three ways to get data out of Records, for three audiences:
+
+| Need | Use |
+|---|---|
+| A quick list of what is on screen | **Export this list** (CSV / JSON) from the work queue. |
+| A repeatable tabular report over one definition's records, grouped and aggregated | **Saved reports**. |
+| A file an outside agency receives on a schedule or when a record is finalized | **Report exports** (export templates) attached to a Workflow or a schedule. |
+
+Prints, PDFs and compiled packets are covered in [Authoring](authoring) and [Dashboard & queue](dashboard-and-queue).
+
+## Saved reports
+
+**Records → Reports → Saved reports** (requires *Manage record reports*).
+
+
+
+| Setting | Notes |
+|---|---|
+| **Report name / Definition** | One definition per report. Pick the definition to choose columns. |
+| **Columns** | Record columns (number, state, occurred, author, group, unit …) plus the definition's fields. |
+| **Sort by / Descending / Group by** | Grouping produces sub-totals. |
+| **Aggregates (JSON)** | Count, Sum, Average, Min, Max on aggregatable fields. |
+| **Filters (JSON)** | Field filters (equals, contains, range). |
+| **Version mappings (JSON)** | How fields on older definition versions map to the current columns. Unmapped versions are included with blank cells. |
+| **Max rows / Include drafts / Include restricted fields** | Restricted fields still require the viewer to hold *View restricted records*. |
+
+**Validate**, **Run** (on screen) or **Run CSV**. Results respect record visibility.
+
+## Report exports (export templates)
+
+**Records → Manage → Report exports** designs the file an agency without an API receives — a state fire marshal, an insurer, a city finance system.
+
+
+
+| Setting | Notes |
+|---|---|
+| **Export name / Key** | The key (lower-case, digits, hyphens) is referenced by Workflow steps and the agency's import — it never changes once in use. |
+| **Format** | CSV (with delimiter and header options), JSON, or fixed formats. |
+| **Scope** | *The triggering record* (used from a Workflow on a Records trigger) or *All records finalized in a window*. |
+| **Record definitions** | Leave all unchecked to export every definition. |
+| **Columns** | From a fixed, reviewed catalog in three tiers: **identity, dates, codes and counts** (always allowed), **narrative and personal detail (Tier 2)** and **restricted sections (Tier 1)** — the last two need their switch *and* an **egress acknowledgement**. |
+| **File name** | Tokens `{template}`, `{date}`, `{record}`. |
+| **Schedule** | None (Workflow only), daily, weekly, monthly, with hour, weekday / day-of-month and a **window (days)** (0 = the schedule period). |
+
+**Run now** renders the export for you to check before an agency sees it (every record it contains is audited as an export). **Runs** lists each generation with record count, size, whether protected fields were withheld, and a download.
+
+Under Advanced Data Protection protected columns are written as `REDACTED` unless the egress acknowledgement is recorded.
+
+### Attaching an export to a Workflow
+
+In the [Workflow](../workflows) designer, an **email** or **file upload** step on a Records trigger (*Record finalized*, *Record amended*) can attach any export listed here. A scheduled export raises its own trigger when it runs, so you can email or upload the file wherever it needs to go.
+
+## Setup examples
+
+| Need | Configuration |
+|---|---|
+| Monthly run summary to the county | Saved report on *Run* grouped by call type with Count; run CSV on the 1st. |
+| State fire marshal wants every finalized incident nightly | Report export, scope *window*, definitions *NERIS incident*, safe-tier columns, daily at 02:00, Workflow SFTP upload step. |
+| Insurer requests one incident | Compile a packet from the queue (PDF), or a Workflow email step with a *triggering record* export. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/RecordSavedReports/{Index,Edit,Run,RunCsv}`, `/User/RecordsExportTemplates/{Index,Edit,Runs,Download}`, `/User/Records/ExportList` |
+| Model | `RmsSavedReport`, `RmsExportTemplate`, `RmsExportRun` |
+| Permissions | `ManageRecordReports` (64), `ExportRecords` (57), `ShareRecordsExternally` (58) for emailed packets |
+| Workflow | Export templates are selectable on email / file actions; scheduled exports emit `RecordExportGenerated` |
diff --git a/docs/web-app/records/settings.md b/docs/web-app/records/settings.md
new file mode 100644
index 0000000..b85cd47
--- /dev/null
+++ b/docs/web-app/records/settings.md
@@ -0,0 +1,83 @@
+---
+sidebar_position: 17
+title: Records Settings
+---
+
+# Records Settings
+
+**Records → Manage → Settings** (department administrators). Changes apply prospectively and are audited.
+
+
+
+## Lifecycle and review
+
+| Setting | Meaning |
+|---|---|
+| **Default lifecycle preset for department definitions** | Quick entry, Review required or Approval / acknowledgement — the default new definitions start with. Locked types keep their own preset unless changed on the definition. |
+| **Review due (hours)** | How long a reviewer has before the record shows as overdue on the dashboard and accountability report. |
+
+## Numbering
+
+| Setting | Meaning |
+|---|---|
+| **Include the year in record numbers** | `RUN-2026-000123` vs `RUN-000123`. |
+| **Sequence digits** | Zero-padding width. |
+| **Separate sequence per station/group** | Each station numbers its own records. |
+
+Per-definition prefixes and per-incident sequences are set on the [definition](definitions).
+
+## Retention
+
+Shipped defaults: **7 years** for standard records; **permanent** for Coroner and other restricted classes. Retention is your department's responsibility under your jurisdiction's rules.
+
+| Setting | Meaning |
+|---|---|
+| **Department default (years)** | Blank = system default. |
+| **Per-definition overrides** | `0` = permanent. Setting a period on a restricted class asks for confirmation because it enables automatic purge. |
+
+Records under a [legal hold](legal-holds-and-disclosures) are never purged.
+
+## Cross-group visibility
+
+| Setting | Meaning |
+|---|---|
+| **Department-wide (default)** | Every member with record view sees every record. |
+| **Group-scoped** | Members see records anchored to their own station/group. Also requires the *See other groups' Records* permission to be locked to group. Authors, owners, reviewers, named participants, responding unit crews and department administrators always see a record. |
+
+Turning on group scoping shows an **impact preview** — records that would be hidden from members of no group, records with no group anchor (which stay department-wide), members in no group — and requires confirmation.
+
+## Search
+
+Shows whether the search index is **online**, the number of indexed records and whether **narrative text** is included. The worker rebuilds the index when the protection policy or catalog version changes. Narrative search is withdrawn when the department is enrolled in [Advanced Data Protection](../data-protection).
+
+## Print layout
+
+How the letterhead renders on record prints. Identity and logo come from the [Department Profile](../department-settings#department-profile).
+
+| Setting | Meaning |
+|---|---|
+| **Show logo / Use the short name / Show address / phone / website** | Letterhead content. |
+| **Letterhead line 1 / 2, Footer text, Watermark label** | Free text (e.g. `CONFIDENTIAL`). |
+| **Page size, Date and time format** | Optional .NET format string such as `yyyy-MM-dd HH:mm`. |
+
+Every save is a new layout version stamped in the provenance footer of every print. Per-definition layouts can override this.
+
+## NERIS settings
+
+Covered in [NERIS incident reports](incident-reports#neris-settings): entity ID, environment, credentials, enable / auto-submit, protected egress acknowledgement and the call-type crosswalk.
+
+## Public-records disclosure
+
+| Setting | Meaning |
+|---|---|
+| **Statutory response clock (days)** | 1–365; the default due date for a new request. |
+| **Default redaction profile** | Standard, No personal identifiers, Full disclosure. |
+| **Release approver** | A member, or any department administrator. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Route | `/User/Records/Settings` |
+| Model | `RecordsDepartmentSettings` (department setting 74 holds retention overrides; settings 70–77 belong to the Records settings screen) |
+| Related | `/User/IncidentReports/Settings` (NERIS), `/User/Department/Profile` (letterhead identity) |
diff --git a/docs/web-app/reports.md b/docs/web-app/reports.md
index 6f402e5..32d4f43 100644
--- a/docs/web-app/reports.md
+++ b/docs/web-app/reports.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 14
+sidebar_position: 22
title: Reports
---
# Reports
-The Reports module is the most comprehensive analytics component in Resgrid, providing detailed insights across all operational areas. It is managed by the `ReportsController` and injects 18 services — the most of any controller.
+**Reports** are the printable, exportable views of what happened: personnel and staffing, certifications, calls, shifts, department activity, action logs, event attendance, checklist compliance and more. Most take a date range or filter; all can be printed, exported and — from **Profile → Report delivery** — scheduled to be emailed on a recurring basis.
+
+**Left menu → Reports.** The Records module adds its own [saved reports, analytics and exports](records/reports-and-exports); Inventory, Work Orders and Checklists have report pages of their own.
+
+
## Report Dashboard
@@ -139,6 +143,8 @@ Real-time snapshot of active calls and assigned resources:
Several reports have parameter selection pages that allow filtering:
+
+
| Report | Parameters |
|--------|-----------|
| Personnel Hours | Date range, specific user (optional) |
@@ -149,8 +155,22 @@ Several reports have parameter selection pages that allow filtering:
All parameter pages respect the **visibility matrix** — only showing personnel/groups the user has permission to view.
-## Internal Report Generation
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Volunteer fire** | Schedule the *Personnel hours* and *Call summary* reports monthly to the chief and treasurer (LOSAP points, run reimbursements); *Certifications* quarterly to the training officer. |
+| **Career fire** | *Unit state history* and *Personnel staffing history* for payroll reconciliation; *Upcoming shift readiness* each morning. |
+| **EMS** | *Call summary* by type for the medical director; *Event attendance* for CE credit. |
+| **SAR** | *Personnel hours* per mission for volunteer-hour grants; *Department activity* YTD for the board. |
+| **Emergency management** | *Action logs* during activations for the after-action report; *Event attendance* for exercises. |
+| **Security / business** | *Active calls and resources* live view for the operations centre; *Flagged call notes* for supervisor review. |
+## Technical reference
+
+`ReportsController` (+ `ChecklistReportsController`); routes `/User/Reports/{Index,PersonnelReport,StaffingReport,CertificationsReport,UpcomingShiftReadinessReport,DepartmentActivityReport,PersonnelHoursReportParams,PersonnelStaffingHistoryReportParams,UnitStateHistoryReportParams,ActionLogsParams,CallSummaryReportParams,ActiveCallsResourcesReport,FlaggedCallNotesReportParams,EventAttendanceReportParams,ChecklistComplianceReport,LogReport}`; scheduled delivery via `ProfileController.Reporting` and the worker; module switch `ReportsDisabled`.
+
+### Internal Report Generation
The `InternalRunReport` endpoint is an **anonymous access** endpoint intended for system-internal use (e.g., scheduled report delivery). It supports generating:
- Staffing Report
- Personnel Report
@@ -161,8 +181,7 @@ The `InternalRunReport` endpoint is an **anonymous access** endpoint intended fo
`InternalRunReport` uses `[AllowAnonymous]` and should be network-restricted in production to prevent unauthorized access.
:::
-## Interactions with Other Modules
-
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Calls** | Call data for summary and activity reports |
diff --git a/docs/web-app/resource-orders.md b/docs/web-app/resource-orders.md
index 00cd051..969df44 100644
--- a/docs/web-app/resource-orders.md
+++ b/docs/web-app/resource-orders.md
@@ -7,6 +7,8 @@ title: Resource Orders
Resource Orders enable cross-department resource requesting and fulfillment. The module is managed by the `OrdersController`.
+
+
## Overview
The resource ordering system allows departments to:
@@ -96,15 +98,23 @@ If the ordering department has auto-fill enabled:
### Manual Acceptance
The `AcceptFill` action manually accepts a submitted fill.
-## Data Endpoints
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Mutual aid** | Order an engine and a tender from linked departments during a large fire; the filling department accepts and assigns units. |
+| **Emergency management** | Resource requests from municipalities to the county EOC; track fills and returns. |
+| **SAR** | Request K9 or drone teams from partner teams. |
+## Technical reference
+
+### Data Endpoints
| Endpoint | Purpose |
|----------|---------|
| `GetYourOrders` | Department's open orders with status |
| `GetAvailableOrders` | Available orders from other departments |
-## Interactions with Other Modules
-
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Department Links** | Linked departments can have order visibility |
diff --git a/docs/web-app/routes.md b/docs/web-app/routes.md
index e884060..8e89cee 100644
--- a/docs/web-app/routes.md
+++ b/docs/web-app/routes.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 41
+sidebar_position: 16
title: Routes
---
@@ -7,6 +7,8 @@ title: Routes
The Routes module provides route planning, execution tracking, and deviation monitoring for units (vehicles/apparatus). It allows departments to define multi-stop routes, schedule them on a recurring basis, track real-time execution by units, and detect deviations from planned paths. The system integrates with Mapbox for route geometry and turn-by-turn navigation.
+
+
**Navigation:** Department Menu → Routes
## Overview
@@ -226,3 +228,13 @@ Access to Routes features is controlled by four permission levels:
| Route Delete | Delete route plans |
All data is scoped to the authenticated user's department — users can only see and manage their own department's routes.
+
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Fire** | Hydrant inspection routes per district; pre-plan walk-through routes. |
+| **EMS / transport** | Inter-facility transfer runs with linked calls per stop. |
+| **Delivery** | Daily delivery routes with stops, dwell times and customer contacts; drivers run them in the Unit app. |
+| **Transit** | Bus routes with timed stops; end-of-day summary as a Record. |
+| **Security** | Patrol routes with checkpoint geofences. |
diff --git a/docs/web-app/run-cards.md b/docs/web-app/run-cards.md
new file mode 100644
index 0000000..29e5261
--- /dev/null
+++ b/docs/web-app/run-cards.md
@@ -0,0 +1,72 @@
+---
+sidebar_position: 5
+title: Run Cards & Automatic Dispatch
+---
+
+# Run Cards & Automatic Dispatch
+
+A **run card** is a pre-planned response package: *"for a high-priority structure fire in District 1 send two engines, a truck, a rescue and a chief; on the second alarm add a tender and a brush unit."* Resgrid matches every new call against your run cards by **priority and call type**, works out which specific units and people should go — by **station response area** or by **closest available unit** — and either dispatches them automatically or pre-populates the New Call page for the dispatcher to confirm. Optional **move-up / backfill** recommendations keep station coverage intact.
+
+Feature flag: `Dispatch.RunCards`. Menu: **Department dropdown → Dispatch Settings → Run Cards**, or `/User/RunCards`.
+
+
+
+## Department-wide dispatch settings
+
+**Department → Dispatch Settings → Run Cards & Automatic Dispatch** sets the defaults every card inherits:
+
+| Setting | Options / meaning |
+|---|---|
+| **Automatic resource selection mode** | *Manual only* (cards define requirements but nothing is selected automatically), *Station based* (units from the station whose response area contains the call, cascading to the next nearest station on shortfall), *Closest unit* (nearest available resources by GPS / station location). |
+| **Automatically dispatch recommended resources** | On: matched cards dispatch immediately when the call is created (including calls from email/SMS import and the API). Off: recommendations pre-populate the New Call page for dispatcher review. |
+| **Minimum unit staffing to dispatch** | Units staffed below this level (Partially staffed, Degraded …) are not selected even if their status matches. Units without defined roles always pass. |
+| **Enable move-up / backfill recommendations** | After selection, check station coverage minimums and recommend relocating resources to depleted stations. |
+| **Closest unit response tuning** | Radius and scoring for closest-unit mode. |
+| **Station coverage minimums** | Per station: minimum number of each unit type or personnel role that should remain available, a radius for closest-unit mode, enabled flag. |
+
+Station response areas come from the **geofences** you draw on [Groups & Stations](groups-stations).
+
+## Building a run card
+
+**New Run Card** opens an editor with five tabs.
+
+
+
+| Tab | What to set |
+|---|---|
+| **General** | Name, description, **Disabled**, per-card overrides of the department defaults (selection mode, auto-dispatch, minimum staffing) and a **home station** used when a call has no location. |
+| **Triggers** | One or more triggers by **call priority**, **call type**, or **priority and type**. A card matches a call when *any* trigger matches; the most specific match wins (priority + type beats type, which beats priority). |
+| **Alarm levels** | Level 1, 2, 3 … each with **unit type requirements** (e.g. Engine × 2, Ladder × 1) and **personnel role requirements** (e.g. Chief × 1, Paramedic × 2). Levels are **additive**: escalating to level 2 dispatches level 2's resources on top of what is already assigned. Name levels (*Working fire*) if you like. |
+| **Dispatchable statuses** | Which unit statuses, personnel statuses and staffing levels count as *available* for this card. Leave empty to use the standard availability rules. |
+| **Test / Simulate** | Pick a priority, type, location and alarm level and see what would be dispatched right now — nothing is actually dispatched. |
+
+## How it plays out on a call
+
+1. A call is created (web, app, email/SMS import, API).
+2. The best-matching run card is found. Its alarm-level-1 requirements are filled from available resources using the selection mode.
+3. If **auto-dispatch** is on, those resources are dispatched immediately; otherwise the New Call page shows the recommendation for the dispatcher to accept or edit.
+4. Escalating the call's **alarm level** (from the call page or the apps) fills the next level's requirements.
+5. If **move-up** is on and a station drops below its coverage minimum, a recommendation to relocate a unit appears.
+6. The decision is recorded and can be captured as **evidence** on a [Record](records/authoring#evidence).
+
+## Setup examples
+
+| Department | Run cards |
+|---|---|
+| **Volunteer fire, 2 stations** | *Structure fire* (priority High + type Fire): L1 Engine×2, Tender×1, Chief role×1; L2 adds Engine×1 from the neighbouring station. *Medical*: Rescue×1, EMT role×2. Station-based mode, auto-dispatch off (officer reviews). |
+| **Career fire, 5 stations** | Cards per type with closest-unit mode, auto-dispatch on, coverage minimums (1 engine per station), move-ups enabled. |
+| **EMS** | *ALS emergency*: Ambulance×1 + Paramedic role×1; *BLS*: Ambulance×1. Minimum staffing *Fully staffed*. |
+| **SAR** | *Missing person*: Team leader role×1, Searcher role×6, K9 role×1 — manual selection (people, not apparatus). |
+| **Security** | *Alarm response*: Patrol unit×1 closest-unit, auto-dispatch on; *Medical on site*: adds First-aid role×1. |
+| **Industrial ERT** | *Hazmat release*: Hazmat team×1 + Safety officer role×1 + Fire brigade×1; coverage minimum keeps one crew in the plant. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/RunCards/{Index,New,Edit,Preview}`, `/User/Dispatch/GetDispatchRecommendation?priority=&type=&latitude=&longitude=&alarmLevel=` |
+| Settings | Department settings 58–60 (dispatch mode, auto-dispatch, staffing gate); station coverage rows per group |
+| Model | `RunCard`, `RunCardTrigger`, `RunCardAlarmLevel`, `RunCardUnitRequirement`, `RunCardRoleRequirement`, `RunCardStatusSelection`, `StationCoverageMinimum` |
+| Feature flag | `Dispatch.RunCards` (seeded by M0116) |
+| Workflow events | Run-card activation, escalation and move-up events (48–51) are available as triggers |
+| Design | `int-Coordination/docs/architecture/run-cards-dispatch-design.md` |
diff --git a/docs/web-app/search.md b/docs/web-app/search.md
index adbfdc9..2086350 100644
--- a/docs/web-app/search.md
+++ b/docs/web-app/search.md
@@ -1,11 +1,13 @@
---
-sidebar_position: 35
+sidebar_position: 52
title: Search
---
# Search
-The Search module provides a quick navigation command palette for accessing application features. It is managed by the `SearchController`.
+The Search module provides a quick navigation command palette for accessing application features.
+
+
## How It Works
@@ -48,8 +50,9 @@ Some items are shown only when the user has appropriate permissions:
When a query is provided, results are filtered by matching against the item label and summary text.
-## Interactions with Other Modules
+## Technical reference
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **All Modules** | Provides navigation shortcuts to all feature areas |
diff --git a/docs/web-app/security-permissions.md b/docs/web-app/security-permissions.md
index b8809a1..7d76af7 100644
--- a/docs/web-app/security-permissions.md
+++ b/docs/web-app/security-permissions.md
@@ -1,102 +1,129 @@
---
-sidebar_position: 31
+sidebar_position: 47
title: Security & Permissions
---
# Security & Permissions
-The Security module manages department-wide permissions and provides access to audit logs. It is managed by the `SecurityController`.
-
-:::note Admin Only
-All write operations in this module require **department administrator** status, checked via `ClaimsAuthorizationHelper.IsUserDepartmentAdmin()`.
-:::
-
-## Permission Configuration
-
-### Available Permissions
-
-The system manages approximately 20 permission types:
-
-| Permission | Description |
-|------------|-------------|
-| AddPersonnel | Who can add new personnel |
-| RemovePersonnel | Who can remove personnel |
-| CreateCall | Who can create dispatch calls |
-| CreateTraining | Who can create trainings |
-| CreateDocument | Who can upload documents |
-| CreateCalendarEntry | Who can create calendar events |
-| CreateNote | Who can create notes |
-| CreateLog | Who can create work logs |
-| CreateShift | Who can create shifts |
-| ViewPersonalInfo | Who can view PII (email, phone) |
-| AdjustInventory | Who can adjust inventory |
-| ViewPersonnelLocation | Who can see personnel GPS locations |
-| ViewUnitLocation | Who can see unit GPS locations |
-| CreateMessage | Who can send messages |
-| ViewGroupUsers | Who can see users in groups |
-| DeleteCall | Who can delete calls |
-| CloseCall | Who can close calls |
-| AddCallData | Who can add data to calls |
-| ViewGroupUnits | Who can see units in groups |
-| ViewContacts | Who can view contacts |
-| EditContacts | Who can edit contacts |
-| DeleteContacts | Who can delete contacts |
-
-### Permission Levels
-
-| Level | Code | Description |
-|-------|------|-------------|
-| Department Admins | 0 | Only department administrators |
-| Department + Group Admins | 1 | Department admins and group/station admins |
-| Admins + Select Roles | 2 | Admins plus users with specific personnel roles |
-| Everyone | 3 | All department members |
-
-### Setting Permissions
-
-**SetPermission:** Sets the permission level for a type.
-
-**SetPermissionData:** Sets additional data (e.g., role IDs) for a permission type while keeping the current action level.
-
-### Cache Refresh
-
-When **location/unit/personnel visibility** permissions change, a `SecurityRefreshEvent` is dispatched to invalidate caches across the system.
-
-## Audit Logs
-
-### Viewing Audit Logs
-
-The audit log system records all significant operations across the application:
-- Timestamp
-- Audit type (e.g., DepartmentSettingsChanged, CallAdded, PersonnelRemoved)
-- Descriptive message
-- Before/after JSON snapshots
-- Acting user
-- IP address and user agent
-
-### Audit Log Endpoints
-
-| Endpoint | Purpose |
-|----------|---------|
-| `GetAuditLogsList` | All audit logs as JSON with formatted timestamps and type strings |
-| `ViewAudit` | Single audit log entry detail (validates department ownership) |
-
-## Interactions with Other Modules
-
-Security permissions affect behavior across the entire application:
-
-| Module | Affected Permissions |
-|--------|---------------------|
-| **Personnel** | AddPersonnel, RemovePersonnel, ViewPersonalInfo |
-| **Dispatch** | CreateCall, DeleteCall, CloseCall, AddCallData |
-| **Mapping** | ViewPersonnelLocation, ViewUnitLocation |
-| **Units** | ViewGroupUnits |
-| **Groups** | ViewGroupUsers |
-| **Inventory** | AdjustInventory |
-| **Documents** | CreateDocument |
-| **Calendar** | CreateCalendarEntry |
-| **Notes** | CreateNote |
-| **Logs** | CreateLog |
-| **Shifts** | CreateShift |
-| **Messages** | CreateMessage |
-| **Trainings** | CreateTraining |
-| **Contacts** | ViewContacts, EditContacts, DeleteContacts |
+**Department menu → Security and Permissions** is where administrators decide *who can do what*: create calls, add people, see phone numbers, see locations on the map, manage records, adjust inventory … It also hosts the **audit log**, **2FA enforcement**, the **department security policy**, **SSO / SCIM** and **Advanced Data Protection**.
+
+
+
+## Permission levels
+
+Every permission is set to one of four levels. Changes take effect at the member's next login.
+
+| Level | Who is allowed |
+|---|---|
+| **Everyone** | All department members. |
+| **Department admins** | Department administrators and the managing user. |
+| **Department + group admins** | Also group/station administrators — usually limited to their own group (e.g. adding users to their group only). |
+| **Admins + selected roles** | Administrators plus members holding the roles you tick. |
+
+Some visibility permissions have a **Group only** option that restricts what a member sees to their own group.
+
+## The permissions
+
+### People, calls and everyday modules
+
+| Permission | Default | Controls |
+|---|---|---|
+| Who can add users / remove users | Dept admins | Adding and removing personnel; group admins are limited to their group. |
+| Who can create / delete / close calls | Everyone | Manual call creation, deletion and closing. |
+| Who can add data to calls | Everyone | Notes, images and files on calls. |
+| Who can create trainings | Dept admins | Training module authoring. |
+| Who can add documents / create calendar entries / create notes | Everyone | Content creation in those modules. |
+| Who can add log entries / delete log entries | Everyone / Dept admins | Legacy Logs module (until Records activation). |
+| Who can create shifts | Dept admins | Shift creation and editing. |
+| Who can view personal info | Everyone | Email addresses, phone numbers and other PII of other members. |
+| Who can see the location of personnel / units | Everyone | Map markers and app locations; use *Group only* to limit to the viewer's group. |
+| Who can send messages | Everyone | In-system mail. |
+| Who can view users / view units | Everyone | Restrict the roster and unit list to the viewer's group. |
+| Who can view / edit / delete contacts | Everyone | The Contacts module (members who cannot view contacts cannot attach them to calls). |
+| Use calendar sync | Everyone | Subscribe to the department calendar from an external calendar app. |
+| Dispatch app login / Command app login | Everyone | Who may sign in to the Dispatch and Incident Command apps. |
+
+### Workflows
+
+| Permission | Default |
+|---|---|
+| Create / edit workflows | Dept admins |
+| Manage workflow credentials | Dept admins |
+| View workflow runs | Dept admins |
+
+### Inventory, checklists, work orders
+
+| Permission | Default |
+|---|---|
+| Adjust inventory | Everyone |
+| Transfer inventory / Issue and return inventory | Same as *Adjust inventory* |
+| Manage controlled substances | Dept admins |
+| Manage checklists / View checklist results | Dept admins |
+| Manage work orders / View other members' work orders | Dept admins |
+
+### Records
+
+| Permission | Default |
+|---|---|
+| Create records · Void or cancel records · Review · Approve · Finalize · Amend finalized · Submit externally · Print and export · Share | Varies (see [Records → Permissions](records/overview#permissions)) |
+| View restricted sections · View legacy logs · View records from other groups | |
+| Manage record definitions · Publish record definitions · Manage record reports · Manage record disclosures · Manage legal holds · Reassign draft records · Manage prevention data | Dept admins |
+
+### Advanced Data Protection
+
+| Permission | Purpose |
+|---|---|
+| Manage data protection settings · View / edit protected call data · View protected personnel / contact / operational data · Export protected data · Configure protected data delivery · Emergency break-glass access | See [Advanced Data Protection](data-protection). |
+
+## Two-factor enforcement
+
+**Require 2FA for admins**: *Disabled*, *Department admins + managing user*, or *… + group admins*. You cannot enable it until you and the managing user both have 2FA on your own accounts. Affected members are sent to the setup page at next login.
+
+## Audit logs
+
+**Audit Logs** lists every significant operation: timestamp, type (`DepartmentSettingsChanged`, `CallAdded`, `PersonnelRemoved`, `PermissionChanged` …), a description, the acting member, IP address and user agent. Open an entry to see the **before / after** snapshots.
+
+
+
+## Department security policy
+
+`/User/Security/SecurityPolicy` — compliance controls for the whole department. **Quick presets**: *Government / CUI*, *Standard enterprise*, *Minimal*.
+
+
+
+| Setting | Notes |
+|---|---|
+| **Require MFA for all members** | Members without MFA are prompted to enrol at next login. |
+| **Require SSO — disable password login** | Needs an active SSO configuration and at least one admin who has tested SSO login. |
+| **Session timeout (minutes)** | 0 = system default; 480 = 8 h. |
+| **Max concurrent sessions per user** | 0 = unlimited; government environments typically use 1. |
+| **Allowed IP ranges (CIDR)** | Logins from outside are denied. Empty = allow all. |
+| **Data classification level** | Unclassified / CUI / Confidential — for compliance reporting and audit logs. |
+| **Password expiration (days) / minimum length** | Local logins only. Minimum 8; NIST recommends 12+; CUI requires 14+. Complexity (upper, digit, special) is always enforced. |
+
+## SSO and SCIM
+
+`/User/Security/Sso` — add **OIDC** (Entra ID, Okta, Auth0, Google) or **SAML 2.0** configurations, enable **SCIM 2.0** provisioning (auto-create, auto-disable, keep names/emails in sync) and copy the **mobile app discovery URL**. Full guides: [SSO overview](../enterprise/sso-overview), [SSO setup](../enterprise/sso-setup), [SCIM provisioning](../enterprise/scim-provisioning).
+
+
+
+## Setup examples
+
+| Department | Recommended permission changes |
+|---|---|
+| **Volunteer fire** | Create calls → *Admins + Officers*; Delete calls → Dept admins; View personal info → Everyone (members need each other's numbers); 2FA for admins. |
+| **Career fire / EMS** | Create/close calls → *Admins + Dispatcher role*; View personal info → *Admins + Officers*; personnel locations *Group only*; MFA for all; session timeout 720. |
+| **SAR / CERT** | Create calls → Team leaders; Add documents → Everyone; View unit locations → Everyone. |
+| **Emergency management** | Create calls → EOC manager + Operations role; Manage workflows → IT role; data classification CUI; IP ranges for the EOC network if desired. |
+| **Security company** | View users / units → *Group only* (clients must not see each other); View contacts → *Admins + Site leads*; SSO with the corporate IdP; Require SSO. |
+| **Industrial** | Government/CUI preset if regulated; Manage controlled substances → Safety role; audit log reviewed monthly. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Controller | `SecurityController` (`Index`, `Audits`, `ViewAudit`, `Sso`, `SsoNew`, `SsoEdit`, `ScimSetup`, `SecurityPolicy`) |
+| Actions | `SetPermission?type=&level=`, `SetPermissionData?type=` (role ids), `GetRolesForPermission?type=`, `GetAuditLogsList` |
+| Model | `Permission` (`PermissionType`, `Action` 0–3, `LockToGroup`, `Data` = role ids); `PermissionTypes` enum; `AuditLog` |
+| Cache | Permission changes raise `SecurityRefreshEvent` to invalidate the authorization matrix; `Resgrid.Console --SecurityRefresh` refreshes it manually |
+| Policies | Everything here requires `IsUserDepartmentAdmin()` |
diff --git a/docs/web-app/shifts.md b/docs/web-app/shifts.md
index d2a7580..c500da9 100644
--- a/docs/web-app/shifts.md
+++ b/docs/web-app/shifts.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 8
+sidebar_position: 17
title: Shifts
---
# Shifts
-The Shifts module manages personnel scheduling, shift signups, and shift trades. It is handled by the `ShiftsController`.
+**Shifts** schedule who is on duty. Resgrid supports **assigned** shifts (you put people on the roster), **signup** shifts (members sign up for open slots, with per-group quotas), recurring shift patterns, trades between members and attendance tracking — and shifts can drive dispatch (*dispatch shift instead of group*) and checklist scheduling.
+
+**Left menu → Shifts.** *Your Shifts* shows the signed-in member's upcoming duty; *Shift Staffing* shows who is on for each shift today; administrators create shifts and set the days, groups and quotas. Settings: **Department Settings → Shifts**.
+
+
## Shift Lifecycle
@@ -23,6 +27,8 @@ Displays all shifts with visibility based on whether the user is a department ad
**Authorization:** `Shift_Create` policy
+
+
### Shift Configuration
| Field | Description |
@@ -99,6 +105,8 @@ The shift day view shows:
**Authorization:** `Shift_View` policy
+
+
Shows the current user's:
- Upcoming shift signups
- Open trade requests directed at them
@@ -139,6 +147,8 @@ The trade system enables personnel to swap shifts:
**Authorization:** `Shift_View` policy
+
+
The staffing view allows assigning specific personnel to shifts:
- Admin users see all shifts
- Non-admin users see only their group's shifts
@@ -148,6 +158,8 @@ The staffing view allows assigning specific personnel to shifts:
**Authorization:** `Shift_View` policy
+
+
### Calendar Views
- **All Shifts Calendar** — Shows all shift days across all shifts
- **Single Shift Calendar** — Calendar view for a specific shift
@@ -162,8 +174,22 @@ Calendar items include:
**Workshift Integration:** Workshift days are also displayed on the shift calendar alongside traditional shifts.
-## Data Endpoints
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Volunteer fire** | Signup shifts per station (e.g. *Night duty crew* 18:00–06:00) with a quota of 4 and a required *Driver* role; allow multi-group signup for neighbouring stations; turn on *Dispatch shift instead of group* only once signups are reliable. |
+| **Career fire / EMS** | Assigned shifts on a 24/48 or 48/96 pattern, one shift group per station, personnel assigned by platoon; trades require officer approval. |
+| **SAR** | Signup *on-call* weeks rather than shifts; use the Calendar for trainings. |
+| **Emergency management / EOC** | Assigned 12-hour EOC shifts during activations; roles per section; signup for volunteer positions. |
+| **Security** | Assigned shifts per client site, rotating patterns, trades allowed within the same site group. |
+| **Industrial ERT** | Assigned shifts matching plant crews; minimum quota per qualification (confined space, hazmat). |
+
+## Technical reference
+`ShiftsController`; routes `/User/Shifts/{Index,NewShift,EditShiftDetails,EditShiftDays,EditShiftGroups,ShiftCalendar,YourShifts,ShiftStaffing,ViewShift,Signup,RequestTrade,ProcessTrade}`; permission `CreateShift`; events `ShiftCreatedEvent`, `ShiftTradeRequestedEvent`, `ShiftTradeFilledEvent`; module switch `ShiftsDisabled`.
+
+### Data Endpoints
| Endpoint | Purpose |
|----------|---------|
| `GetShiftCalendarItems` | Calendar items for all shifts + workshifts |
@@ -177,8 +203,7 @@ Calendar items include:
| `GetPersonnelNotOnShiftDay` | Personnel matching role requirements but not signed up |
| `GetShiftDaysUserIsOn` | Shift days the current user is on |
-## Interactions with Other Modules
-
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Dispatch** | Shift-based dispatch replaces group dispatch with shift personnel |
diff --git a/docs/web-app/subscription-billing.md b/docs/web-app/subscription-billing.md
index 6926120..13ac6ea 100644
--- a/docs/web-app/subscription-billing.md
+++ b/docs/web-app/subscription-billing.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 30
+sidebar_position: 51
title: Subscription & Billing
---
# Subscription & Billing
-The Subscription module manages department plan selection, payment processing, and addon management through Stripe integration. It is managed by the `SubscriptionController`.
+**Subscription & Billing** shows the department's plan (Free, Standard, Premium, Ultimate, Enterprise), what it includes and its limits (personnel, units, features), lets the **managing user** upgrade, change billing details, buy **add-ons** (Push-to-Talk, Advanced Data Protection, Readiness Pro) and download invoices. Self-hosted installations show the plan they are licensed for.
+
+**Department menu → Subscription and Billing.** Only the managing user can purchase or cancel.
+
+
## Subscription Dashboard
@@ -82,6 +86,8 @@ The `ValidateCoupon` endpoint checks a Stripe coupon code and returns "Valid" or
### PTT (Push-to-Talk) Addon
+
+
Manage the PTT addon subscription:
- View current PTT quantity from active Stripe subscription
- Add PTT addon (modifies subscription quantity)
@@ -97,14 +103,28 @@ The `BuyAddon` action supports purchasing plan addons:
View all historical payments for the department.
+
+
## Invoice Viewing
**Authorization:** `CanUserViewPayment` runtime check
Displays invoice details with deserialized Stripe `Charge` data.
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Small volunteer department** | Free or Standard covers dispatch, personnel and units; add PTT if you use the apps as radios. |
+| **Career fire / EMS** | Premium/Ultimate for voice alerting, shifts and records; Readiness Pro for work orders; ADP if patient data is stored. |
+| **Multi-agency / government** | Enterprise for SSO/SCIM and security policy; department links for shared dispatch. |
+| **Business / industrial** | Standard plus Readiness Pro (maintenance) and PTT. |
+
+## Technical reference
+
+`SubscriptionController`, `ReadinessProBillingController`; routes `/User/Subscription/{Index,UpdateBillingInfo,Cancel,BuyAddon,ManagePTTAddon,BuyAdpAddon,ManageAdpAddon,PaymentHistory,ViewInvoice,SelectRegistrationPlan}`; payments through Stripe or Paddle; plan limits cached 14 days (`SubscriptionsService`, `LimitsService`); addon entitlements checked live (`ReadinessAccessService`).
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Dashboard** | Plan limit warnings displayed |
diff --git a/docs/web-app/templates.md b/docs/web-app/templates.md
index 74fad81..c7617a0 100644
--- a/docs/web-app/templates.md
+++ b/docs/web-app/templates.md
@@ -1,11 +1,13 @@
---
-sidebar_position: 25
+sidebar_position: 40
title: Templates
---
# Templates
-The Templates module provides call quick templates and call note autofills that streamline call creation. It is managed by the `TemplatesController`.
+The Templates module provides call quick templates and call note autofills that streamline call creation.
+
+
## Call Quick Templates
@@ -66,8 +68,18 @@ Modify name, data text, and sort order.
Validates department ownership.
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Fire** | Templates: Structure fire, Vehicle fire, MVA, Alarm — each pre-selecting type, priority and dispatch targets. |
+| **EMS** | Templates per determinant level with the right unit type. |
+| **Security** | Alarm response, Escort, Medical templates; call-note templates for standard dispositions. |
+| **Delivery** | Delivery, Pickup templates with destination fields. |
+
+## Technical reference
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Dispatch** | Templates pre-fill call form; autofills insert into call notes |
diff --git a/docs/web-app/trainings.md b/docs/web-app/trainings.md
index a9c0f96..26aa749 100644
--- a/docs/web-app/trainings.md
+++ b/docs/web-app/trainings.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 17
+sidebar_position: 25
title: Trainings
---
# Trainings
-The Trainings module enables creation and delivery of training materials with quiz assessment capabilities. It is managed by the `TrainingsController`.
+**Trainings** is a lightweight learning-management module: write or attach course material (text, files, links to videos), add **quiz questions**, assign the training to members or roles with a due date, and track who has completed it and their scores. Completed trainings can also feed certification records.
+
+**Left menu → Trainings.** Members take assigned trainings from the web or the Responder app.
+
+
## Training List
@@ -15,6 +19,8 @@ Displays all trainings for the department.
### Training Fields
+
+
| Field | Required | Description |
|-------|----------|-------------|
| Name | Yes | Training title |
@@ -51,6 +57,8 @@ When a user views a training:
- The content is displayed (title, description, text, attachments)
- The training is **automatically marked as viewed** for the current user
+
+
This enables view tracking for compliance and reporting.
## Taking Quizzes
@@ -89,8 +97,21 @@ The `Report` action generates a training participation report showing:
- Quiz results
- Group assignments for each user
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Volunteer fire** | Annual refreshers (SCBA, bloodborne pathogens, driver safety) with a 5-question quiz each; assign to the *Firefighter* role with a 30-day due date; report to the training officer. |
+| **EMS** | Protocol updates as trainings with an acknowledgement quiz; CE tracking through certifications. |
+| **SAR** | Navigation and radio trainings for new members; link to external video courses. |
+| **CERT** | Module refreshers between in-person classes; completion required before deployment eligibility. |
+| **Security / industrial** | Post-order acknowledgements, hazard communication, LOTO awareness — with quiz pass mark 80 %. |
+
+## Technical reference
+
+`TrainingsController`; routes `/User/Trainings/{Index,New,View,Edit,Quiz,Report,ResetUserTraining,DeleteTraining}`; permission `CreateTraining`; events `TrainingAddedEvent`, `TrainingUpdatedEvent`; module switch `TrainingDisabled`.
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Personnel** | Training assignment targets |
diff --git a/docs/web-app/types-configuration.md b/docs/web-app/types-configuration.md
index 4bc9f0e..84d60db 100644
--- a/docs/web-app/types-configuration.md
+++ b/docs/web-app/types-configuration.md
@@ -1,16 +1,22 @@
---
-sidebar_position: 22
+sidebar_position: 39
title: Types & Configuration
---
# Types & Configuration
-The Types module is a centralized configuration area for managing various entity types used throughout the system. It is managed by the `TypesController`.
+**Types** are the pick-lists the rest of Resgrid is built on: **unit types** (Engine, Ambulance, Patrol car), **call types** (Fire, Medical, Alarm), **call priorities** (with colours, sounds and dispatch behaviour), **certification types**, **document categories**, **note categories**, **contact note types** and the **personnel status list ordering**. Set them up early — dispatch, run cards, NERIS crosswalks, custom statuses and reports all refer to them.
+
+**Department menu → Types.**
+
+
## Unit Types
Define categories for units (Engine, Ladder, Ambulance, etc.):
+
+
| Field | Description |
|-------|-------------|
| Type Name | Unit type name (required, unique) |
@@ -28,6 +34,8 @@ All operations fire audit events with before/after snapshots.
Define incident categories (Fire, EMS, MVA, etc.):
+
+
| Field | Description |
|-------|-------------|
| Type Name | Call type name (required) |
@@ -42,6 +50,8 @@ Define incident categories (Fire, EMS, MVA, etc.):
Define urgency levels for calls with visual and audio indicators:
+
+
| Field | Description |
|-------|-------------|
| Priority Name | Display name (required, unique) |
@@ -124,8 +134,24 @@ All operations use:
1. ASP.NET `[Authorize(Policy = "Department_Update")]` attribute
2. Resgrid's `IAuthorizationService` for fine-grained checks
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Volunteer / career fire** | Unit types: Engine, Ladder/Truck, Rescue, Tender, Brush, Command, Utility. Call types: Structure fire, Vehicle fire, Brush/wildland, Alarm, MVA, Medical, Hazmat, Public assist, Water rescue. Priorities: Low, Medium, High, Emergency (Emergency = full alert sound, overrides quiet hours). Certifications: FF1, FF2, Driver/Operator, EMT, Officer 1. |
+| **EMS** | Unit types: ALS, BLS, Supervisor, Wheelchair van. Call types by nature (Cardiac, Trauma, Respiratory, IFT, Standby). Priorities Echo/Delta/Charlie/Bravo/Alpha/Omega if you follow MPDS. Certifications: EMT, AEMT, Paramedic, CPR, ACLS, PALS. |
+| **SAR** | Unit types: Ground team, K9 team, Technical team, UTV, Drone. Call types: Missing person, Overdue hiker, Rescue, Recovery, Evidence search, Mutual aid, Training. Certifications: SARTECH II, Wilderness first aid, Rope tech. |
+| **Emergency management** | Unit types: EOC section, MCV, Trailer. Call types: Activation, Weather event, Resource request, Shelter opening, Exercise. Priorities: Monitoring, Partial activation, Full activation. |
+| **CERT** | Unit types: CERT team; call types: Deployment, Training, Community event. |
+| **Security** | Unit types: Patrol vehicle, Foot post, Bike; call types: Alarm, Suspicious activity, Escort, Medical, Fire alarm, Access control. Priorities: Routine, Urgent, Emergency. |
+| **Delivery / transit** | Unit types: Van, Truck, Bus; call types: Delivery, Pickup, Breakdown, Accident, Passenger incident. Priorities by SLA. |
+| **Industrial ERT** | Unit types: Fire brigade, Hazmat, Rescue, Medical; call types: Fire, Spill/release, Confined space, Medical, Evacuation, Drill; certifications for every OSHA/NFPA qualification. |
+
+## Technical reference
+
+`TypesController` (+ `Department/Types` index page); routes `/User/Types/{NewUnitType,EditUnitType,NewCallType,EditCallType,NewCallPriority,EditCallPriority,NewCertificationType,NewDocumentType,NewNoteType,NewContactNoteType,ListOrdering}`; model `UnitType`, `CallType`, `DepartmentCallPriority` (colour, sound, `IsDefault`, `Tone`, `DispatchPersonnel/Units`), `CertificationType`, `DocumentCategory`, `NoteCategory`, `ContactNoteType`.
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Units** | Unit types categorize units |
diff --git a/docs/web-app/unit-tracking.md b/docs/web-app/unit-tracking.md
new file mode 100644
index 0000000..f97bfde
--- /dev/null
+++ b/docs/web-app/unit-tracking.md
@@ -0,0 +1,63 @@
+---
+sidebar_position: 9
+title: Hardware GPS Tracking
+---
+
+# Hardware GPS Tracking (Unit Tracking)
+
+Units normally report their position from the **Unit app** on a phone or tablet. **Hardware GPS tracking** lets a dedicated tracker — a Teltonika or Digital Matter device wired into the apparatus, or a forwarding service such as Traccar — send positions for a unit directly, so the unit is on the map even when no crew phone is running the app.
+
+**Units → (unit row) → Tracking**, or `/User/UnitTracking/Index?unitId=…`.
+
+
+
+## Concepts
+
+| Term | Meaning |
+|---|---|
+| **Tracking binding** | The link between one unit and one device or forwarding service: profile, device identifier, credentials and source restrictions. One unit can have several bindings (e.g. a hardware tracker plus a Traccar forward) with a **source priority** that decides which wins when both report. |
+| **Tracking profile** | The device or service model and its protocol/transport: *Generic Resgrid JSON over HTTPS*, *Traccar forwarding*, *Teltonika Codec 8 (TCP/UDP)*, *Digital Matter managed JSON* … Each profile has a **certification status** — *Certified* profiles are selectable; *Candidate* profiles are visible but not yet usable until Resgrid has tested them with real device evidence. |
+| **Credential** | A token (bearer, basic or custom header) issued per binding for HTTPS profiles. Shown once; rotate or revoke at any time. |
+| **Allowed source networks** | Optional CIDR ranges that may send positions for this tracker. |
+
+## Adding a binding
+
+**Add tracking binding**:
+
+| Field | Notes |
+|---|---|
+| **Tracking profile** | Pick the device / service. |
+| **Display name** | e.g. `Engine 1 Teltonika FMC130`. |
+| **Device identifier** | The identifier the device emits (IMEI for Teltonika, unique id for Traccar, serial for Digital Matter). It is normalized before storage. |
+| **Secondary identifier / Firmware version** | Optional, for your records. |
+| **Source priority** | Higher wins when several bindings report for the same unit. |
+| **Allowed source networks** | Comma-separated IPv4/IPv6 CIDRs. |
+
+
+
+Then, for HTTPS profiles, **Create credential** (choose the **authentication mode** — bearer, basic or header — and copy the token: it is shown once). Configure the device or forwarding service with the endpoint shown on the page and the credential.
+
+## Monitoring
+
+The binding's **Tracking status** shows last received, last valid fix, last error code and delivery health. Department administrators (outside production) can **Send test JSON** to validate a generic payload without authenticating or storing it. **Disable tracking** revokes every credential for the binding.
+
+Positions from hardware trackers flow through the same pipeline as app positions: the unit appears on the Mapping page, in the Dispatch and Big Board apps, feeds closest-unit [run-card](run-cards) selection and can be captured as *Unit tracking fixes* evidence on a [Record](records/authoring#evidence).
+
+## Setup examples
+
+| Department | Setup |
+|---|---|
+| **Fire / EMS with hard-wired trackers** | One Teltonika binding per apparatus (TCP, IMEI), Unit app as secondary source. |
+| **Fleet already on Traccar** | One *Traccar forwarding* binding per unit pointing the Traccar forward at the Resgrid endpoint. |
+| **SAR / volunteer** | Usually the Unit app only; add a Digital Matter Oyster on trailers and UTVs that have no crew phone. |
+| **Security / delivery** | Vehicle trackers for every patrol / delivery vehicle; source priority above the phone app. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Routes | `/User/UnitTracking/{Index,New,Details,Edit}?unitId=` |
+| Gateway | `Resgrid.TrackerGateway` (separate process; TCP/UDP listeners per enabled protocol module) and generic HTTPS ingress on the API |
+| Providers | `Resgrid.Providers.Tracking` — protocol modules (`teltonika-codec8`, Traccar v6.14.5 adapter pinned, `digitalmatter-json-v1` gated) |
+| Retention | `UnitLocationRetentionRepository` (NoSQL) |
+| Design | `int-Coordination/docs/architecture/hardware-gps-tracking-implementation-design.md` |
diff --git a/docs/web-app/units.md b/docs/web-app/units.md
index 829c8b1..b3a8c27 100644
--- a/docs/web-app/units.md
+++ b/docs/web-app/units.md
@@ -1,195 +1,72 @@
---
-sidebar_position: 6
+sidebar_position: 8
title: Units
---
# Units
-Units represent vehicles, apparatus, equipment, or any tracked asset in the department. The Units module is managed by the `UnitsController`.
+A **unit** is anything that responds as one thing and has a status of its own: an engine, ambulance, ladder, brush truck, command vehicle, patrol car, delivery van, a SAR team, a hazmat team, a drone. Units have a **type**, a **station**, optional **roles** (seats) that people are assigned to, a live **status** (Available, Responding, On scene, Out of service …), GPS position from the Unit app or a [hardware tracker](unit-tracking), and their own logs and equipment.
-## Unit List
+
-**Authorization:** `Unit_View` policy
+## Where to find it
-The main index displays all units organized by group/station with:
-- Unit name and type
-- Current state (with custom state colors)
-- Station assignment
-- Tree-view sidebar for group filtering
+**Left menu → Units.** Units are listed by station/group with type, current state and timestamp. Buttons: **Events**, **Logs**, **Edit**, **Delete**; select several to **set status** at once (only units sharing the same status set can be selected together). **Unit Staffing** and **New Unit** are in the toolbar.
-**Visibility:** Unit visibility is governed by the `CanUserViewUnitViaMatrix` authorization check, which can restrict visibility based on group membership.
+## Creating a unit
-## Creating Units
+
-**Authorization:** `Unit_Create` policy
+| Field | Notes |
+|---|---|
+| **Name** | `Engine 1`, `Medic 12`, `Patrol 3`, `Team Alpha`. |
+| **Type** | From your [unit types](types-configuration#unit-types). Type decides which custom statuses apply and is used by run cards and coverage minimums. |
+| **Station / group** | Where it is based. Units can also be un-grouped. |
+| **Unit roles** | Seats that can be staffed: *Driver*, *Officer*, *Firefighter*, *Paramedic*, *Navigator*. Mark a role **required** so the unit shows as partially staffed until it is filled. |
+| **Custom fields** | Any [User Defined Fields](user-defined-fields) configured for units (VIN, radio ID, capacity …). |
-### Unit Fields
+Adding is blocked when the plan's unit limit is reached.
-| Field | Required | Description |
-|-------|----------|-------------|
-| Unit Name | Yes | Must be unique within the department |
-| Unit Type | No | Classification (Engine, Ladder, Ambulance, etc.) |
-| Station Group | No | Home station assignment |
-| Custom State | No | Assign a custom unit state set |
+## Unit status
-### Unit Roles
+Set a unit's status from the list, the [Dashboard](dashboard), the Unit app or the API. Statuses come from the default set — Available, Delayed, Unavailable, Committed, Out of Service — or, more usually, from [custom unit statuses](custom-statuses) defined per unit type (Responding, On Scene, Transporting, At Hospital, Returning …). A status can require a **destination** (a station or an active call) and carries an optional note and location. Statuses drive dispatch availability, the map, Big Board and reports.
-Each unit can have defined roles (Driver, Officer, etc.):
-- Role names must be unique within the unit
-- Roles are used for staffing assignments
+## Unit staffing
-### Creation Process
-1. Validates name uniqueness
-2. Saves the unit and its roles
-3. Creates a Novu subscriber (for push notifications)
-4. Fires `AuditEvent` (UnitAdded) and `UnitAddedEvent`
+**Unit Staffing** assigns people to unit roles for the shift or day — who is driving Engine 1, who is the officer. Staffing is what the Unit app shows as the crew, what checklists route to, and what the *minimum staffing* gate uses in [run cards](run-cards). Members are searched by name; only active members appear.
-## Editing Units
+
-**Authorization:** `Unit_Update` policy + `CanUserModifyUnit` runtime check
+## Unit logs and events
-Updates unit name, type, station group, and roles. Fires `AuditEvent` (UnitChanged).
+- **Logs** — narrative entries for the unit (mileage, maintenance notes, activity). After Records activation these become **Unit activity** records in [Records](records/authoring).
+- **Events** — every status, staffing and location change; **Generate report** prints it; administrators can clear all statuses for a unit.
-## Deleting Units
+## Equipment, checklists and tracking
-**Authorization:** `Unit_Delete` policy + `CanUserModifyUnit` runtime check
+From a unit you also reach its **equipment** (everything issued to it in [Inventory](inventory)), its [checklists](checklists) (target type *Unit*), its [work orders](work-orders) and its **hardware GPS tracking** bindings.
-Deletes a unit. Fires `AuditEvent` (UnitRemoved).
+## Setup examples
-## Unit State Management
+| Department | Units and roles |
+|---|---|
+| **Fire** | Engine (Driver, Officer, FF ×2), Ladder, Rescue, Tender, Brush, Chief (Officer). One unit type per apparatus kind so statuses fit. |
+| **EMS** | Medic units (Driver/EMT, Attendant/Paramedic), Supervisor; statuses Responding / On scene / Transporting / At hospital / Available. |
+| **SAR** | Teams as units (Team Leader, Navigator, Medic, Searchers), UTVs and K9 as units. |
+| **Emergency management** | EOC sections as units are *not* recommended — use groups; units for MCVs, trailers, generators that move. |
+| **Security** | Patrol vehicles and foot posts as units with a single *Officer* role; statuses On patrol / At post / Responding / Break. |
+| **Delivery / transit** | One unit per vehicle with *Driver* role; statuses Loading / En route / Delivering / Returning. |
+| **Industrial ERT** | Brigade engine, hazmat trailer, rescue truck; roles per certification. |
-### Setting Unit State
+## Technical reference
-Units have a current operational state that can be set through several methods:
-
-| Method | Description |
-|--------|-------------|
-| `SetUnitState` | Set a single unit's state |
-| `SetUnitStateWithDest` | Set state with a destination (call or station) |
-| `SetUnitStateForMultiple` | Batch state change for multiple units (pipe-delimited IDs) |
-| `SetUnitStateWithDestForMultiple` | Batch state + destination for multiple units |
-
-### State Destinations
-
-When setting a unit state, a destination type determines the context:
-
-| Detail Type | Options |
-|-------------|---------|
-| None | No destination |
-| Calls | Select from active calls |
-| Stations | Select from station groups |
-| CallsAndStations | Select from either calls or stations |
-
-### Default Unit Statuses
-
-If no custom unit states are defined:
-
-| Status | Description |
-|--------|-------------|
-| Available | Ready for dispatch |
-| Delayed | Available with delay |
-| Unavailable | Not available |
-| Committed | Currently committed |
-| Out Of Service | Not operational |
-| Responding | En route |
-| On Scene | At incident |
-| Staging | At staging area |
-| Returning | Returning to station |
-| Cancelled | Response cancelled |
-| Released | Released from incident |
-| Manual | Manual status |
-| Enroute | En route to destination |
-
-### Dynamic Status Dropdowns
-
-The controller provides several endpoints for building dynamic status dropdowns:
-- `GetUnitStatusHtmlForDropdown` — HTML options based on unit type's custom states
-- `GetUnitStatusHtmlForDropdownByStateId` — HTML options by custom state ID
-- `GetUnitStatusDestinationHtmlForDropdown` — Destination dropdown based on status detail type
-- `GetUnitOptionsDropdown` — Full HTML dropdown menu with state options and destination sub-menus
-- `GetUnitOptionsDropdownForStates` — Same for multiple units with a shared state
-
-## Unit Staffing
-
-**Authorization:** `Unit_View` policy
-
-Unit staffing assigns personnel to specific unit roles:
-
-### Viewing Staffing
-Displays all units with their roles and currently assigned personnel.
-
-### Updating Staffing
-1. Select personnel for each role on each unit
-2. On save, existing active role assignments are deleted
-3. New `UnitActiveRole` entries are created from the form data
-
-### Personnel Search for Staffing
-The `GetPersonnelForUnitStaffingJson` endpoint supports search-as-you-type for finding personnel to assign, returning name, group, and role information.
-
-## Unit Logs
-
-### Creating Unit Logs
-**Authorization:** `UnitLog_Create` policy
-
-Add narrative log entries for a unit. The narrative text is HTML-decoded before storage.
-
-### Viewing Unit Logs
-**Authorization:** `UnitLog_View` policy
-
-View all log entries for a specific unit.
-
-## Unit Events & Tracking
-
-### Viewing Events
-**Authorization:** `Unit_View` policy
-
-Displays unit state change events on a map with:
-- Map centered on department coordinates
-- OSM (OpenStreetMap) integration
-- Custom state resolution for event labels
-
-### Event Data
-The `GetUnitEvents` endpoint returns:
-- All unit state events
-- Custom state name and color resolution
-- Destination names (calls or stations resolved from IDs)
-- GPS coordinates for map display
-
-### Generating Event Reports
-Select specific events to generate a report with:
-- Event details and timestamps
-- Resolved destination names (station names, call names)
-- Timeline of unit activity
-
-## ETA Calculation
-
-When viewing units for a call, the system calculates **Estimated Time of Arrival**:
-1. Gets the unit's last known GPS position
-2. Uses `IGeoService.GetEtaInSecondsAsync` to calculate travel time to the call location
-3. Displays ETA in the call dispatch grid
-
-## Data Endpoints
-
-| Endpoint | Purpose |
-|----------|---------|
-| `GetUnits` | All units (id, name, type, station) |
-| `GetUnitsForGroup` | Units for a specific group |
-| `GetUnitsAndRolesForGroup` | Units with roles for a group |
-| `GetUnitTypes` | Department unit types |
-| `GetUnitsList` | Units with current state, color, timestamp |
-| `GetUnitsForCallGrid` | Units with ETA to call location |
-| `GetActivePersonnelForUnitStaffingRoleJson` | Currently assigned person for a unit role |
-
-## Interactions with Other Modules
-
-| Module | Interaction |
-|--------|-------------|
-| **Dispatch** | Units dispatched to calls |
-| **Groups** | Units assigned to station groups |
-| **Custom Statuses** | Custom unit state definitions |
-| **Mapping** | Unit locations shown on maps |
-| **Shifts** | Unit roles used in shift requirements |
-| **Calls** | Unit destination can be a call |
-| **Reports** | Unit state history reports |
-| **Command** | Unit types used in command definitions |
-| **Novu** | Push notification integration |
+| Item | Value |
+|---|---|
+| Controller | `UnitsController`, `UnitTrackingController` |
+| Routes | `/User/Units/{Index,NewUnit,EditUnit,DeleteUnit,UnitStaffing,AddLog,ViewLogs,ViewEvents}` (`?unitId=`) |
+| Policies | `Unit_View/Create/Update/Delete` + `CanUserViewUnit`, `CanUserEditUnit` |
+| Permissions | `ViewGroupUnits`, `CanSeeUnitLocations` |
+| Data endpoints | `GetUnitsList`, `GetUnits`, `GetUnitsForGroup?groupId=`, `GetUnitsAndRolesForGroup`, `GetUnitsForCallGrid?callLat=&callLong=` (ETA), `GetUnitEvents?UnitId=`, `SetUnitState`, `SetUnitStateWithDest`, `SetUnitStateForMultiple`, `GetUnitStatusHtmlForDropdown`, `GetPersonnelForUnitStaffingJson?search=` |
+| Events | `UnitAddedEvent`, `UnitStatusEvent`, `AuditEvent` |
+| Legacy | `UnitLog` writes are blocked after Records activation (use Unit activity records) |
+| API | `api/v4/Units/*`, `api/v4/UnitStatus/*`, `api/v4/UnitLocation/*` |
diff --git a/docs/web-app/user-defined-fields.md b/docs/web-app/user-defined-fields.md
index 528c9e9..4dd1e45 100644
--- a/docs/web-app/user-defined-fields.md
+++ b/docs/web-app/user-defined-fields.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 38
+sidebar_position: 43
title: User Defined Fields
---
@@ -7,6 +7,8 @@ title: User Defined Fields
The User Defined Fields module allows departments to define, manage, and view custom data fields on **Calls**, **Personnel**, **Units**, and **Contacts**. UDF field definitions are configured by Department Admins via the UDF management page. Field values are captured in the standard create/edit forms for each entity type and are displayed on detail/view pages.
+
+
**Authorization:** UDF definition management requires Department Admin access. Viewing and editing field values on records follows the same permissions as the parent entity.
**Navigation:** Department Menu → User Defined Fields
@@ -194,3 +196,13 @@ For definition configuration changes (adding/editing/removing fields), filter by
- [User Defined Fields API](../api/user-defined-fields.md) — REST API reference for programmatic access to definitions, values, and mobile schema
- [Forms](forms.md) — Visual form builder for extending the New Call creation workflow
- [Workflows](workflows.md) — Automations that can interact with UDF field values
+
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Fire** | Calls: Box number, Mutual aid given/received, Water used (gal). Units: VIN, Pump capacity, Radio ID. Personnel: Pager number, Shirt size. |
+| **EMS** | Calls: Determinant code, Transport destination; Personnel: Licence number. |
+| **SAR** | Calls: Subject age, Point last seen, Mission number; Personnel: Pack weight limit. |
+| **Security** | Calls: Client PO number, Site code; Units: Plate number. |
+| **Records** | Extend locked record types (Run, NERIS) with department fields — never sent in standardized exports. |
diff --git a/docs/web-app/voice-audio.md b/docs/web-app/voice-audio.md
index 9bd7ecb..b888ac5 100644
--- a/docs/web-app/voice-audio.md
+++ b/docs/web-app/voice-audio.md
@@ -1,11 +1,13 @@
---
-sidebar_position: 33
+sidebar_position: 36
title: Voice & Audio
---
# Voice & Audio
-The Voice module manages VoIP voice channels and audio streams for department communication. It is managed by the `VoiceController`.
+The Voice module manages VoIP voice channels and audio streams for department communication.
+
+
:::note Plan-Gated Feature
Voice capability is checked at every action via `CanDepartmentUseVoiceAsync`. This feature requires an appropriate subscription plan or PTT addon.
@@ -73,8 +75,18 @@ Modify stream name and URL. Validates department ownership.
Removes an audio stream. Validates department ownership.
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Fire** | PTT channels: Dispatch, Fireground 1/2, Command; audio streams: the county dispatch scanner feed. |
+| **SAR** | Channels per team plus Base; use PTT where radio coverage is poor. |
+| **Security** | Channels per site; supervisors channel. |
+| **Events** | Temporary channels per event. |
+
+## Technical reference
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Subscription** | PTT addon enables voice features |
diff --git a/docs/web-app/weather-alerts.md b/docs/web-app/weather-alerts.md
index 05e3259..0c6b263 100644
--- a/docs/web-app/weather-alerts.md
+++ b/docs/web-app/weather-alerts.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 39
+sidebar_position: 37
title: Weather Alerts
---
@@ -7,6 +7,8 @@ title: Weather Alerts
The Weather Alerts module automatically ingests severe weather alerts from government meteorological agencies, notifies department members, and optionally attaches relevant alerts to dispatch calls. It is designed for first responder organizations that need real-time situational awareness of severe weather in their jurisdiction.
+
+
**Authorization:** Viewing alerts requires the `WeatherAlert_View` permission. Managing sources and zones requires `Department_Update` (department administrator). Creating, updating, and deleting sources requires `WeatherAlert_Create`, `WeatherAlert_Update`, and `WeatherAlert_Delete` permissions respectively.
**Navigation:** Department Menu → Weather Alerts
@@ -266,8 +268,18 @@ The display language is determined by each user's language preference.
---
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Fire / wildland** | Red flag warnings and wind advisories for your zones → notification to officers. |
+| **Emergency management** | All watches/warnings for county zones → EOC duty officer; severity threshold Warning. |
+| **SAR** | Winter storm and avalanche products for mountain zones. |
+| **Transit / delivery** | Winter weather advisories → operations. |
+
+## Technical reference
+### Interactions with Other Modules
| Module | Interaction |
|---|---|
| **Dispatch / Calls** | Active alerts can be automatically attached as system call notes when Call Integration is enabled |
diff --git a/docs/web-app/work-orders.md b/docs/web-app/work-orders.md
new file mode 100644
index 0000000..eb02215
--- /dev/null
+++ b/docs/web-app/work-orders.md
@@ -0,0 +1,175 @@
+---
+sidebar_position: 27
+title: Work Orders & Maintenance
+---
+
+# Work Orders & Maintenance
+
+Work Orders track repairs, inspections and preventive maintenance for your apparatus, stations, facilities and equipment — from the moment somebody reports a problem to the moment an authorized person verifies the fix and (where needed) releases a safety hold. It sits alongside [Checklists](checklists) (which *find* the problems) and [Inventory](inventory) (which holds the parts and serialized assets).
+
+:::info Readiness Pro add-on
+Work Orders and the preventive-maintenance engine are part of the paid **Readiness Pro** add-on. History always remains readable; *creating new* work requires an active Readiness Pro subscription and the Maintenance module enabled under **Department Settings → Module Settings**. Subscribe from **Work Orders → Readiness Pro** or **Department → Subscription & Billing**.
+:::
+
+
+
+## Where to find it
+
+**Left menu → Work Orders.** The landing page is the filterable list. The toolbar links to **New work order**, **Preventive maintenance** (recurring schedules), **Operations policy**, **Bulk operations**, **Maintenance reports** and **Service history**.
+
+Filters: status, priority, type, target (unit / group / equipment), **Assigned to me**.
+
+## Lifecycle of a work order
+
+```
+Requested → Accepted → Assigned → In progress → Completed → Closed
+ ↘ Rejected / Duplicate / Cancelled ↕ On hold
+```
+
+| Status | Meaning |
+|---|---|
+| **Requested** | Somebody submitted a request. Anyone with department membership can request. |
+| **Accepted** | A manager triaged it and agreed it is real work. Acceptance stops the *response* clock. |
+| **Assigned** | Given to a specific member or personnel role. The assignee must **Accept assignment** before work can start. |
+| **In progress** | Work is being done. Labor, parts and files are usually added here. |
+| **On hold** | Waiting for parts, vendor, weather, approval … |
+| **Completed** | The technician says the work is done and confirms all task steps are complete. Completion stops the *repair* clock. |
+| **Closed** | Verified. Safety-critical work must be verified by a *different* authorized person. |
+| **Rejected / Duplicate / Cancelled** | Terminal states. Duplicate records the canonical work-order ID. |
+
+Every status change asks for a **reason** and is written to the **Activity** timeline.
+
+## Creating a work order
+
+**Work Orders → New work order** is a four-step form.
+
+
+
+**1 · Describe the work**
+
+| Field | Notes |
+|---|---|
+| **Title / Description** | What needs doing. Be specific — this is what the technician reads. |
+| **Type** | Corrective, Preventive, Inspection, Facility, Other. |
+| **Priority** | Low, Normal, High, Emergency. Priority drives the service-level clocks (see *Operations policy*). |
+| **Due date** | Drives the overdue flag and escalation. |
+
+**2 · What it is for**
+
+| Field | Notes |
+|---|---|
+| **Maintenance target** | A **Unit** (apparatus), a **Group / station**, or a serialized **Equipment** asset from Inventory. |
+| **Site, building or location** | Free text: `Station 2 bay 3`, `Roof, north side`. |
+
+**3 · Cost and vendor**
+
+| Field | Notes |
+|---|---|
+| **Estimated cost / Approved cost / Currency / Cost center** | Used by the spending-approval policy and the cost reports. |
+| **Vendor details / Warranty reference** | Who is doing outside work and whether it is under warranty. |
+
+**4 · Safety and procedure**
+
+| Field | Notes |
+|---|---|
+| **Safety-critical work** | Requires independent verification before closure and enables safety holds. |
+| **Hazardous work** | Requires procedure reference, version, permit, isolation reference and qualified-personnel details before work can start. |
+| **Task steps** | The checklist the technician works down. All steps must be confirmed before *Completed*. |
+
+:::caution
+Resgrid records procedure and isolation references; it does **not** perform physical isolation (lock-out / tag-out) or authorize return to service. Your written safety procedures still govern.
+:::
+
+## Working a work order
+
+The detail page has tabs for **Activity**, **Comments**, **Labor**, **Parts**, **Files**, **Safety holds** and (Readiness Pro operations) **Spending approvals**, **Vendor charges** and **Parts allocation**.
+
+
+
+- **Labor** — work date, hours, hourly rate, note. The person defaults to the current user.
+- **Parts** — either **free-text parts** (recorded for cost only; Inventory stock is not changed) or **Inventory-linked parts** (item, source stock location, lot). Inventory parts use ledger costs and, for controlled stock, still require an independent witness in Inventory.
+- **Files** — PDF, PNG or JPEG up to 10 MB, virus-scanned. Files can be **withdrawn** but never deleted.
+- **Resolution / Cause / Verification and test evidence / Verified by** — filled in at completion and closure.
+- **Export** produces a printable record with the revision reference.
+
+### Safety holds
+
+When a work order places a **unit out of service** or **equipment out for repair** (manually via **Apply safety hold**, or automatically from a failed [checklist](checklists)), the unit's status is changed and the hold is recorded. Releasing a hold requires an **independent authorized reviewer** who records their qualification and release evidence. **Closing a work order never restores service by itself** — the hold must be released, and the previous state is only restored if it is unchanged and no other holds remain.
+
+### Parts allocation (Readiness Pro operations)
+
+Reserve stock → issue it to a work location → consume it, or return unused parts to the source. Reserved and issued balances cannot be used by other orders. Only *consumption* is charged as a parts expense. Outstanding reservations must be released before the order can be completed.
+
+## Preventive maintenance (recurrences)
+
+**Work Orders → Preventive maintenance → New preventive schedule** creates a schedule that generates work orders automatically.
+
+
+
+| Trigger | Options |
+|---|---|
+| **Calendar frequency** | None, Daily, Weekly, Monthly, Quarterly, Yearly, with **first due date and local time**, **time zone**, optional **service window** (e.g. only on weekdays 08:00–16:00) and **blackout** dates. |
+| **Meter trigger** | Operating hours, operating cycles, miles or kilometres, with an **interval** and **baseline**. Record readings from the schedule page (**Record reading**) or let the [Unit app](../apps/unit) / API feed them. A **meter reset** (replacement) is an audited action with a required reason. |
+| **Condition trigger** | A threshold on a recorded measurement (at or above / at or below), e.g. tyre tread depth, battery voltage, pressure. |
+| **Lead time in days** | Create the work order this many days before it is due. |
+| **Completion-based** | Measure the next interval from verified closure instead of from the previous due date. |
+| **Assignment and escalation** | Who the generated order goes to; **escalate after N overdue minutes** to an **escalation role**. |
+
+Calendar, meter and condition triggers use whichever is reached first. One pending order is allowed per schedule; cancelling a generated order pauses the schedule for review. Use **Approve deferral** to move a due date with an audited reason rather than editing it.
+
+## Operations policy
+
+**Work Orders → Operations policy** (administrators) sets department-wide rules:
+
+
+
+| Section | What it controls |
+|---|---|
+| **Spending approvals** | Require independent approval when estimated cost, or the running total of labor + vendor charges + committed parts, exceeds a **threshold** (per currency). The requester can never approve their own request. |
+| **Business calendar** | Working days, hours and holidays used for the service-level clocks. |
+| **Service targets** | Per-priority **response target** and **repair target** in working minutes. Deadlines start at creation; acceptance stops the response clock; completion stops the repair clock. Set both to zero to disable a priority. |
+
+## Bulk operations and import
+
+- **Bulk operations** — preview up to 200 rows of assignment or status changes, then apply the valid rows. Each row is applied independently; errors stay visible and successful rows are not duplicated on retry.
+- **Import work orders** — paste CSV using the **downloaded template** (keep the column names; numeric `type` 0–4, `priority` 0–3, UTC dates such as `2026-09-09T12:00:00Z`).
+
+## Reports and history
+
+- **Maintenance reports** — for a UTC date range (up to 366 days): total / open / overdue orders, open by priority and age bucket, mean repair time, active vs waiting vs downtime hours, preventive-maintenance compliance, repeated failures, missed response / repair targets, and costs by currency. Export CSV.
+- **Service history** — one row per order and currency, all-time unless filtered.
+- A work-order snapshot is also included in the Checklists **Readiness packet** for a call.
+
+
+
+## Permissions
+
+| Permission | Default | Grants |
+|---|---|---|
+| **Manage work orders** | Department admins | Triage, assign, change status, verify, apply/release holds, edit policy, run bulk operations. |
+| **View other members' work orders** | Department admins | See work orders raised by others in the permitted group or department. Requesters always see their own. |
+
+Spending approvals and safety-hold releases additionally require the approver to be a *different* person from the requester / completer.
+
+## Setup examples
+
+| Department type | How to use it |
+|---|---|
+| **Fire (any size)** | Preventive schedules per apparatus: annual pump test (calendar), oil change every 250 engine hours (meter), ladder inspection yearly. Enable *Create a work order on failure* on the daily apparatus checklist so a bad brake light becomes a ticket automatically. |
+| **EMS** | Ambulance mileage-based service (meter, miles), stretcher and monitor preventive inspections (equipment target), *Hazardous work* off, spending approval above $500 with the operations manager as approver. |
+| **SAR / wildland** | ATV/UTV hour-meter service, rope and hardware retirement schedules (condition trigger on inspection count), chainsaw service. |
+| **Emergency management** | Generator monthly run (calendar) and annual load test, radio cache inspection, trailer registration/inspection. |
+| **Security / facilities** | Facility type work orders for door, camera and lighting faults raised from patrol checklists; business calendar Monday–Friday with response targets; vendor charges for outsourced repairs. |
+| **Industrial ERT / plant** | *Hazardous work* and *Safety-critical* used routinely; permit, isolation and qualified-personnel fields mandatory; independent verification and safety-hold release enforced by policy. |
+
+## Technical reference
+
+| Item | Value |
+|---|---|
+| Controller | `WorkOrdersController` (partials `WorkOrderMaintenanceController`, `WorkOrderOperationsController`, `WorkOrderReportingController`) |
+| Routes | `/User/WorkOrders/{Index,New,Detail,Edit,Evidence,Recurrences,NewRecurrence,EditRecurrence,Recurrence,Operations,Policy,Bulk,ImportTemplate,Reports,History}`, `/User/ReadinessProBilling/Index` |
+| Feature flag | `Maintenance.WorkOrders` (seeded off by M0189) **and** an active Readiness Pro addon payment (`PlanAddonTypes.ReadinessPro`) — see `ReadinessAccessService.CanUseMaintenanceAsync` |
+| Module switch | `DepartmentModuleSettings.MaintenanceDisabled` |
+| Permissions | `PermissionTypes.ManageWorkOrders` (114), `PermissionTypes.ViewAllWorkOrders` (115) |
+| Workflow events | `WorkOrderCreated`, `WorkOrderStatusChanged`, `WorkOrderAssigned`, `WorkOrderRecurrenceChanged`, `WorkOrderThresholdReached`, `WorkOrderOverdue`, `WorkOrderSafetyHoldApplied`, `WorkOrderSafetyHoldReleased`, `WorkOrderDeferred`, `WorkOrderPartChanged`, `WorkOrderApprovalChanged`, `WorkOrderSlaBreached`, `WorkOrderVendorChargeChanged`, `WorkOrderPolicyChanged` |
+| Protected data | Work-order text and files are protected-data classified when the department is enrolled in [ADP](data-protection). |
diff --git a/docs/web-app/workflows.md b/docs/web-app/workflows.md
index 6200725..13f8dc5 100644
--- a/docs/web-app/workflows.md
+++ b/docs/web-app/workflows.md
@@ -1,11 +1,15 @@
---
-sidebar_position: 37
+sidebar_position: 44
title: Workflows
---
# Workflows
-The Workflows module provides a powerful event-driven automation engine that lets departments subscribe to system events, transform event data using templates, and execute configurable actions such as sending emails, SMS messages, calling APIs, posting to chat platforms, or uploading files to cloud storage. It is managed by the `WorkflowsController`.
+**Workflows** are Resgrid's automation engine: *when X happens, do Y*. Pick a trigger (a call is created, a unit goes out of service, a record is finalized, a checklist fails, a work order is overdue, a form is submitted …), add optional conditions, and chain actions — send an email or SMS, post to Slack/Teams/Discord, call a webhook or REST API, upload a file, create a call, attach a Records export. Templates use the event's data, credentials are stored encrypted, and every run is logged with retries and a health view.
+
+**Department menu → Workflows.** Start from the built-in **templates** or create a blank workflow; test with **Run now** on a past event before enabling.
+
+
**Authorization:** Department Admins only. Access is controlled via `ClaimsAuthorizationHelper.IsUserDepartmentAdmin()`.
@@ -40,6 +44,8 @@ Displays all workflows configured for the department with:
Navigate to **Department → Workflows** and click **New Workflow**.
+
+
### Workflow Fields
| Field | Required | Description |
@@ -55,6 +61,8 @@ Navigate to **Department → Workflows** and click **New Workflow**.
The edit view allows you to modify the workflow settings and manage its steps inline.
+
+
### Workflow Steps
Each workflow can have one or more **steps** that execute in sequence. Each step defines:
@@ -247,6 +255,8 @@ Each action type has specific configuration fields set via `Action Config`:
Credentials store the authentication details needed by workflow actions (SMTP passwords, API keys, webhook URLs, etc.). All credentials are **encrypted at rest** using AES-256 encryption with department-specific key derivation, ensuring each department's secrets are isolated.
+
+
### Managing Credentials
Navigate to **Department → Workflows → Credentials** to manage stored credentials.
@@ -282,6 +292,8 @@ Click **New Credential** and select the credential type. Fill in the type-specif
The **Runs** view provides a paginated audit trail of all workflow executions:
+
+
| Column | Description |
|--------|-------------|
| Timestamp | When the workflow execution started |
@@ -324,8 +336,22 @@ The **Pending** view lists all currently pending and in-progress workflow runs f
- **Cancel** — Cancel an individual pending run
- **Clear All** — Cancel all pending runs for the department (with confirmation dialog)
-## Retry Behavior
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Volunteer fire** | *Call created (High/Emergency)* → email the chief and post to the department Discord; *Certification expiring* → email the member and training officer; *Unit out of service* → SMS the apparatus officer. |
+| **Career fire** | *Record finalized (NERIS)* → upload the export to the state fire marshal SFTP nightly; *Work order overdue* → Teams channel post; *Call closed* → webhook to the city records system. |
+| **EMS** | *Call created* → API call to the billing/ePCR system with call number and address; *Checklist failed (narcotics count)* → email the medical director. |
+| **SAR** | *Call created* → SMS the mutual-aid coordinator; *Message sent (deployment poll)* → collect responses into a webhook to a spreadsheet. |
+| **Emergency management** | *Call created (Activation)* → email every ESF lead and create the EOC incident channel; *Weather alert received* → Slack post. |
+| **Security / business** | *Call closed* → email the client contact a summary (from a Records export); *Form submitted (incident form)* → create a work order via API. |
+## Technical reference
+
+`WorkflowsController`; routes `/User/Workflows/{Index,New,Edit,Runs,RunDetail,Health,Pending,Credentials,CredentialNew,CredentialEdit}`; permissions `CreateWorkflow`, `ManageWorkflowCredentials`, `ViewWorkflowRuns`; execution by the workflow worker with retry/back-off; templates sandboxed (see [Workflow variables](../reference/workflow-variables) and [Workflows API](../api/workflows)).
+
+### Retry Behavior
When a workflow step fails:
1. If `Attempt Number < Max Retry Count`, the run is re-enqueued with exponential backoff delay (`Retry Backoff Base × 2^(attempt - 1)` seconds)
@@ -335,8 +361,7 @@ When a workflow step fails:
The `Max Retry Count` has a server-side ceiling of **5** to prevent infinite retry abuse.
-## Template Sandboxing
-
+### Template Sandboxing
Scriban templates are executed in a sandboxed environment to prevent abuse:
| Protection | Limit |
@@ -348,16 +373,14 @@ Scriban templates are executed in a sandboxed environment to prevent abuse:
| Rendered content size | 256 KB |
| `import` / `include` built-ins | Disabled |
-## Dynamic Action Config Fields
-
+### Dynamic Action Config Fields
All text fields in action configuration (email Subject, To, CC, filenames, URLs, etc.) are rendered through the Scriban template engine at execution time. You can use `{{ }}` expressions in any config field:
- **Subject:** `New Call: {{ call.name }}`
- **Filename:** `report_{{ timestamp.date }}.csv`
- **Recipient:** `{{ user.email }}`
-## Security Protections
-
+### Security Protections
### SSRF Prevention
HTTP API calls, FTP, and SFTP actions enforce:
@@ -418,8 +441,7 @@ To prevent bulk messaging abuse, the number of recipients per outbound step is c
| Email To + CC | 1 (no CC) | 10 |
| SMS To | 1 | 5 |
-## Interactions with Other Modules
-
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Dispatch & Calls** | Call Added, Call Updated, Call Closed events trigger workflows |
diff --git a/docs/web-app/workshifts.md b/docs/web-app/workshifts.md
index 70ec170..921ada7 100644
--- a/docs/web-app/workshifts.md
+++ b/docs/web-app/workshifts.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 9
+sidebar_position: 18
title: Workshifts
---
@@ -7,6 +7,8 @@ title: Workshifts
Workshifts (static shifts) provide a simpler scheduling mechanism compared to the full Shifts module. They are managed by the `WorkshiftsController`.
+
+
## Overview
Workshifts define fixed time blocks with assigned units, differing from the dynamic signup-based Shifts system.
@@ -50,8 +52,17 @@ The day view shows:
Requires confirmation via a dedicated confirmation page. Full audit trail recorded.
-## Interactions with Other Modules
+## Setup examples
+
+| Department type | How to set it up |
+|---|---|
+| **Career fire** | A/B/C platoon workshifts used as the *each shift* anchor for checklist schedules and for shift-based dispatch. |
+| **EMS** | 12-hour day/night workshifts. |
+| **Security** | Site shift patterns per client. |
+
+## Technical reference
+### Interactions with Other Modules
| Module | Interaction |
|--------|-------------|
| **Shifts** | Workshift days appear on the shift calendar alongside traditional shifts |
diff --git a/docusaurus.config.js b/docusaurus.config.js
index 26e1f40..bd3d626 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -61,27 +61,116 @@ const config = {
({
navbar: {
title: 'Resgrid Docs',
+ hideOnScroll: false,
logo: {
alt: 'Resgrid Logo',
src: 'img/logo.svg',
},
items: [
{
- type: 'doc',
- docId: 'intro',
+ type: 'dropdown',
+ label: 'Get Started',
position: 'left',
- label: 'Introduction',
+ items: [
+ {type: 'doc', docId: 'intro', label: 'Introduction'},
+ {type: 'doc', docId: 'get-started/start', label: 'Quick Start'},
+ {type: 'doc', docId: 'get-started/hosted', label: 'Hosted vs Self-Hosted'},
+ {type: 'doc', docId: 'setup-guides/overview', label: 'Setup Guides by Organization'},
+ {type: 'doc', docId: 'how-tos/setup-department', label: 'Set Up a Department'},
+ {type: 'doc', docId: 'get-started/support', label: 'Support'},
+ ],
+ },
+ {
+ type: 'dropdown',
+ label: 'Web App',
+ position: 'left',
+ items: [
+ {type: 'doc', docId: 'web-app/overview', label: 'Overview'},
+ {type: 'doc', docId: 'web-app/navigation', label: 'Navigation'},
+ {type: 'doc', docId: 'web-app/dispatch-calls', label: 'Dispatch & Calls'},
+ {type: 'doc', docId: 'web-app/run-cards', label: 'Run Cards'},
+ {type: 'doc', docId: 'web-app/personnel', label: 'Personnel'},
+ {type: 'doc', docId: 'web-app/units', label: 'Units'},
+ {type: 'doc', docId: 'web-app/mapping', label: 'Mapping'},
+ {type: 'doc', docId: 'web-app/shifts', label: 'Shifts'},
+ {type: 'doc', docId: 'web-app/records/overview', label: 'Records (RMS)'},
+ {type: 'doc', docId: 'web-app/checklists', label: 'Checklists'},
+ {type: 'doc', docId: 'web-app/work-orders', label: 'Work Orders'},
+ {type: 'doc', docId: 'web-app/inventory', label: 'Inventory'},
+ {type: 'doc', docId: 'web-app/chat', label: 'Chat & Assistant'},
+ {type: 'doc', docId: 'web-app/workflows', label: 'Workflows'},
+ {type: 'doc', docId: 'web-app/reports', label: 'Reports'},
+ {type: 'doc', docId: 'web-app/security-permissions', label: 'Security & Permissions'},
+ ],
},
{
- type: 'doc',
- docId: 'intro',
+ type: 'dropdown',
+ label: 'Apps',
position: 'left',
- label: 'Quickstart',
+ items: [
+ {type: 'doc', docId: 'apps/calendar', label: 'Apps Overview'},
+ {type: 'doc', docId: 'apps/responder', label: 'Responder'},
+ {type: 'doc', docId: 'apps/unit', label: 'Unit'},
+ {type: 'doc', docId: 'apps/dispatch', label: 'Dispatch'},
+ {type: 'doc', docId: 'apps/big-board', label: 'Big Board'},
+ {type: 'doc', docId: 'apps/relay', label: 'Relay'},
+ ],
+ },
+ {
+ type: 'dropdown',
+ label: 'Administer',
+ position: 'left',
+ items: [
+ {type: 'doc', docId: 'configuration/setup', label: 'Configuration'},
+ {type: 'doc', docId: 'web-app/department-settings', label: 'Department Settings'},
+ {type: 'doc', docId: 'web-app/types-configuration', label: 'Types & Statuses'},
+ {type: 'doc', docId: 'web-app/notifications', label: 'Notifications'},
+ {type: 'doc', docId: 'enterprise/sso-overview', label: 'Enterprise SSO & SCIM'},
+ {type: 'doc', docId: 'web-app/data-protection', label: 'Advanced Data Protection'},
+ {type: 'doc', docId: 'web-app/subscription-billing', label: 'Subscription & Billing'},
+ ],
+ },
+ {
+ type: 'dropdown',
+ label: 'Self-Hosted',
+ position: 'left',
+ items: [
+ {type: 'doc', docId: 'self-hosted/quick-start', label: 'Quick Start'},
+ {type: 'doc', docId: 'self-hosted/installation', label: 'Installation'},
+ {type: 'doc', docId: 'self-hosted/multi', label: 'Kubernetes & k3s'},
+ {type: 'doc', docId: 'self-hosted/laptop', label: 'Windows Laptop / Desktop'},
+ {type: 'doc', docId: 'self-hosted/rick', label: 'Incident Command Kit (RICK)'},
+ {type: 'doc', docId: 'reference/docker', label: 'Docker Reference'},
+ {type: 'doc', docId: 'reference/sizing', label: 'Sizing Guidelines'},
+ ],
+ },
+ {
+ type: 'dropdown',
+ label: 'Developers',
+ position: 'left',
+ items: [
+ {type: 'doc', docId: 'api/information', label: 'API Overview'},
+ {type: 'doc', docId: 'api/authentication', label: 'API Authentication'},
+ {type: 'doc', docId: 'api/workflows', label: 'Workflows API'},
+ {type: 'doc', docId: 'enterprise/sso-api-reference', label: 'SSO & SCIM API'},
+ {type: 'doc', docId: 'development/prerequisites', label: 'Development Setup'},
+ {type: 'doc', docId: 'development/solution', label: 'Solution Architecture'},
+ {type: 'doc', docId: 'reference/overview', label: 'Reference'},
+ {type: 'doc', docId: 'reference/feature-flags', label: 'Feature Flags'},
+ ],
+ },
+ {
+ href: 'https://resgrid.com',
+ label: 'Resgrid.com',
+ position: 'right',
+ className: 'navbar-external-link',
},
{
href: 'https://github.com/Resgrid',
- label: 'GitHub',
position: 'right',
+ className: 'header-github-link',
+ 'aria-label': 'Resgrid on GitHub',
+ html: 'GitHub',
},
],
},
diff --git a/package-lock.json b/package-lock.json
index fecc7ba..d13e702 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -113,7 +113,6 @@
"version": "4.14.2",
"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.14.2.tgz",
"integrity": "sha512-L5zScdOmcZ6NGiVbLKTvP02UbxZ0njd5Vq9nJAmPFtjffUSOGEp11BmD2oMJ5QvARgx2XbX4KzTTNS5ECYIMWw==",
- "peer": true,
"dependencies": {
"@algolia/client-common": "4.14.2",
"@algolia/requester-common": "4.14.2",
@@ -204,7 +203,6 @@
"version": "7.19.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz",
"integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==",
- "peer": true,
"dependencies": {
"@ampproject/remapping": "^2.1.0",
"@babel/code-frame": "^7.18.6",
@@ -2670,7 +2668,6 @@
"version": "7.12.9",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz",
"integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/generator": "^7.12.5",
@@ -2987,7 +2984,6 @@
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.3.1.tgz",
"integrity": "sha512-Sm3/7OdXbQreemf9aO25keerZSbnKMpGEfmH90EyYpj1e8wMD4TuwJIb3THDSgRMWk1kYJfSRulELBy4gVgZUA==",
- "peer": true,
"dependencies": {
"@svgr/plugin-jsx": "^6.3.1",
"camelcase": "^6.2.0",
@@ -3255,7 +3251,6 @@
"version": "18.0.18",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.18.tgz",
"integrity": "sha512-6hI08umYs6NaiHFEEGioXnxJ+oEhY3eRz8VCUaudZmGdtvPviCJB8mgaMxaDWAdPSYd4eFavrPk2QIolwbLYrg==",
- "peer": true,
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -3523,7 +3518,6 @@
"version": "8.8.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
"integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -3571,7 +3565,6 @@
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -3631,7 +3624,6 @@
"version": "4.14.2",
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.14.2.tgz",
"integrity": "sha512-ngbEQonGEmf8dyEh5f+uOIihv4176dgbuOZspiuhmTTBRBuzWu3KCGHre6uHj5YyuC7pNvQGzB6ZNJyZi0z+Sg==",
- "peer": true,
"dependencies": {
"@algolia/cache-browser-local-storage": "4.14.2",
"@algolia/cache-common": "4.14.2",
@@ -4070,7 +4062,6 @@
"url": "https://tidelift.com/funding/github/npm/browserslist"
}
],
- "peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001370",
"electron-to-chromium": "^1.4.202",
@@ -4661,7 +4652,6 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
@@ -4914,7 +4904,6 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
@@ -7798,7 +7787,6 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
@@ -8460,7 +8448,6 @@
"url": "https://tidelift.com/funding/github/npm/postcss"
}
],
- "peer": true,
"dependencies": {
"nanoid": "^3.3.4",
"picocolors": "^1.0.0",
@@ -9079,7 +9066,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "peer": true,
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@@ -9253,7 +9239,6 @@
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
- "peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
@@ -9376,7 +9361,6 @@
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
- "peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
@@ -9442,7 +9426,6 @@
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz",
"integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==",
- "peer": true,
"dependencies": {
"@types/react": "*",
"prop-types": "^15.6.2"
@@ -9470,7 +9453,6 @@
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.3.tgz",
"integrity": "sha512-mzQGUvS3bM84TnbtMYR8ZjKnuPJ71IjSzR+DE6UkUqvN4czWIqEs17yLL8xkAycv4ev0AiN+IGrWu88vJs/p2w==",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.12.13",
"history": "^4.9.0",
@@ -9724,7 +9706,6 @@
"version": "7.12.9",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz",
"integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/generator": "^7.12.5",
@@ -11772,7 +11753,6 @@
"version": "5.74.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz",
"integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==",
- "peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.3",
"@types/estree": "^0.0.51",
@@ -11871,7 +11851,6 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
@@ -12002,7 +11981,6 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
@@ -12440,7 +12418,6 @@
"version": "4.14.2",
"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.14.2.tgz",
"integrity": "sha512-L5zScdOmcZ6NGiVbLKTvP02UbxZ0njd5Vq9nJAmPFtjffUSOGEp11BmD2oMJ5QvARgx2XbX4KzTTNS5ECYIMWw==",
- "peer": true,
"requires": {
"@algolia/client-common": "4.14.2",
"@algolia/requester-common": "4.14.2",
@@ -12522,7 +12499,6 @@
"version": "7.19.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz",
"integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==",
- "peer": true,
"requires": {
"@ampproject/remapping": "^2.1.0",
"@babel/code-frame": "^7.18.6",
@@ -14250,7 +14226,6 @@
"version": "7.12.9",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz",
"integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==",
- "peer": true,
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/generator": "^7.12.5",
@@ -14442,7 +14417,6 @@
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.3.1.tgz",
"integrity": "sha512-Sm3/7OdXbQreemf9aO25keerZSbnKMpGEfmH90EyYpj1e8wMD4TuwJIb3THDSgRMWk1kYJfSRulELBy4gVgZUA==",
- "peer": true,
"requires": {
"@svgr/plugin-jsx": "^6.3.1",
"camelcase": "^6.2.0",
@@ -14663,7 +14637,6 @@
"version": "18.0.18",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.18.tgz",
"integrity": "sha512-6hI08umYs6NaiHFEEGioXnxJ+oEhY3eRz8VCUaudZmGdtvPviCJB8mgaMxaDWAdPSYd4eFavrPk2QIolwbLYrg==",
- "peer": true,
"requires": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -14923,8 +14896,7 @@
"acorn": {
"version": "8.8.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
- "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
- "peer": true
+ "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w=="
},
"acorn-import-assertions": {
"version": "1.8.0",
@@ -14955,7 +14927,6 @@
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "peer": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -14999,7 +14970,6 @@
"version": "4.14.2",
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.14.2.tgz",
"integrity": "sha512-ngbEQonGEmf8dyEh5f+uOIihv4176dgbuOZspiuhmTTBRBuzWu3KCGHre6uHj5YyuC7pNvQGzB6ZNJyZi0z+Sg==",
- "peer": true,
"requires": {
"@algolia/cache-browser-local-storage": "4.14.2",
"@algolia/cache-common": "4.14.2",
@@ -15333,7 +15303,6 @@
"version": "4.21.3",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz",
"integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==",
- "peer": true,
"requires": {
"caniuse-lite": "^1.0.30001370",
"electron-to-chromium": "^1.4.202",
@@ -15752,7 +15721,6 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "peer": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
@@ -15915,7 +15883,6 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "peer": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
@@ -17992,7 +17959,6 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "peer": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
@@ -18462,7 +18428,6 @@
"version": "8.4.16",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz",
"integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==",
- "peer": true,
"requires": {
"nanoid": "^3.3.4",
"picocolors": "^1.0.0",
@@ -18844,7 +18809,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "peer": true,
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@@ -18976,7 +18940,6 @@
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
- "peer": true,
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
@@ -19068,7 +19031,6 @@
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
- "peer": true,
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
@@ -19122,7 +19084,6 @@
"version": "npm:@docusaurus/react-loadable@5.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz",
"integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==",
- "peer": true,
"requires": {
"@types/react": "*",
"prop-types": "^15.6.2"
@@ -19140,7 +19101,6 @@
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.3.tgz",
"integrity": "sha512-mzQGUvS3bM84TnbtMYR8ZjKnuPJ71IjSzR+DE6UkUqvN4czWIqEs17yLL8xkAycv4ev0AiN+IGrWu88vJs/p2w==",
- "peer": true,
"requires": {
"@babel/runtime": "^7.12.13",
"history": "^4.9.0",
@@ -19339,7 +19299,6 @@
"version": "7.12.9",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz",
"integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==",
- "peer": true,
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/generator": "^7.12.5",
@@ -20801,7 +20760,6 @@
"version": "5.74.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz",
"integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==",
- "peer": true,
"requires": {
"@types/eslint-scope": "^3.7.3",
"@types/estree": "^0.0.51",
@@ -20893,7 +20851,6 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "peer": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
@@ -20985,7 +20942,6 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "peer": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
diff --git a/src/components/HomepageFeatures/Icons.js b/src/components/HomepageFeatures/Icons.js
new file mode 100644
index 0000000..9fe6775
--- /dev/null
+++ b/src/components/HomepageFeatures/Icons.js
@@ -0,0 +1,212 @@
+import React from 'react';
+
+/*
+ * Minimal inline stroke icon set for the landing page. Every icon is drawn on a
+ * 24x24 grid and inherits `currentColor`, so it can be tinted with CSS.
+ */
+const paths = {
+ book: (
+ <>
+
+
+ >
+ ),
+ compass: (
+ <>
+
+
+ >
+ ),
+ server: (
+ <>
+
+
+
+
+ >
+ ),
+ code: (
+ <>
+
+
+ >
+ ),
+ radio: (
+ <>
+
+
+
+
+
+ >
+ ),
+ fileText: (
+ <>
+
+
+
+
+ >
+ ),
+ clipboardCheck: (
+ <>
+
+
+
+ >
+ ),
+ zap: ,
+ smartphone: (
+ <>
+
+
+ >
+ ),
+ monitor: (
+ <>
+
+
+
+ >
+ ),
+ truck: (
+ <>
+
+
+
+
+ >
+ ),
+ radioTower: (
+ <>
+
+
+
+
+
+
+
+ >
+ ),
+ headphones: (
+ <>
+
+
+
+ >
+ ),
+ calendar: (
+ <>
+
+
+
+
+ >
+ ),
+ shield: ,
+ lifeBuoy: (
+ <>
+
+
+
+
+
+
+ >
+ ),
+ sliders: (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ ),
+ terminal: (
+ <>
+
+
+ >
+ ),
+ users: (
+ <>
+
+
+
+
+ >
+ ),
+ map: (
+ <>
+
+
+
+ >
+ ),
+ message: (
+
+ ),
+ externalLink: (
+ <>
+
+
+
+ >
+ ),
+ arrowRight: (
+ <>
+
+
+ >
+ ),
+ package: (
+ <>
+
+
+
+
+ >
+ ),
+ layers: (
+ <>
+
+
+
+ >
+ ),
+ github: (
+
+ ),
+};
+
+export default function Icon({name, size = 20, className, strokeWidth = 1.75}) {
+ const body = paths[name];
+ if (!body) {
+ return null;
+ }
+ return (
+
+ );
+}
diff --git a/src/components/HomepageFeatures/index.js b/src/components/HomepageFeatures/index.js
index df45e6d..79de50f 100644
--- a/src/components/HomepageFeatures/index.js
+++ b/src/components/HomepageFeatures/index.js
@@ -1,193 +1,510 @@
import React from 'react';
import clsx from 'clsx';
import Link from '@docusaurus/Link';
+import Icon from './Icons';
import styles from './styles.module.css';
-/* ── Quick-start navigation cards ── */
-const QuickLinks = [
+/* ─────────────────────────────────────────────
+ Content
+ ───────────────────────────────────────────── */
+
+/* Four entry paths — who are you and what do you want to do? */
+const Paths = [
{
- title: 'Getting Started',
- icon: '🚀',
- description: 'Set up your Resgrid account in minutes and start dispatching.',
- link: '/get-started/start',
- linkLabel: 'Quick Start',
+ title: 'New to Resgrid?',
+ icon: 'book',
+ tone: 'blue',
+ description:
+ 'What Resgrid is, what comes in the box, who uses it and how the hosted and self-hosted editions differ.',
+ link: '/intro',
+ linkLabel: 'Read the introduction',
},
{
- title: 'Self-Hosted',
- icon: '🖥️',
- description: 'Deploy Resgrid on your own infrastructure with Docker or bare-metal.',
- link: '/get-started/hosted',
- linkLabel: 'Installation Guide',
+ title: 'Set up your department',
+ icon: 'compass',
+ tone: 'teal',
+ description:
+ 'Step-by-step recipes for fire, EMS, SAR, emergency management, security, industrial, transit and more.',
+ link: '/setup-guides/overview',
+ linkLabel: 'Pick a setup guide',
},
{
- title: 'API Reference',
- icon: '🔌',
- description: 'Integrate Resgrid into your workflow with our REST API.',
- link: '/api/information',
- linkLabel: 'Explore APIs',
+ title: 'Host it yourself',
+ icon: 'server',
+ tone: 'violet',
+ description:
+ 'Run the same code as the hosted service on Docker, Kubernetes, a laptop or the Resgrid Incident Command Kit.',
+ link: '/self-hosted/quick-start',
+ linkLabel: 'Self-hosted quick start',
},
{
- title: 'Configuration',
- icon: '⚙️',
- description: 'Fine-tune departments, roles, notifications and more.',
- link: '/configuration/setup',
- linkLabel: 'Configure',
+ title: 'Integrate & automate',
+ icon: 'code',
+ tone: 'amber',
+ description:
+ 'REST API, event-driven workflows, webhooks, SSO & SCIM provisioning and the developer setup.',
+ link: '/api/information',
+ linkLabel: 'Open the API docs',
},
];
-/* ── Core platform capabilities ── */
-const Capabilities = [
+/* Every documented module, grouped the same way the introduction groups them. */
+const FeatureAreas = [
{
- title: 'Computer Aided Dispatch',
- icon: '📡',
+ key: 'operations',
+ title: 'Operations',
+ icon: 'radio',
+ tone: 'blue',
description:
- 'Create, manage and track calls with real-time status updates, mapping and automatic notifications.',
+ 'Take the call, alert the right people, watch it unfold on the map and keep every status current.',
+ items: [
+ {label: 'Dispatch & Calls', to: '/web-app/dispatch-calls'},
+ {label: 'Run Cards & Auto-Dispatch', to: '/web-app/run-cards'},
+ {label: 'Call Check-In Timers', to: '/web-app/call-checkin-timers'},
+ {label: 'Personnel', to: '/web-app/personnel'},
+ {label: 'Units', to: '/web-app/units'},
+ {label: 'Groups & Stations', to: '/web-app/groups-stations'},
+ {label: 'Custom Statuses', to: '/web-app/custom-statuses'},
+ {label: 'Mapping', to: '/web-app/mapping'},
+ {label: 'Custom Maps', to: '/web-app/custom-maps'},
+ {label: 'Indoor Maps', to: '/web-app/indoor-maps'},
+ {label: 'Hardware GPS Tracking', to: '/web-app/unit-tracking'},
+ {label: 'Routes', to: '/web-app/routes'},
+ {label: 'Shifts', to: '/web-app/shifts'},
+ {label: 'Workshifts', to: '/web-app/workshifts'},
+ {label: 'Chat & Assistant', to: '/web-app/chat'},
+ {label: 'Messages', to: '/web-app/messages'},
+ {label: 'Voice & Audio', to: '/web-app/voice-audio'},
+ {label: 'Protocols', to: '/web-app/protocols'},
+ {label: 'Contacts', to: '/web-app/contacts'},
+ ],
},
{
- title: 'Personnel & Units',
- icon: '👥',
+ key: 'records',
+ title: 'Records & Reporting',
+ icon: 'fileText',
+ tone: 'teal',
description:
- 'Organize your team with roles, groups, stations and unit tracking across shifts.',
+ 'A full records management system — incident reports, prevention, investigations, analytics and disclosure.',
+ items: [
+ {label: 'Records (RMS) Overview', to: '/web-app/records/overview'},
+ {label: 'NERIS Incident Reports', to: '/web-app/records/incident-reports'},
+ {label: 'Record Definitions & Templates', to: '/web-app/records/definitions'},
+ {label: 'Authoring Records', to: '/web-app/records/authoring'},
+ {label: 'Dashboard & Work Queue', to: '/web-app/records/dashboard-and-queue'},
+ {label: 'Occupancies & Pre-plans', to: '/web-app/records/occupancies'},
+ {label: 'Inspections', to: '/web-app/records/inspections'},
+ {label: 'Hydrants & Water Sources', to: '/web-app/records/hydrants'},
+ {label: 'Permits & Plan Review', to: '/web-app/records/permits'},
+ {label: 'Community Risk Reduction', to: '/web-app/records/community-risk-reduction'},
+ {label: 'Investigations', to: '/web-app/records/investigations'},
+ {label: 'Analytics', to: '/web-app/records/analytics'},
+ {label: 'Quality Review', to: '/web-app/records/quality-review'},
+ {label: 'Legal Holds & Disclosures', to: '/web-app/records/legal-holds-and-disclosures'},
+ {label: 'Reports', to: '/web-app/reports'},
+ {label: 'Forms', to: '/web-app/forms'},
+ {label: 'Documents', to: '/web-app/documents'},
+ {label: 'Notes', to: '/web-app/notes'},
+ {label: 'Calendar', to: '/web-app/calendar'},
+ {label: 'Trainings', to: '/web-app/trainings'},
+ ],
},
{
- title: 'Real-Time Mapping',
- icon: '🗺️',
+ key: 'readiness',
+ title: 'Readiness & Logistics',
+ icon: 'clipboardCheck',
+ tone: 'violet',
description:
- 'Visualize calls, personnel and units on live maps with custom layers and geofencing.',
+ 'Know that apparatus, equipment, stock and people are ready before the next call comes in.',
+ items: [
+ {label: 'Checklists', to: '/web-app/checklists'},
+ {label: 'Work Orders & Maintenance', to: '/web-app/work-orders'},
+ {label: 'Inventory', to: '/web-app/inventory'},
+ {label: 'Resource Orders', to: '/web-app/resource-orders'},
+ {label: 'Department Links', to: '/web-app/department-links'},
+ {label: 'Communication Tests', to: '/web-app/communication-tests'},
+ {label: 'Weather Alerts', to: '/web-app/weather-alerts'},
+ {label: 'Templates', to: '/web-app/templates'},
+ {label: 'Distribution Lists', to: '/web-app/distribution-lists'},
+ {label: 'Dashboard', to: '/web-app/dashboard'},
+ ],
},
{
- title: 'Mobile Applications',
- icon: '📱',
+ key: 'automation',
+ title: 'Automation, Security & Integration',
+ icon: 'zap',
+ tone: 'amber',
description:
- 'Native iOS and Android apps for responders, dispatchers and unit commanders.',
+ 'Automate the routine, lock down access and connect Resgrid to the rest of your stack.',
+ items: [
+ {label: 'Workflows', to: '/web-app/workflows'},
+ {label: 'Workflow Variables', to: '/reference/workflow-variables'},
+ {label: 'Notifications', to: '/web-app/notifications'},
+ {label: 'Security & Permissions', to: '/web-app/security-permissions'},
+ {label: 'Account Security & 2FA', to: '/web-app/account-security'},
+ {label: 'Advanced Data Protection', to: '/web-app/data-protection'},
+ {label: 'Enterprise SSO & SCIM', to: '/enterprise/sso-overview'},
+ {label: 'Logs & Auditing', to: '/web-app/logs'},
+ {label: 'User Defined Fields', to: '/web-app/user-defined-fields'},
+ {label: 'Command Definitions', to: '/web-app/command-definitions'},
+ {label: 'Connect', to: '/web-app/connect'},
+ {label: 'REST API', to: '/api/information'},
+ {label: 'Feature Flags', to: '/reference/feature-flags'},
+ ],
},
+];
+
+/* The cross-platform application suite. */
+const Apps = [
{
- title: 'Shifts & Scheduling',
- icon: '📅',
- description:
- 'Build recurring shift patterns, manage sign-ups and automate staffing coverage.',
+ title: 'Responder',
+ icon: 'smartphone',
+ description: 'For individual personnel: status, calls, chat, PTT voice, shifts and location.',
+ link: '/apps/responder',
},
{
- title: 'Open Source',
- icon: '🔓',
- description:
- 'Fully open-source under the Apache 2.0 license — audit, extend and self-host with confidence.',
+ title: 'Unit',
+ icon: 'truck',
+ description: 'Shared apparatus device: unit status, crew roles, call details and GPS.',
+ link: '/apps/unit',
},
-];
-
-/* ── Explore section cards ── */
-const ExploreLinks = [
{
- title: 'Apps',
- description: 'Big Board, Dispatch, Responder, Unit and more.',
+ title: 'Dispatch',
+ icon: 'headphones',
+ description: 'Multi-panel dispatch console with live map, resources, PTT and activity log.',
link: '/apps/dispatch',
- icon: '📋',
},
{
- title: 'Modules',
- description: 'Calls, Personnel, Units, Mapping, Shifts, Reports and more.',
- link: '/category/modules',
- icon: '🧩',
+ title: 'Big Board',
+ icon: 'monitor',
+ description: 'Widget-based wall display for stations, EOCs and command vehicles.',
+ link: '/apps/big-board',
+ },
+ {
+ title: 'Relay',
+ icon: 'radioTower',
+ description: 'Listen to a scanner or audio feed, detect tones, record audio and dispatch.',
+ link: '/apps/relay',
},
+];
+
+/* Setup guides by organization type. */
+const SetupGuides = [
+ {label: 'Fire Department', to: '/setup-guides/fire-department'},
+ {label: 'EMS Agency', to: '/setup-guides/ems-agency'},
+ {label: 'Search & Rescue', to: '/setup-guides/search-and-rescue'},
+ {label: 'Emergency Management / EOC', to: '/setup-guides/emergency-management'},
+ {label: 'Incident Management Team', to: '/setup-guides/incident-management-team'},
+ {label: 'CERT & Community Response', to: '/setup-guides/cert-community-response'},
+ {label: 'Security & Facilities', to: '/setup-guides/security-and-facilities'},
+ {label: 'Industrial Emergency Response', to: '/setup-guides/industrial-emergency-response'},
+ {label: 'Delivery, Transit & Field Service', to: '/setup-guides/delivery-transit-field-service'},
+ {label: 'Multi-Agency Dispatch Center', to: '/setup-guides/multi-agency-dispatch-center'},
+];
+
+/* Administer / self-host / develop link columns. */
+const ResourceColumns = [
{
- title: 'How-To Guides',
- description: 'Step-by-step walkthroughs for common tasks.',
- link: '/category/how-tos',
- icon: '📖',
+ title: 'Administer',
+ icon: 'sliders',
+ description: 'Configure and run a department day to day.',
+ items: [
+ {label: 'Configuration Overview', to: '/configuration/setup'},
+ {label: 'Department Settings', to: '/web-app/department-settings'},
+ {label: 'Types & Configuration', to: '/web-app/types-configuration'},
+ {label: 'Personnel Roles', to: '/configuration/personnel-roles'},
+ {label: 'Stations & Groups', to: '/configuration/stations-groups'},
+ {label: 'Mapping Layers', to: '/configuration/mapping-layers'},
+ {label: 'Text Messaging', to: '/configuration/text-messaging'},
+ {label: 'Call Import', to: '/configuration/call-import'},
+ {label: 'Subscription & Billing', to: '/web-app/subscription-billing'},
+ {label: 'Help & Setup', to: '/web-app/help-setup'},
+ ],
},
{
- title: 'Development',
- description: 'Prerequisites, solution architecture and contributing.',
- link: '/development/prerequisites',
- icon: '💻',
+ title: 'Self-host',
+ icon: 'server',
+ description: 'Deploy and operate Resgrid on your own infrastructure.',
+ items: [
+ {label: 'Quick Start', to: '/self-hosted/quick-start'},
+ {label: 'Installation', to: '/self-hosted/installation'},
+ {label: 'Kubernetes & k3s', to: '/self-hosted/multi'},
+ {label: 'Windows Laptop / Desktop', to: '/self-hosted/laptop'},
+ {label: 'Incident Command Kit (RICK)', to: '/self-hosted/rick'},
+ {label: 'Docker Reference', to: '/reference/docker'},
+ {label: 'Sizing Guidelines', to: '/reference/sizing'},
+ {label: 'Auditing', to: '/reference/auditing'},
+ {label: 'Localization', to: '/reference/localization'},
+ {label: 'Hosted vs Self-Hosted', to: '/get-started/hosted'},
+ ],
+ },
+ {
+ title: 'Develop',
+ icon: 'terminal',
+ description: 'Build against the API or contribute to the codebase.',
+ items: [
+ {label: 'API Information', to: '/api/information'},
+ {label: 'API Authentication', to: '/api/authentication'},
+ {label: 'Workflows API', to: '/api/workflows'},
+ {label: 'Custom Maps API', to: '/api/custom-maps'},
+ {label: 'Calendar Export API', to: '/api/calendar-export'},
+ {label: 'SSO & SCIM API Reference', to: '/enterprise/sso-api-reference'},
+ {label: 'Prerequisites', to: '/development/prerequisites'},
+ {label: 'Getting the Code', to: '/development/getting-code'},
+ {label: 'Solution Architecture', to: '/development/solution'},
+ {label: 'Reference Overview', to: '/reference/overview'},
+ ],
},
];
-/* ── Components ── */
+/* ─────────────────────────────────────────────
+ Building blocks
+ ───────────────────────────────────────────── */
-function QuickLinkCard({title, icon, description, link, linkLabel}) {
+function SectionHeader({eyebrow, title, subtitle, action}) {
return (
-
- {icon}
-
- Dive deeper into specific areas of the platform.
-
+
+
+ Setup guides
+
Configured for how you operate
+
+ Resgrid runs fire departments, EMS agencies, SAR teams, EOCs,
+ security companies, industrial brigades and transit fleets. Each
+ guide walks through the statuses, types, roles and modules that
+ fit your kind of organization.
+
+ Dispatch, records & readiness.
+
+ One platform, documented.
+
- Open-source computer-aided dispatch & emergency management
- platform. Learn how to deploy, configure and extend Resgrid for
- your organization.
+ Everything you need to set up, operate, self-host and extend Resgrid —
+ the open-source computer-aided dispatch, records management and
+ logistics platform for first responders and the teams that dispatch
+ people and vehicles.
- Get Started
+ Get started
+
- API Reference
+ to="/web-app/overview">
+ Explore the web app