Skip to content

Releases: openises/TicketsCAD

v4.1.2 — what a fresh install was missing

Choose a tag to compare

@ejosterberg ejosterberg released this 26 Jul 21:19

This release fixes three things a brand-new install was missing.

They were found by doing something that should have been routine and was not: cloning the public tag onto an empty database and running the documented install steps. On its very first run, the self-check added in 4.1.1 reported that a fresh install did not satisfy its own schema. Every check before that had run against a long-lived development database where the missing objects already happened to exist.

Upgrading

git pull
php sql/run_migrations.php

Docker: git pull && docker compose up -d --build

Fixed

responder_notes was created by no migration. Two endpoints created it on the fly just before writing, so saving a unit note worked. But three other places read it — including the Notes Log report — so on an install where nobody had written a note yet, those queries hit a table that did not exist. Lazy creation at the write site is not a schema; it is a table that exists only if you happened to use the right feature first.

permission_review_dismissals had the same problem, created on demand by the RBAC code. It is also one of the tables a user lost to crash recovery — and because nothing ever created it, no repair could put it back.

user_tfa.last_used_counter (two-factor replay protection) only appeared the first time somebody enrolled in 2FA.

The schema check missed tables it only reads. It covered tables written with an explicit column list, so a table the code merely reads from could be dropped without anything noticing. Of the four tables one user actually lost, only two would have been named. Coverage is now every table the code touches — 169 tables and 1011 columns, up from 128.

Verified

On a genuine fresh install — public tag, empty database, documented steps — the self-check passes.

Then, on that same install: dropping all four of the tables that user lost and running the ordinary php sql/run_migrations.php, with no flags, names all four, repairs them, and passes the re-check. A team saves afterwards through the real save path, and the Notes Log query works before any note exists.

Full suite 3605 passing, 0 failed.

Keeping up to date

git pull gets you fixes as they land. Short walkthroughs if git is new to you:

Full changelog: CHANGELOG.md

v4.1.1 — the install checks itself

Choose a tag to compare

@ejosterberg ejosterberg released this 26 Jul 06:10

TicketsCAD can now check — and repair — its own database structure.

Every health check up to now was about files: permissions, stale code, missing libraries. None of them could see the failure that actually costs a self-hoster an evening: a database whose structure has fallen behind the code, so a screen loads perfectly and then refuses to save with a bare HTTP 400.

That happened to a beta tester last week. His laptop lost power, a few tables were damaged, he re-created them — and then the Teams screen would not save. He ran the migrations. They told him everything was up to date. It took four rounds of email to find out why.

Upgrading

git pull
php sql/run_migrations.php

Docker needs the rebuild step as well:

git pull && docker compose up -d --build

Added

php tools/check-schema.php — asks your database whether it has the columns this version writes to, and reports exactly what is missing. It changes nothing.

php tools/check-schema.php --repair

re-applies the schema migrations and re-checks in a fresh process. The migrations are idempotent and delete nothing. If you want to be certain first, php tools/backup_run.php.

A "Database schema vs this version" row on Status → File & Code Health, so drift is visible before anyone hits it.

A save that fails on a missing column now explains itself — which column, that your data is intact, and the command to fix it — instead of an unexplained HTTP 400.

See docs/TROUBLESHOOTING.md#schema-out-of-date.

Fixed

The migration runner no longer reports health it has not verified. It decided "already applied" from its own tracker table — which records whether a migration script ran, not whether the schema that script produced still exists. So if a table was dropped during crash recovery, or the database was restored from an older backup, every script still read as applied: the runner did nothing and reported everything up to date while the application was broken. Recovering required --force, and nothing anywhere suggested it.

It now asks the database, and re-applies automatically when the two disagree.

Software that confidently reports health it has not checked is worse than software that reports nothing, and that is the part of this release worth caring about.

The commit-time schema gate could not see any of the writers. It examined each SQL string in isolation, but the code builds its queries by concatenation — so the INSERT keyword and the column list never appeared in the same string, and all 89 writer statements across 53 tables were silently skipped. That is why the previous release's teams problem reached a user instead of being caught before it shipped.

The gate now reads concatenated SQL, and a generated manifest of every column the code writes to — 128 tables, 1008 columns — is checked against your live database.

Keeping up to date

TicketsCAD is developed in the open and fixes land continuously. If you clone with git, staying current is git pull — you get corrections as they happen without waiting for a tagged release. Two short walkthroughs if git is new to you:

Full changelog: CHANGELOG.md

v4.1.0 — resilience

Choose a tag to compare

@ejosterberg ejosterberg released this 26 Jul 05:14

A resilience release. Everything here came out of real installs run by real people this week — a power loss that looked like total data loss, a Docker deployment with no way to run the radio bridge, and a database table that existed in two incompatible shapes at once.

Upgrading is a git pull. If you cloned the repository, that is the whole update:

git pull
php sql/run_migrations.php

Docker installs need the rebuild step too — a pull alone does not update a running container:

git pull && docker compose up -d --build

Two schema-normalizing migrations are included. Both are idempotent, neither deletes a row, and both report anything they cannot safely decide rather than guessing. Back up first anyway — and after this release, that is one command.

Added

Automatic backups, on by default. A daily backup now runs on its own. No setup, no scheduler required — though it also works from cron or Windows Task Scheduler via tools/backup_run.php. Interval, retention and destination are configurable, and a warning appears if there has been no recent verified backup.

Backups are verified, not assumed. Every archive is reopened and checked to contain a real database dump before it counts as a success. A backup that silently produced an empty file is not a backup.

A restore tool — tools/restore.php. There previously was no supported way to restore one. It is dry-run by default, verifies the archive before touching anything, and takes a safety backup of the current database first — so restoring the wrong file is itself undoable.

restore.php --drill — prove a backup restores. Restores a backup into a throwaway database, reports how many tables and rows came back next to what is live, then drops it. Your real database is only read. Untested backups are the ones that fail when you need them; this is how you stop having untested backups.

Docker deployment for the DMR bridgeservices/dvswitch/docker/ and docs/RADIO-DMR-DOCKER.md. Runs the bridge and its AMBE vocoder together in one container, configured entirely by environment variables, with no systemd required. It refuses to start if the vocoder is not answering — a bridge with a dead vocoder otherwise connects normally and transmits silence, which is a miserable thing to debug from the receiving end.

A getting-started guide for beginners — what TicketsCAD is, how to open it, the address-versus-folder gotcha, and free links for learning the command line, Docker and git.

Fixed

A damaged database table no longer looks like an empty list. After an unclean shutdown, a single unreadable table could make a whole screen render empty — which reads as "my data is gone" when the records are safe on disk. Affected screens now say which table is damaged, that the data is likely recoverable, and where the repair steps are.

Teams could exist with no name, and on some installs the Teams screen would not load or save. The teams table had two competing definitions, so the columns an install ended up with depended on the order the setup scripts ran — and the built-in seed wrote to columns that later became read-only, which is where the four unnamed teams came from. There is now one canonical definition, and sql/run_teams_schema_normalize.php brings any install onto it.

The same hazard is now impossible. member, member_types, member_status and constituents were each defined by two different files as well. All are consolidated, and a test now fails the build if any table is ever defined twice again.

MySQL troubleshooting for two situations that each cost a user an evening: MySQL not starting or not staying running, and recovering a crashed table after a power loss. See docs/TROUBLESHOOTING.md.

Docker updates now say plainly that git pull alone does not update a running container.

Keeping up to date

TicketsCAD is developed in the open and fixes land continuously. If you clone with git, staying current is git pull — you get documentation corrections and small fixes as they happen, without waiting for a tagged release. Two short walkthroughs if you have not used git before:

Full changelog: CHANGELOG.md

TicketsCAD v4.0.6 — 'your data is not lost' instead of an endless spinner after a crash

Choose a tag to compare

@ejosterberg ejosterberg released this 25 Jul 11:14

Point release over v4.0.5. No schema change — upgrade in place.

Fixed

  • After a crash or power loss with MySQL running, the dashboard could spin forever and look like a fresh install — because MySQL hadn't finished recovering and the incident tables couldn't be read yet. The data was never lost, but nothing said so. The dashboard now detects "database reachable but its tables can't be read" and shows a calm "Your data is not lost" page — with what to check and a link to recovery steps — instead of an endless spinner. A genuine, readable empty database (a real fresh install) is unaffected.
  • Added a TROUBLESHOOTING.md section, "App looks empty / fresh install after a crash or power loss," with the safe recovery procedure (back up the data folder first, innodb_force_recovery, export, reimport) and prevention.

Full test suite: 3501 passing; schema + API-contract audits clean.

See CHANGELOG.md for full history.

TicketsCAD v4.0.5 — Traccar /newui subdirectory path note

Choose a tag to compare

@ejosterberg ejosterberg released this 25 Jul 00:51

Documentation-only release over v4.0.4.

Fixed

  • docs/TRACCAR-SETUP.md — documented that installs serving NewUI from a subdirectory (a "dual mode" setup where NewUI runs alongside the legacy app under /newui/) must include that prefix in the position-forwarder URL — e.g. https://<host>/newui/api/location.php?provider=traccar. A missing prefix is the usual cause of an HTTP 404 from Traccar's forwarder. (Thanks to a beta tester for the report.)

See CHANGELOG.md for full history.

TicketsCAD v4.0.4 — HTTPS setup guide + acknowledge-weekly, Raspberry-Pi Docker note

Choose a tag to compare

@ejosterberg ejosterberg released this 24 Jul 20:15

Point release over v4.0.3. No schema change — upgrade in place.

Added

  • HTTPS setup guide (docs/HTTPS-SETUP.md) — step-by-step recipes for putting HTTPS in front of TicketsCAD in four situations: a public domain (Caddy + automatic Let's Encrypt), no open ports (Cloudflare Tunnel), a LAN with a domain (Caddy + DNS validation), and a LAN with no domain (mkcert). Once HTTPS is on, the "not encrypted" reminder disappears on its own.
  • Acknowledge the HTTPS reminder — for installs that deliberately run on plain HTTP (e.g. a trusted private LAN), an administrator can now acknowledge the reminder. Acknowledging quiets it for 7 days, after which it returns on the next admin sign-in and must be re-acknowledged. Every acknowledgment is audit-logged — so the reminder can be quieted without an administrator ever permanently forgetting the system is unencrypted. Non-admins and the login page keep the gentle dismissible note.
  • Diagnostics now shows a "Connection encrypted (HTTPS): yes/no" row.

Fixed

  • Docker on small hosts (Raspberry Pi, low-RAM VMs): added troubleshooting for container ticketscad_db is unhealthy — the database container exiting before it becomes healthy, usually from out-of-memory (the image build and the database competing for RAM), a 32-bit OS (MariaDB 11 is 64-bit only), or a half-initialized data volume. See docs/DOCKER.md.
  • The "skip to content" accessibility link no longer lands on a warning banner — it now targets the page's real content.

Full test suite: 3488 passing; schema + API-contract audits clean.

See CHANGELOG.md for full history.

TicketsCAD v4.0.3 — map-overlay rename, upgrade orchestrator, Traccar ingest

Choose a tag to compare

@ejosterberg ejosterberg released this 24 Jul 13:42

Point release over v4.0.2. Bug fixes only — no schema change; upgrade in place.

Fixed

  • Map overlays — renaming a map markup (marker, line, circle, or polygon) no longer erases its shape. A rename now updates only the name and leaves the geometry and colour intact. (#3)
  • Location ingest (Traccar / OwnTracks / OpenGTS) — opening the ingest URL in a web browser to test it used to return {"error":"Not authenticated"}, which led people to chase a non-existent authentication problem. The endpoint now answers a browser with a clear "this URL is correct — it accepts POST only, and this is not an auth failure" message. Position forwarding itself was always POST and is unaffected.
  • Upgrade orchestrator (tools/upgrade/run.php) — the one-command legacy → v4 upgrade could fail two ways: the pre-upgrade database backup silently produced an empty file, and the schema-migration steps aborted with Cannot redeclare step(). Both are fixed — the backup falls back to the built-in PDO dump when mysqldump can't authenticate, and each migration step now runs as an isolated subprocess.

Full test suite: 3473 passing; schema + API-contract audits clean.

See CHANGELOG.md for full history.

TicketsCAD v4.0.2 — OpenCallbook call-sign lookup (amateur + GMRS)

Choose a tag to compare

@ejosterberg ejosterberg released this 22 Jul 03:51

Added

  • OpenCallbook call-sign lookup provider (opencallbook.com) that resolves both amateur radio and GMRS call signs in a single query — now the default. Configurable under Settings → FCC Lookup, alongside the local database, callook.info (amateur-only), and self-hosted FCC-ULS-API options.
  • A configurable lookup identity (User-Agent) for internet call-sign lookups: send this site's name with the software name and version (full), or the software name and version only (minimal).

Fixed

  • GMRS call-sign lookups returned "No Record Found" because the previous default (callook.info) only covers the amateur database. Installs still on that default are automatically migrated to OpenCallbook on update; deliberate offline choices (local database / self-hosted FCC-ULS-API / disabled) are left unchanged.

Changed

  • docs/DOCKER.md: expanded the Upgrading section — back up first, pin to a release tag, verify migrations ran, and how to roll back.

Upgrading: pull the new tag and run the migrations as usual (php tools/install_fresh.php, or restart the Docker container — migrations run automatically). No manual steps required; the call-sign provider is switched over for you.

TicketsCAD v4.0.1

Choose a tag to compare

@ejosterberg ejosterberg released this 20 Jul 04:07

Adds an optional Docker voice compose profile for browser push-to-talk over Zello and DMR.

docker compose --profile voice up -d

This starts the Zello + DMR WebSocket relays alongside the app (reusing the app image — nothing extra to build); the app's Apache reverse-proxies the browser's /zello-ws and /dmr-ws connections to them. Configure Zello credentials / DMR channels in Settings → Communications. See docs/DOCKER.md section 8a.

The hardware DMR/AMBE bridge to BrandMeister and Meshtastic still run on the host (they need a physical radio). No app-code changes since v4.0.0.

TicketsCAD v4.0.0

Choose a tag to compare

@ejosterberg ejosterberg released this 20 Jul 03:07

First public release of TicketsCAD NewUI v4 — a modern, keyboard-first dashboard rewrite of the legacy TicketsCAD Computer-Aided Dispatch (CAD) system for volunteer fire, ARES/RACES, CERT, EMS, and campus-security teams. It runs on the same MariaDB schema as the legacy openises/tickets, so existing installs upgrade in place.

Highlights

  • Keyboard-first dispatch dashboard (GridStack widgets, Leaflet map, command bar)
  • Full incident lifecycle: create, dispatch, status, notes, close cascade
  • Units, personnel/roster, facilities (with bed/capacity tracking), teams
  • RBAC (65 permissions), TOTP 2FA, audit logging, session security
  • Location providers (APRS, Meshtastic, OwnTracks, Traccar, DMR, browser GPS) + per-unit device tracking
  • Communications: Zello + DMR widgets, internal messaging, chat, weather alerts
  • ICS forms, scheduling, reports, external API + webhooks, Docker + shared-hosting installs

Fixed / Security in 4.0.0

  • Mass-casualty bed counts decrement each unit's destination facility independently
  • Incidents referenced by case number throughout
  • Settings API no longer returns stored secret values to the browser

See CHANGELOG.md for details. Feedback and issues welcome.