01
Getting Started
Everything starts at /ContestSchedules — a public,
no-login browse page listing every schedule under Upcoming
& In Progress (a card grid) and Past
Schedules (a table, most recent 20). A ⚠ icon next to a past
contest means its submission deadline has passed without being
marked submitted to the sponsor yet. Click + New Contest
Schedule to create one, or click any contest name to open
its editor.
Creating or editing a schedule needs any signed-in account — not site-admin specifically; any club member can run a contest schedule. Viewing an existing schedule (or its results) never requires signing in at all, so upcoming operators can check their shift times or browse past results with no account.
02
Shift Scheduling
At /ContestDetails?id=.... The top section is the
contest window itself: Contest Name, Start/End (in your chosen UTC
offset), Grid Square, and whether shift times are shown publicly.
Lock this schedule defaults on for a brand-new
schedule (safe to share a link before you're done editing) — uncheck
it to let any other signed-in member edit it too.
Add shifts one at a time (Callsign, Name, Start/End), or paste/import a whole roster at once — the page's overlap detection, CSV/XLSX import, and printable roster all operate on the same shift list. Name/Callsign fields autocomplete from everyone who's ever checked into a real net (not the separate Operator Directory in §3 — that catalog only feeds reminder emails, not this autocomplete). A typed name that matches nothing still saves fine.
Clone makes an editable copy of a locked schedule —
handy both for "edit a copy" and for reusing last year's shift roster
as a starting point for this year's, without touching the original
or its lock state. Add to Calendar downloads a
.ics file of just the contest window for your own
calendar app.
03
Operator Directory
At /ContestOperators (admin only) — a curated list of
shift volunteers, kept deliberately separate from the app's
auto-populated net check-in cache so a deliberately-entered email
address is never at risk if that other cache is ever cleared.
Each entry: Callsign (required), Name, Email, Preferred Times, Preferred Modes, and an Opt-out checkbox that excludes them from reminder emails without deleting their record. Every field is editable directly in the table (💾 Save / ✕ Delete per row). This directory's only real connection to scheduling is reminder emails (§4) — it looks up each shift's operator here to decide who has an email on file and who's opted out.
04
Reminder Emails
Two places send the exact same reminder, using the exact same template and the exact same send history:
- A schedule's own Reminder Emails panel on ContestDetails — scoped to just that one contest.
/ContestEmailAdmin(admin only) — a Manual Send panel that can do the same for any contest, plus the shared template editor and full send history.
Both work the same way: Preview Recipients shows exactly who will get the email and who's being skipped (and why — no email on file, or opted out) before anything sends; only after previewing does Send Now appear, which asks you to confirm.
The template (subject + HTML body, edited on ContestEmailAdmin) uses
merge tokens: {{Callsign}}, {{ContestName}},
{{ShiftList}} (that operator's own shifts, already
formatted as an HTML list — wrap it in <ul>
yourself), and {{ContestLink}}. A Send a Test
Email panel sends the current template with sample data to
any address you like, without touching real send history or any
real schedule. A Default Reminder Schedule (days
before the contest) applies to any schedule that hasn't set its own
— used only by the automatic daily send, never by a manual send.
05
Entering Results
At /ContestResultsEntry?id=... — requires a signed-in
admin account. Fields: Total Contacts, Number of Operators,
Claimed Score (entered right after the contest) and,
separately, Certified Score (the sponsor's official
score, usually published weeks or months later — come back and fill
it in once it's out), Propagation Conditions, Power, Mode, a free-text
Summary, an optional Certificate upload (.pdf/.png, 10 MB max),
a Submission Deadline, and a Submitted to contest
sponsor checkbox.
If an earlier contest with the exact same name already has results, a box at the top shows that prior year's contacts/operators/score for quick comparison. Editing later is just reopening the same page and re-saving — there's no separate edit mode.
06
Public Results
At /ContestResultsView?id=... — fully public, one page
per contest. Shows the stat tiles (Contacts, Operators, a Score tile
— Claimed, with Certified underneath once it exists), Propagation/
Power/Mode, the Summary text, a Certificate link if one was uploaded
(opens inline, doesn't force a download), and a clear submission
status line: submitted, overdue-and-not-submitted, or an upcoming
deadline.
07
Cross-Contest Analysis
At /ContestAnalysis — admin only. Pick a date range
(This Year / Last Year / All Time / Custom) and get six summary
tiles (Total Contests, Operator Hours, Contacts, Score, Distinct
Operators, Submitted-to-Sponsor), five charts (Contests Per Month,
By Contest Name, By Mode, By Power, Top Operators by Hours), and a
Most Active Operators table. Operator-hours here is exact, since
every shift already records real start/end times.
Score everywhere on this page uses the certified score if the sponsor has published one, falling back to the claimed score otherwise. Export to Excel downloads the identical filtered dataset as a 3-sheet workbook (Summary, Operators, Contests By Month); Print gives a clean printed copy of the tiles/charts/table.