Skip to content

feat(logging): persist per-QSO transmit power (tx_pwr) end to end#244

Merged
patrickrb merged 1 commit into
mainfrom
optio/task-3ed19184-9dbe-42e2-b3b0-29b3692e6f7b
Jul 24, 2026
Merged

feat(logging): persist per-QSO transmit power (tx_pwr) end to end#244
patrickrb merged 1 commit into
mainfrom
optio/task-3ed19184-9dbe-42e2-b3b0-29b3692e6f7b

Conversation

@patrickrb

Copy link
Copy Markdown
Owner

Problem

The Power (W) field on the Log a contact form is collected and POSTed, but the value was silently discarded:

  • contacts had no power column, and Contact.create never inserted it.
  • The form sent the value under the key power, which no route or model consumed.
  • ADIF export could therefore only emit the station's single default power (stations.power_watts), never the actual power a QSO was made with, and ADIF import ignored TX_PWR entirely.

Net effect: an operator dutifully records power for each QSO and it vanishes on save — a visible form field that does nothing, plus a round-trip data loss on import/export.

Solution

Wire transmit power through as a genuine per-QSO field, using the ADIF-standard name tx_pwr (watts):

  • Schema / migration — add nullable contacts.tx_pwr numeric(10,2) (drizzle/schema.ts + generated 0006_add_contacts_tx_pwr.sql). Backwards compatible: existing rows are NULL.
  • Persist on saveContact.create now inserts tx_pwr; the log form sends the snake_case tx_pwr at the fetch() call site (component-local state stays power, which is form-internal and exempt from the snake_case rule).
  • ADIF import — reads TX_PWR so logs imported from other software keep each contact's power.
  • ADIF exportCOALESCE(c.tx_pwr, s.power_watts) so a per-QSO value wins and falls back to the station default; the search-results export (SELECT *) carries the column automatically. generateAdif already emitted tx_pwr, so nothing else changed there.
  • Edit dialog — surfaces Power (W) so a logged or imported value is visible and editable; a blank input clears the field to NULL rather than an empty string a numeric column would reject.

Testing

  • npm run typecheck — clean
  • npm run lint — clean
  • npm run build — compiled successfully
  • npx playwright test on the DB-free pure-function specs (84 tests) — all pass, including new adif-generate cases that guard tx_pwr export, a fractional QRP value, omission when absent, and a parser round-trip.
  • The migration is a single ALTER TABLE contacts ADD COLUMN tx_pwr numeric(10, 2);, generated by drizzle-kit generate and applied through the runtime migrator (/api/admin/migrate, /install) like the existing migrations. DB-integration/browser specs require a live Postgres + server and were not run in this environment.

Follow-up (out of scope)

  • Read-only contact views (dashboard / search table) could show power as a column/detail; this PR keeps display to the log form and edit dialog.
  • The QuickLogCard quick-logger has no power input; adding one there is a natural next step.

🤖 Generated with Claude Code

The "Power (W)" field on the log form was collected and POSTed as `power`,
but no column consumed it and `Contact.create` never inserted it — so an
operator's per-QSO power was silently dropped on save, and ADIF export could
only emit the station's single default power.

- schema: add nullable `contacts.tx_pwr numeric(10,2)` (ADIF TX_PWR, watts) +
  migration 0006_add_contacts_tx_pwr.
- Contact.create: persist tx_pwr.
- new-contact form: send the ADIF-standard `tx_pwr` at the wire (component
  state stays `power`, which is form-local and exempt from snake_case).
- ADIF import: read TX_PWR so imported logs keep per-QSO power.
- ADIF export: COALESCE(c.tx_pwr, s.power_watts) so a per-QSO value wins and
  falls back to the station default; the search export's SELECT * carries it
  automatically.
- EditContactDialog: expose Power (W) so a logged/imported value is visible
  and editable (blank clears to NULL, not an empty string).
- tests: guard tx_pwr export + parser round-trip in adif-generate.spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nodelog Ready Ready Preview, Comment Jul 24, 2026 10:13am

Request Review

@patrickrb
patrickrb merged commit cf160cd into main Jul 24, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant