Initial codebase: Go + Wails amateur radio logbook

Backend (Go 1.25 / Wails v2):
- QSO storage on SQLite (modernc) with embedded migrations (0001..0005)
- Streaming ADIF import (batch insert) + WorkedBefore per callsign and DXCC
- Callsign lookup with QRZ.com + HamQTH providers (primary/failsafe routing)
  and SQLite-backed TTL cache
- DXCC resolver from cty.dat (auto-download, longest-prefix-match)
- Multi-profile operator identities (home/portable/SOTA/contest) — every
  QSO stamps MY_* from the active profile
- CAT control via OmniRig COM on a single OS-locked goroutine, with
  bidirectional sync (freq/mode/band/split/VFOs) and Rig1/Rig2 hot-swap
- Settings store (key/value), CAT debug log at %APPDATA%/HamLog/cat.log

Frontend (React 18 + TypeScript + Tailwind v4 + shadcn-style):
- Single-row entry strip with CAT-aware band/mode/freq, RST, Start/End
  UTC, per-field locks (band/mode/freq/start/end) for backdated QSOs
- Topbar: live freq (MHz.kHz.Hz dotted), live UTC, band/mode/SPLIT badges,
  CAT pill with rig selector and clickable Azimuth pill (rotor TODO)
- Settings tree: Profiles (Log4OM-style manager), Station Information
  (edits the active profile), unified Callsign Lookup with Test buttons,
  Bands/Modes lists, CAT
- Worked-before matrix (band × mode × class) with new-DXCC highlighting
- ADIF import from menu + Maintenance > Refresh cty.dat

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-26 00:16:45 +02:00
parent 734d296300
commit 7ace2cc602
87 changed files with 15892 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
-- station_profiles: one row per operating configuration (home, portable,
-- SOTA, /MM, contest…). The user picks one as active; every QSO stamps
-- the active profile's MY_* fields. Place reserved for per-profile creds
-- (LoTW, Clublog, QRZ.com) in a later migration once those exports land.
CREATE TABLE station_profiles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL, -- "Home", "Portable", "SOTA"…
callsign TEXT NOT NULL DEFAULT '',
operator TEXT NOT NULL DEFAULT '',
my_grid TEXT NOT NULL DEFAULT '',
my_country TEXT NOT NULL DEFAULT '',
my_state TEXT NOT NULL DEFAULT '',
my_cnty TEXT NOT NULL DEFAULT '',
my_street TEXT NOT NULL DEFAULT '',
my_city TEXT NOT NULL DEFAULT '',
my_postal_code TEXT NOT NULL DEFAULT '',
my_sota_ref TEXT NOT NULL DEFAULT '',
my_pota_ref TEXT NOT NULL DEFAULT '',
my_rig TEXT NOT NULL DEFAULT '',
my_antenna TEXT NOT NULL DEFAULT '',
tx_pwr REAL, -- nullable: not always known
is_active INTEGER NOT NULL DEFAULT 0, -- 1 for the currently-selected profile
sort_order INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
);
-- Only one profile can be active at a time. Enforced lazily — the Go side
-- clears all then sets one before each switch.
CREATE INDEX idx_station_profiles_active ON station_profiles(is_active);