-
Notifications
You must be signed in to change notification settings - Fork 15
War Room
A deliberately basic chat that runs on your own server, for when Teams, Slack or the internet are unavailable.
This is not a Teams replacement and does not try to be. Nobody is giving up their real chat tool for it. The entire point is that it works on the day the real one cannot.
When the internet drops, the onβpremise service desk is often the last thing still running on the LAN β and it already knows every analyst, which team they are in, and what is currently on fire. So it is the natural place for people to gather.
The alternative, on the day it happens, is everybody standing up and shouting across the office, or a WhatsApp group on personal phones that half the team is not in.
| Channels | An Everyone room that always exists, plus one channel per team you belong to |
| Messages | Plain text, oldest first, with who said it and when |
| Presence | A line telling you who else is currently in the room β most of what you want to know when nothing else is working |
| Retention | A setting: anything from 7 days to forever |
Analysts only. The selfβservice portal does not get this.
No direct messages, no private channels, no threads, no @mentions, no unread badges, no file upload, no editing or deleting a message. Each is individually reasonable and collectively they are a chat platform β which is a product, not a feature.
Channels are not stored anywhere. The list is rendered from your teams table, filtered by the analyst's rows in analyst_teams.
That single constraint is what keeps this a feature rather than a product. The moment admins can create freeβform channels, the module owns channel lifecycle, membership management, whoβcanβseeβwhat, renaming, archival, and orphans when somebody leaves. Derive them from teams and every one of those already has an answer, maintained in one place.
It also means there is no admin screen to build: you manage channels by managing teams, in System β Teams, which is where an admin would look anyway.
π The Everyone channel always exists, is always first, and cannot be removed. In a real outage you want one obvious place for everybody, not six team rooms and an argument about which to use.
The war room page loads nothing from the internet β no CDN script, no web font, no remote image. A tool for the day the internet is down must not have a dependency that fails to resolve while it is down.
The same reasoning drives two other decisions:
- Retention is applied on write, not by cron. An emergency tool must not depend on somebody having configured a scheduled job. Old messages are removed as new ones arrive, in small batches so no single send stalls.
- No tokens, no certificates, no external service. Nothing in this module can expire between the day it is installed and the day it is needed.
π What rots is dependencies, not code. This is a breakβglass feature and that is fine because it has nothing that can go stale. The same could not be said of a video call, which needs a working certificate on every participant's device.
The page asks the server for anything new every three seconds, and that one request also records your presence and reports who else is there.
SSE would be the obvious modern choice and is wrong here: Apache + mod_php holds one process per open connection, so thirty analysts each keeping an EventSource open would sit on thirty workers indefinitely β during an incident, when the rest of the app is busiest. A short poll is stateless, costs one indexed lookup that usually returns nothing, and degrades gracefully.
The poll doubling as the heartbeat is why presence needs no second request.
Two tables.
warroom_messages β team_id (NULL = Everyone), analyst_id, body, created_datetime.
β οΈ The two delete rules differ on purpose.team_idCASCADEs β delete a team and its channel goes with it, which is what "a channel is a team" has to mean.analyst_idis SET NULL β delete an analyst and the conversation survives, because these messages are the record of what was said during an incident and losing half of it because somebody left the company would be the wrong trade. Those rows render as Former analyst.
warroom_presence β one row per analyst, upserted by the poll. The UNIQUE on analyst_id is what makes it an upsert; without it a longβrunning poll would add a row per request. Shape mirrors ticket_presence.
-
Channel access is checked serverβside on every read and every write, not by rendering a shorter channel list. Guessing a
team_idyou are not a member of returns 403. -
Messages are inserted with
textContent, neverinnerHTML. A chat box rendering other people's text as HTML is a storedβXSS hole that every analyst walks into during an incident. Verified with a live<img onerror>payload. - The retention setting is written through the generic settings endpoint, which refuses any key nobody owns. Ownership is declared in the module's settings manifest, so the tab that shows the setting and the capability that guards it cannot drift apart.
- Using the war room is plain module access. Only the retention decision is gated (
war_room.manage) β in an outage you do not want a permission between an analyst and the only chat that still works.
β οΈ English only at present. The other 23 locales have nolang/<locale>/war-room.php. This is safe β a missing namespace file falls back to English rather than erroring β but it is outstanding work, not a decision.- No help page yet, unlike every other module.
- No D008 Debug Tools health check yet. Worth having precisely because this is a breakβglass feature: an admin should be able to confirm it works before they need it.
- Messages are not linked to an incident record. A perβincident thread was considered and deliberately deferred β see the design rule above.
- Service layer:
includes/warroom.phpΒ· Endpoints:api/war-room/poll.php,send.php - Page:
war-room/index.phpΒ· Settings:war-room/settings/Β· Strings:lang/en/war-room.php - Mobile:
assets/css/mobile.cssLAYER 19 β see MobileβFriendly - Changelog: #1008
- Related: Teams (channels come from here) Β· Service Status (where an outage gets recorded)
FreeITSM β an open-source IT Service Management platform Β· github.com/edmozley/freeitsm Β· MIT licence
- Installation
- β° Scheduled tasks (cron jobs)
- Architecture
- AI Providers
- Internationalisation (i18n)
- Timezones & Time Handling
- Theming & Dark Mode
- β¨οΈ Command palette (βK)
- π Searching inside tickets
- π Attached documents
- MobileβFriendly
-
Security
- Layer 1 β which modules you can enter
- β³ π§© Module Access Control
- β³ π οΈ Module Access β Developer Guide
- Layer 2 β what you can administer
- β³ π Roles & Permissions
- β³ π οΈ Roles β Developer Guide
- β³ π€ Why capabilities are constants
- Layer 3 β the System module
- β³ π Admin Access Control
- Hardening
- β³ π Security review response 2026-08
- β³ π‘οΈ Security hardening 2026-08
- β³ π οΈ Security hardening 2026-08 β Developer Guide
- β³ π‘οΈ Round three β plain English
- β³ π οΈ Round three β Developer Guide
- Single Sign-On (SSO)
- ποΈ LDAP & Active Directory
- Browser Extension
- API Reference
-
π REST API β how it works
- β³ π« REST API: Tickets
- β³ π» REST API: Assets
- β³ π΄ REST API: Problems
- β³ π REST API: Changes
- β³ π REST API: Knowledge
- β³ β REST API: Tasks
- β³ ποΈ REST API: CMDB
- β³ π REST API: Contracts
- β³ ποΈ REST API: Calendar
- β³ πΏ REST API: Software
- β³ π¦ REST API: Service Status
- β³ βοΈ REST API: Morning Checks
- β³ π REST API: Forms
- β³ βοΈ REST API: Workflow
- β³ πΊοΈ REST API: Network Mapper
- β³ π§ Using the API docs page
- β³ π OpenAPI specification
- β³ β OpenAPI: kept correct
- β³ π οΈ Maintaining the catalogue
- Watchtower
-
Tickets
- β³ Mailbox Authentication
- β³ π€ Email send log
- β³ Basic IMAP mailboxes
- β³ Email rendering & images
- β³ SLA Management
- β³ WhatsApp channel
- β³ π¬ Web chat channel
- β³ π£ Slack channel
- β³ π Linking tickets
- β³ ποΈ Canned responses
- β³ βοΈ Limiting replies to particular senders
- β³ βοΈ Email signatures
- β³ π The public web address
- β³ π Raising a ticket for someone else
- β³ π Merging tickets
- β³ β Splitting tickets
- β³ β Selecting several tickets
- β³ π οΈ Snoozing tickets β Developer Guide
- β³ π₯ Collision detection
- β³ β±οΈ Time tracking
- Problem Management
- Tasks
- Assets
- Knowledge
- Change Management
- Calendar
- Morning Checks
- Reporting
- Software
- Forms
- Contracts
- Service Status
- π Notifications
- π¨ War Room
- Self-Service Portal
- LMS
- Process Mapper
- CMDB
- Network Mapper
- Workflows
- Issue trackers (Jira, Azure DevOps)
- System
-
Overview
- β³ π Progress tracker
- β³ Concepts & vocabulary
- β³ Email routing & mailboxes
- β³ Settings: global vs per-company
- β³ Users & self-service
- β³ Staff cross-company access
- β³ Worked examples
- β³ Pitfalls & gotchas
- β³ Scope: what it's for
- β³ π οΈ Developer Guide (make a module multi-company)
- β³ ποΈ Case study: CMDB (a linked graph)
- β³ π§ͺ Test harness (prove it's isolated)