Changelog

What changed in EzFD, newest first. Read from the top down to the date you last updated.

There are no version numbers — EzFD is deployed by pulling the repository — so entries are dated by when they landed on master.

Each entry says what the change does for you, grouped by whether it added something, fixed something, changed existing behaviour, removed something, or was a security update. Entries that affect what you submit or see also carry a tag:

Tag Meaning
Scoring A claimed score moves. If you already submitted, check the number
Exports A Cabrillo, ADIF, summary sheet or backup file changes
Display An operator sees or does something different on screen
Setup Deployment, the admin console, or how the server is run

Untagged entries are internal — tests, refactors, CI — and safe to skip if you only run events.


2026-10-01

Added

2026-09-23

Changed

  • CI actions moved to their current major versions — actions/checkout and actions/setup-node go from v4 to v6. v4 runs on GitHub's Node 20 runtime, which is being retired, and would eventually have stopped CI from running at all. (#103)

Fixed

  • Restarting the server took a minute and a half Setup — Any browser with the logger or dashboard open held the old process up, so every deploy.sh run, every Update application and every systemctl restart ezfd sat on "Configuring systemd service" until systemd force-killed it at 90 seconds. The server now ends its live-update streams when asked to stop and restarts in a second or two; open tabs reconnect by themselves and send anything they logged in the gap. (#104) Docs: Deployment → Service management, Architecture → Real-time updates
  • Servers left on Node.js 20 through every update Setup — deploy.sh only installed Node on a fresh install, so a server set up earlier stayed on Node 20 however often it was redeployed, and Node 20 stopped receiving security fixes in April 2026. Re-running deploy.sh now moves any server below Node 24 up to it, and the admin console's Update application warns when the server is behind. CI and deploy.sh now both read the version from .nvmrc, so a server can no longer run a Node release that CI never tested. (#103) Docs: Deployment → Updating, Offline field servers → Updating later, Administration → Updating the application

Security

  • Next.js 16.3.6 Setup — Fixes two critical remote code execution advisories in 16.3.2, one of them in the image optimisation endpoint that every install serves, plus a high-severity flaw in the sharp image library it bundles. Anyone with a server reachable from the internet should update. (#103) Docs: Deployment → Updating

2026-09-16

Added

  • A dashboard view to put on a screen at the site Display — The new Overview tab is laid out to be read from across a tent rather than scanned: contacts, rate, claimed score and sections in large type, the section map, the join code, and a board showing every band in use with which modes have somebody on them, which are booked and which are free. A band somebody is actually on outranks a booking, so the gaps it shows are real gaps rather than paperwork. It is the one view without the side panel — it prints the join code itself. (#102) Docs: Operating → The Overview, Offline field servers → At the site

Fixed

  • The band breakdown silently dropped four bands on a special event Display — 60m, 30m, 17m and 12m are the bands only a special event can log, and the Bands view kept its own band list that omitted all four. A special event that worked 30m had those contacts logged, scored and counted everywhere else, and then missing from the band table with nothing on screen to say a row was gone. Contest events were never affected. (#102) Docs: Operating → The dashboard
  • The dashboard ignored band claims on Field Day and Winter Field Day — It only ever fetched them for special events, because until now nothing on a contest dashboard displayed one. The new Overview reads them, so a claimed band would have drawn as free there. No effect on any earlier release, where nothing on that screen read them. (#102)

2026-09-14

Changed

  • The map draws its own coastlines instead of fetching them Display — The land under the sections used to come from a tile service: CARTO's, then OpenStreetMap's. It now ships with the application, as a 56 KB outline of the world's coastlines built from Natural Earth's public-domain data, so the map is complete the moment the app loads and no EzFD install fetches anything from a third party. Nothing to configure, no account, no key. The background is coastlines and land only — there were never roads or towns on it at the zooms this map uses, and there are none now. (#101) Docs: Operating → The Map view, Troubleshooting → The map has no roads, towns or terrain

Fixed

  • The map was jerky to pan in Firefox Display — Panning dropped 11 of 319 frames at a worst case of 30ms, enough to feel like the map was fighting you, while the same map in a Chromium browser was smooth. The cause was Firefox repainting the raster background tiles as the map moved; with the background now drawn as shapes rather than images, the same measurement is 0 dropped frames of 517 at 6.1ms. (#101) Docs: Operating → The Map view
  • The map had no ground under it on a field server with no internet Display Setup — Sections drew correctly but floated on empty grey, because the background was fetched and there was nothing to fetch it from. The whole map now ships with the app, so a site with no uplink gets the same map as a hosted instance. Worth one look when you test yours offline before an event. (#101) Docs: Offline field servers → Verify it actually works offline
  • The sample data script only half-did what it documented — It said it spread the demo contacts across a weekend and did not, leaving that as a manual step; a screenshot taken hours later showed a rate of 0 QSO/hr over a 260-contact log. Only affects documentation screenshots. (#101)

2026-09-13

Changed

  • The map stops stacking labels it cannot draw legibly Display — At the zoom the map opens at, 54 of its 85 section labels overlapped another one, worst through the Northeast where a dozen sections are smaller than their own abbreviations, so what should have been a reference was a pile of boxes. A label is now drawn only where it fits, and the rest appear as you zoom in — nothing you can already see disappears as you go further in. No section becomes unidentifiable either, because hovering or tapping the shape itself now names it and says whether you have worked it, which it never did before: the only way to identify a section used to be hitting its 9px label. Docs: Operating → The Map view

Fixed

  • Section labels for what you still need were the hardest to read Display — Unworked labels were dark grey on a near-black box, at a contrast of 2.32:1 for 9px text, while worked labels sat at 10.48:1 — so the labels an operator is actually hunting were the ones they could not read, and only in dark mode, which is the default. Both are legible now. Docs: Operating → The Map view
  • The map could keep drawing a stale set of worked sections Display — It redrew when the number of worked sections changed, so a recompute that removed one section and added another — one operator deleting a mistaken contact while another logs a new section — left the map showing the old set with nothing to say it was out of date. It now tracks the sections themselves.
  • Worked sections on the map ran together into one amber blob Display — The border between two worked sections was amber over an amber fill, and because that fill is translucent over a basemap whose lightness inverts between themes, in dark mode — the default — the border ended up at exactly the same lightness as the fill it was meant to separate. It was not faint, it was invisible, and a run of worked sections stopped being countable. Borders are now a neutral that flips with the theme, with worked sections carrying the stronger one so the outline of what you have done is what stands out. A second cause was quieter still: each section's fill was painting over its neighbour's border, so half of every boundary on the map was washed out even in light mode. Docs: Operating → The Map view

2026-09-11

Changed

  • deploy.sh supports Debian, Ubuntu and Raspberry Pi OS, and stops on anything else Setup — It used to carry on, installing nothing and checking the prerequisites were present. The trouble was everything it does after that check: the nginx server block, the database cluster, the firewall and the service user all assume Debian's layout, and where those assumptions do not hold they fail silently rather than loudly. The clearest case is nginx — a server block written to sites-available on a distribution whose nginx.conf only includes conf.d/*.conf is never read, and nginx -t still passes, because a file nobody includes is not a syntax error. The deploy reported success and the site served nginx's welcome page. It now stops at the pre-flight, before asking you anything, and prints what a by-hand deployment involves. EzFD itself is unchanged and still runs anywhere: what is narrow is the script. (#96) Docs: Deployment → Other distributions

2026-09-10

Added

  • Run a whole event on a Pi with no internet Setup — A machine you carry to the site can be the central log for the weekend with no uplink at all. Operators join over local WiFi and everything behaves normally, because from the app's point of view nothing is offline — dupes, band coordination and the live score are all server-side and the server is at the site. The install is the same deploy.sh as any other server, run in a different order: run it at home while you still have a network, leave the domain blank so it skips Let's Encrypt, and nothing it needs afterwards is on the internet. A Pi 4 or 5 builds the app itself; below 2 GB of RAM it leans on the swap file deploy.sh adds and takes longer, which is a one-time cost paid at home. A new guide covers the parts that only bite offline — the clock, plain HTTP, giving the machine a name, power cuts, and merging the log back afterwards. (#95) Docs: Offline field servers → Set it up at home, Offline field servers → What the machine has to be
  • The admin console knows what is keeping time Setup — Server time / clock now reports a hardware RTC or a GPS receiver alongside NTP, and calls fake-hwclock out by name rather than counting it. It also offers to write the system clock back to the RTC, which is the step people forget after setting the time by hand — without it the correction lives only in RAM and the next reboot restores the old, wrong value over the top of it. (#95) Docs: Offline field servers → The clock is the part that bites, Administration → Server time
  • The app says when the server's clock cannot be trusted Display Setup — Two new warnings on the logging page, both about the thing that cannot be repaired after an event: QSOs are stamped by the server, so a wrong server clock quietly corrupts every contact's time. It now says when nothing is holding the clock — no network time, no GPS, no hardware clock — and when whatever is holding it has gone a long time unset. Those show before anyone logs anything, which is the point: a wrong clock is silent until it has already cost you contacts. Neither fires merely because NTP is off, which on an offline field server is true by design. Docs: Offline field servers → The clock is the part that bites, Troubleshooting → Nothing is holding this server's clock
  • The skew banner now names which clock is wrong Display — It could only ever say the server and your device disagreed, and deliberately would not say which was right — honest, and no help to the operator deciding what to fix. With three or more devices connected it compares what all of them report and says so outright: "9 of 11 connected devices agree". A dozen phones, most synchronised by a carrier within the last day, are collectively a better authority than a field server asking itself. With one or two devices it keeps the old both-ways wording, because that genuinely is not enough to convict either side. Docs: Troubleshooting → This server's clock is N ahead of / behind this device, API → GET /api/time

Changed

  • deploy.sh runs on more than Ubuntu and Debian Setup — It refused outright on anything else, which ruled out the old laptops and spare SBCs a club is most likely to have available for a field server. It now separates "can I install packages here" from "can this machine run EzFD": Debian derivatives such as Raspberry Pi OS, Mint and Pop!_OS are recognised through ID_LIKE, and anything else installs nothing and is told precisely which of Node, PostgreSQL, nginx, rsync and openssl it still needs. systemd is now the one hard requirement, since the service unit is what brings EzFD back after a power cut. Docs: Deployment → Requirements

Fixed

  • A field server with an RTC fitted was told its clock was broken Setup — the clock screen asked one question, whether NTP was synchronised, and told anyone who answered no to fit an RTC module. That is aimed squarely at the operator most likely to have already fitted one: an offline field server with a working RTC answers no by definition. It now says the clock is being held by the RTC and what to check instead. (#95) Docs: Offline field servers → The clock is the part that bites

2026-09-06

Added

  • The map fills sections instead of pinning them Display — Sections are drawn as their real boundaries and fill amber once worked, so what you have and where the gaps are is one glance rather than a count of label boxes. 81 of the 85 have a boundary; Ontario's four are carved by census division under RAC rather than ARRL rules and ship as one dashed outline until those are transcribed, which is honest rather than a guessed line drawn as confidently as a real one. The boundaries are a file the app ships, so they draw on a field server with no internet — only the basemap under them needs the network. (#92) Docs: Operating → The Map view
  • Ontario's four sections are drawn Display — GH, ONE, ONN and ONS were the last four without a boundary, shipping as one dashed outline over the whole province. They are now drawn from RAC's own published table, so all 85 sections fill. Nipissing District stays dashed and is labelled ONE or ONN: RAC splits it along Algonquin Park, which is not a census-division line, and a guessed line would look exactly as confident as the 84 real ones. Nothing about what a contact counts for changes — log the section the other station sent you, as before. (#94) Docs: Operating → The Map view

Fixed

  • Canada's provinces sat slightly apart from Ontario on the map Display — Drawing Ontario's sections from Statistics Canada while its neighbours came from a coarser world dataset left a strip belonging to neither along the Ottawa River and the Manitoba border. Every Canadian boundary now comes from the one source, so the borders meet exactly; provincial outlines are more accurate as a side effect. Nothing outside the map reads these shapes. (#94) Docs: Operating → The Map view

  • The menu opens over the map, not under it Display — On the dashboard's Map view, opening ☰ drew the map straight through the panel: the map stayed bright where the rest of the screen dimmed, and its zoom buttons and the OpenStreetMap credit sat on top of the menu entries. The map now takes one place in the stacking order like any other panel, so the menu, the sticky header and the log's filter dropdowns all sit above it. (#93) Docs: Operating → The menu

2026-09-05

Added

  • Merge an event that ran in two places into one log Setup — A field server at the site and the hosted instance can both hold real contacts from the same weekend. Importing that export used to make a third event, so the two logs had to be reconciled by hand. POST /api/import/event?merge_into= now reconciles them: contacts you don't have are added, duplicate flags are recomputed across the whole log — each instance computed its own against a different subset, so both were wrong for the union — and the roster and checkout history come across. It reports what it did rather than just succeeding, and it will not resolve a contact edited on both sides, undo a deletion, or change the event's settings. Running it twice is safe. (#90) Docs: Administration → Merging two instances of one event, API → POST /api/import/event
  • Rig control is a button in the header Display — It shows whether a radio is connected and what it is tuned to, and with none connected it reads Rig off and opens the panel you connect from. That panel used to be reachable only from the band list further down, which is not where anyone looks for "how do I hook up my radio". (#86) Docs: Operating → Reading the header, Rig control → Setup
  • One menu, behind ☰ Display — Everything you can do on the logger and the dashboard now lives in a slide-out menu, grouped and with a line under each entry saying what it is. The header keeps only what you read at a glance. On a phone the dashboard header was four rows of buttons before the filter bar even started; it is two now. (#84) Docs: Operating → The menu
  • Who worked what Display — A new Operators view on the dashboard, reading the log you already have: contacts, points, best hour, bands, sections, and which sections that operator was the first to reach. Sort by any column. The totals row is meant to be checked against the scoreboard, so contacts imported without an operator get their own row rather than disappearing out of the count. The per-hour average stays blank until an operator's contacts span an hour, since dividing by less than one projects a partial hour out to a whole one. (#82) Docs: Operating → The Operators view
  • A read of the log before you submit Scoring Display — The summary sheet now opens with anything worth settling first: unrecognised sections, a station that sent two different exchanges, a bonus claimed that rule 7.3 does not list for your class, and Winter Field Day objectives the log contradicts — those multiply, so a wrong tick moves the whole score. It does not check callsigns against any list: Field Day brings out operators no contest list has heard of, and flagging them would bury the findings that are real. (#81) Docs: Field Day → Before you submit
  • The GOTA station is a real station now Scoring Exports Display — Set a GOTA callsign on the event and operators can sign in there; their contacts are signed with that call, count for the entry as normal, and earn their 5 bonus points each from the log rather than from a number somebody remembers to type. There is no cap and no per-operator limit — the app used to apply a 1,000-point cap that was never in the rules. (#80, closes #23) Docs: Field Day → The GOTA station, Database → qsos

Changed

  • Text is a size larger, and the small sizes are one size Display — The body of the interface goes from 12px to 13px and headings from 14 to 15, while the four near-identical sizes below 12px — 9, 10, 10.5 and 11 — become one. Thirteen distinct sizes, nine now. Easier to read outdoors at two in the morning, and the side panel still fits a 1366x768 laptop without a scrollbar. (#87)
  • Every control on a phone is thumb-sized Display — Eleven were under 44px, some as small as 15px tall. They are all at least 44px now on a touchscreen, and unchanged on a laptop, where a logger wants the density and a mouse can hit a small button. (#87)
  • The logging screen's side panel fits without scrolling Display — On a 1366x768 laptop it ran 307px past the bottom of the screen. The score panel now shows the mode split and the score, with the full breakdown on the dashboard, and the call checkout starts folded on a contest, where claiming a band is opt-in. It stays open on a special event, and a claim you hold is shown either way. (#86) Docs: Operating → The dashboard
  • Quick Log is offered on special events only Exports — It logs a contact straight from the callsign box, which is what a special event wants and what a contest cannot use: Field Day and Winter Field Day need a class and section from every station, and logging without them filed whatever was left in the boxes. With a callsign the call-history file knew, that was a plausible exchange the station never sent, and it went to Cabrillo unchallenged. (#86) Docs: Special event stations → Quick Log
  • The rig control panel is short now Display — Status, a connect button and the three steps that start the bridge. The per-platform install walls and the troubleshooting section it used to carry are in the rig control guide, linked from the panel. (#86) Docs: Rig control → Setup
  • Every control is reachable at every screen size Display — Which controls you got used to depend on how wide your browser was, and not on purpose. The guides were reachable only on a phone; Import ADIF, both exports and the second-radio window only at tablet width and up. If you have been logging from a phone and could not find the export, that is why. (#84) Docs: Operating → The menu
  • The rate beside each operator is now their best hour Display — The dashboard's Operators panel divided an operator's contacts by however long they had been sitting there, so a good run read lower and lower as the band went quiet around it. It now shows the most they worked in any 60 minutes, which is the same figure the new Operators view prints — the two would otherwise have disagreed on the same screen. (#82) Docs: Operating → The Operators view

Fixed

  • The map draws again Display — Every tile read "API key required". The map came from CARTO's basemap CDN, which used to be open to anyone and is not any more, and the refusal arrives as a picture rather than an error — so the map still drew, still put every section in the right place, and said nothing about why it was unreadable. It now uses OpenStreetMap's own tiles, which need no account and no key, so there is nothing to configure and a field server with no credentials works the same as a hosted one. Dark mode filters the tiles rather than loading a second style. (#91) Docs: Troubleshooting → The map says "API key required"
  • The dashboard scrolls like a page on a phone Display — It was two stacked panes that each scrolled inside a screen that did not: a window onto the log, and under it a window about two lines tall onto the score, bonuses, sections worked, operators and the join code. The page scrolls now, with the view tabs pinned at the top, and only the log and the operators table keep a scroll of their own. Nothing changes on a laptop. (#88) Docs: Operating → The dashboard
  • Field Day says band coordination, not call checkout Display — The logging panel was worded for a special event whatever the event was, so a Field Day screen offered to "check out" the callsign and reported that "nobody has the call checked out" — about a callsign nobody was competing for, since every station sends the club call all weekend. It now says what is actually being coordinated on a contest: the transmitter, one signal per band and mode, held by a station rather than a person. Claiming is still optional there, and the panel no longer prints an empty list saying so. (#89) Docs: Operating → Claiming a band and mode, Quick start → Pick where you're operating
  • A busy club no longer pushes the logging panel off the screen Display — The Operators list grew with the roster: ten people signed in made it 368px tall and ran the side panel 143px past the bottom of a 900px display. It shows five at a time and scrolls inside itself now, with you on top. (#87) Docs: Operating → Who else is on
  • The CW keying button came back to the header Display — Opening the keying window is something you do at the start of a CW shift, so putting it in the menu made it look as though it had been removed. It is a button again, beside Rig, and whether it appears comes from the same rule the menu uses. (#86) Docs: Operating → Reading the header
  • The header printed \u00d7 instead of × Display — Between the sections worked and the score. A unicode escape had been written into the markup as text rather than as the character it stands for. (#86)
  • The logger kept two disagreeing copies of its own controls — One for the header and one for a phone bar, each hand-maintained, which is why the two had drifted apart. There is one list now, read by both screens, and a test fails if a second copy appears or an entry is added that nothing wires up. (#84)
  • Changelog entries citing a pull request rendered as literal text — A citation like [#80] needs a matching definition at the foot of this file to become a link; two entries were missing theirs and showed the brackets instead. The link test now checks citations as well as guide anchors. (#82)

2026-08-30

Added

  • Rig control without installing anything, on Chromium Display — Chrome and Edge can open the radio's CAT port directly, so band and mode follow the VFO with no Python, no Hamlib and no second process to keep running — and a second radio needs no second bridge. Kenwood and Elecraft commands for now, which also covers FlexRadio SmartCAT, and reading only: CW keying still uses the bridge. The bridge is unchanged and stays the default, and is still the only option on Firefox, Safari, iOS and a plain-HTTP server. (#79) Docs: Rig control → Two ways to connect

  • A LICENSE file — The licence was stated in the README and nowhere a tool looks, so GitHub reported the project as unlicensed and anyone checking before deploying it at a club found nothing. The text is unchanged and now lives in the file that governs, with CI failing if the README's copy drifts from it. (#78)

  • Every changelog entry points at its documentation — Each entry now names the guide and the section covering it, so reading about a change and reading how to use it is one click rather than a search. A test checks every link and every anchor, because a renamed section silently leaves the link resolving to the top of the page. (#76) Docs: Development → Tests

  • The documentation sidebar is grouped, and shows where you are Display — It listed all seventeen guides alphabetically with nothing to say which was yours and no mark on the one you were reading. It now follows the index's own audience grouping, highlights the current guide, and carries previous/next links so the set can be read straight through. On a phone it collapses, so a guide starts at the top of the screen rather than below a list of links. (#77) Docs: EzFD documentation → Reading these in the app

Fixed

  • The development guide described a CI that no longer existed — It said lint and shellcheck were "deliberately not gated" and listed four test suites. Both are gated and there are twelve. A contributor reading it would have expected a pull request to pass that CI now fails. (#76) Docs: Development → Tests, Development → CI
  • Links to a section whose heading has an apostrophe Display — At /docs those headings were given an id with a stray 39 in it, so every link to one opened the right page at the top rather than at the section. It worked on GitHub and failed only in the app, which is the direction nothing was watching. (#76) Docs: Development → Tests
  • Links to the documentation index Display — A guide pointing at the index sent a reader to /docs/README, which is not a page. The index is served at /docs. (#76) Docs: EzFD documentation

2026-08-28

Added

  • The station number in the logger header Display — The station you pick at sign-in is now shown beside your callsign, in the main window and the CW keying window alike. Nothing on screen used to confirm it, so a mis-click at sign-in tagged a whole shift's contacts with the wrong transmitter and the first sign of it was the Cabrillo export. (#72) Docs: Operating → Reading the header
  • The operating position picker opens on a band Display — Rather than forty-five blank buttons, it preselects one you have checked out, or failing that the band this browser was last logging on, and says which of the two it used. Clicking any other band changes it. The memory is per station and survives signing out, so the next operator at a club laptop is offered the radio's own band. (#73) Docs: Quick start → Pick where you're operating, Operating → Getting to the logger

Fixed

  • Checkouts appear in the position picker as they happen Display — The picker refreshed on a timer, so for up to fifteen seconds it could show a band as free that somebody had already taken — the exact window in which two operators pick the same one. It now listens on the same live stream the logging screen uses. Its clock was the other half: a checkout made this second was arriving and being drawn as not yet started. (#74) Docs: Operating → Getting to the logger, Architecture → Real-time updates
  • Leaving visitor mode goes home Display — ← Exit on a visitor dashboard landed on the event's operator sign-in, the one screen a visitor had deliberately not chosen — and if the browser still held a sign-in for that event, it went straight on into a logging window. (#75) Docs: Getting started → While it runs

2026-08-25

Added

  • An operating position step when you sign in Display — After your callsign you are asked where you are sitting, with every band and mode shown as free, on air, or checked out, and the option to claim it there. The logger used to open on a hard-coded 20m phone, which on a busy site is a guess — and on a special event could put you on a band somebody else had booked. (#71) Docs: Quick start → Pick where you're operating, Operating → Getting to the logger
  • Dashboard log view Display — Every contact in one table, narrowed by operator, station, band, mode, section, time or duplicates, with the columns you choose. Answers a question about the log without exporting it mid-event, and gives a club something worth putting on a screen at the site. (#66) Docs: Operating → The Log view
  • This changelog — So you can tell at a glance whether an update moves a score, changes an export or alters the screen, instead of reading commits. (#67, #68)

Changed

  • The dashboard opens on the log Display — Contacts arriving is what a dashboard is usually put up to show, and the log is the only view that answers a question about a specific QSO. The map and rate chart are one tab away. (#70) Docs: Operating → The dashboard
  • Changelog layout — Entries are grouped by what they did (added, fixed, changed, removed, security) with the subject in front, so a date's worth of work can be skimmed rather than read. Adds a Setup tag for deployment and admin-console changes. (#69)

2026-08-24

Added

  • Contest rules reference — rules-reference.md transcribes the scoring rules for both contests with their rule numbers, so a value can be checked against the source rather than against the code that uses it. (#60) Docs: Contest rules reference
  • Documentation as part of every change — AGENTS.md records which guide owns which kind of change, so a feature and its documentation land together. (#62) Docs: Development → Conventions

Fixed

Removed


2026-08-23

Added

  • Documentation inside the app Display — Served at /docs. The operator who needs the troubleshooting page on a field server with no internet is exactly the one who cannot reach GitHub. (#54) Docs: EzFD documentation → Reading these in the app
  • Band and mode coordination for contests Display — A station can claim a band and mode, and another is warned rather than silently doubling up. (#47) Docs: Operating → Who else is on
  • Operator quick start Display — For someone who has a join code and a radio and nothing to administer. (#56) Docs: Quick start

Changed

  • New events default to section MN Display — Matching the example callsign rather than an unrelated section. (#55)

Fixed


2026-08-22

Added

Fixed

Security


2026-08-21

Added

  • Special event station support Display — One callsign across many operators, with band and mode checkout enforced by a database constraint rather than by convention. Docs: Special event stations
  • Full documentation under docs/, with screenshots — Guides for operating, deployment, administration and the API, replacing a single README. (#25, #26) Docs: EzFD documentation
  • 24-hour clock pickers and a schedule timeline Display — Event start and end times are set on a UTC clock rather than typed, and the schedule is shown as a timeline. (#27, #28, #29) Docs: Special event stations → The call checkout

Earlier history is in the commit log. This file starts where the work became continuous enough to be worth summarising.