Skip to content

chore(logging): strip debug console.log noise + enforce no-console lint rule - #189

Merged
patrickrb merged 1 commit into
mainfrom
cleanup/strip-console-log
May 11, 2026
Merged

chore(logging): strip debug console.log noise + enforce no-console lint rule#189
patrickrb merged 1 commit into
mainfrom
cleanup/strip-console-log

Conversation

@patrickrb

Copy link
Copy Markdown
Owner

Summary

The codebase had ~109 console.log/info/debug calls scattered through src/, mostly QRZ/LoTW sync debug scaffolding and ADIF import batch tracers. They were development breadcrumbs that never got cleaned up — none shipped useful runtime info. This PR strips them and adds an ESLint rule so they can't quietly come back.

Heavy hitters cleaned:

  • src/app/api/contacts/qrz-sync/route.ts — 28 per-contact debug traces
  • src/lib/qrz.ts — 20 HTTP request/response traces
  • src/app/api/contacts/qrz-download/route.ts — 8
  • src/app/api/install/finalize/route.ts — 7 (one converted to console.warn for real)
  • src/app/api/cron/lotw-{download,upload}/route.ts — 12 combined (auth/header debug + per-station progress)
  • src/app/api/adif/import/route.ts + src/components/AutoImportADIF.tsx — 13 batch-progress traces
  • src/app/api/lotw/download{,-contact}/route.ts — 12 credential-path traces
  • src/app/api/install/migrate-schema/route.ts — 4
  • Smaller cleanups in UserContext, search/page, dxpeditions

Kept:

  • console.error in genuine error paths (unchanged policy)
  • console.warn for real warnings (e.g. fallback paths in Propagation, install routes)
  • The two intentional console.log calls in src/lib/logger.ts (with eslint-disable-next-line — the logger module is precisely what the rest of the codebase should use going forward)

ESLint:

  • Added no-console rule with allow: ['warn', 'error'] at error level
  • Exempted scripts/**/*.{js,mjs} (CLI utilities legitimately use console)
  • Exempted tests/**/*.{ts,js} (diagnostic output in test failures)

Notes for review

Test plan

  • npm run lint — 0 errors, 52 warnings (unchanged baseline)
  • npx tsc --noEmit — clean
  • npm run build — succeeds
  • Manual: trigger a QRZ sync, watch server logs — should be quiet except on errors
  • Manual: run the install wizard end-to-end — should still succeed; warnings only on missing optional tables
  • Cron: next scheduled LoTW upload/download — successful runs are silent; errors still log

🤖 Generated with Claude Code

…nt rule

The codebase had ~109 console.log/info/debug calls scattered through src/,
mostly QRZ/LoTW sync debug scaffolding and ADIF import batch tracers. None
of them shipped useful runtime info — they were development breadcrumbs
that never got cleaned up. Strip them and add an ESLint rule so they
can't quietly come back.

Heavy hitters cleaned:
- src/app/api/contacts/qrz-sync/route.ts: 28 per-contact debug traces
- src/lib/qrz.ts: 20 HTTP request/response traces
- src/app/api/contacts/qrz-download/route.ts: 8
- src/app/api/install/finalize/route.ts: 7 (one converted to console.warn)
- src/app/api/cron/lotw-{download,upload}/route.ts: 12 combined (auth/header
  debug + per-station progress)
- src/app/api/adif/import/route.ts + src/components/AutoImportADIF.tsx:
  13 batch-progress traces
- src/app/api/lotw/download{,-contact}/route.ts: 12 credential-path traces
- src/app/api/install/migrate-schema/route.ts: 4
- Smaller cleanups in UserContext, search/page, dxpeditions, settings

Kept:
- console.error in genuine error paths (unchanged policy)
- console.warn for real warnings (e.g. fallback paths in Propagation,
  install/database, install/finalize, install/migrate-schema)
- The two intentional console.log calls in src/lib/logger.ts (with
  eslint-disable-next-line annotations, since the logger module is
  precisely what the rest of the codebase should use going forward)

ESLint:
- Added `no-console` rule with `allow: ["warn", "error"]` at error level
- Exempted scripts/**/*.{js,mjs} (CLI utilities legitimately use console)
- Exempted tests/**/*.{ts,js} (diagnostic output in test failures)

Also picks up the same one-line null-guard fix from PR #188 in
tests/database-integration.spec.ts so this branch's `tsc --noEmit` runs
clean independent of merge order.

Lint: 0 errors, 52 warnings (unchanged baseline; React hooks warnings
tracked separately for PR 3).
Build: succeeds.

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

vercel Bot commented May 11, 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 May 11, 2026 0:11am

Request Review

@patrickrb
patrickrb merged commit ac7adad into main May 11, 2026
7 checks passed
@patrickrb
patrickrb deleted the cleanup/strip-console-log branch May 11, 2026 00:18
patrickrb added a commit that referenced this pull request May 11, 2026
Starting from 52 warnings. End state: 0 errors, 0 warnings.

Mix of substantive fixes and one documented rule downgrade. Each category:

Hoisting / stale-closure (17 warnings) — wrapped fetcher functions in
useCallback and moved their declarations above the useEffects that call
them. Adds proper dep arrays. Affected pages:
- adif/page.tsx (fetchStations)
- admin/storage/page.tsx (fetchConfigs)
- admin/users/page.tsx (fetchUsers)
- awards/dxcc/page.tsx (fetchDXCCSummary)
- awards/was/page.tsx (loadStations)
- new-contact/page.tsx (fetchStations, fetchCurrentUser)
- stations/[id]/edit/page.tsx (fetchStation + 3 siblings)
- stations/new/page.tsx (fetchDxccEntities, fetchStatesProvinces)
- stations/page.tsx (fetchStations, fetchStationStats)
- stats/page.tsx (fetchStations)
- search/page.tsx (performSearch, debouncedSearch — moved above the
  useEffect that triggers it)

Memoization warning (1) — search/page.tsx `debouncedSearch` was caught by
react-hooks/preserve-manual-memoization because it depended on
`searchTimeout` state and called `setSearchTimeout`, recreating itself on
every tick. Replaced the state with a useRef so the callback's identity is
stable. This is the React-19-compiler-recommended pattern for timer state.

set-state-in-effect (33 warnings) — disabled. These all fired on the
standard "fetch data on mount → setState with the result" pattern, which
is normal React data-loading. Per-line suppression would add 33 comments
across the codebase, noisier than the warning itself. eslint.config.mjs
carries a comment explaining the decision and pointing at the path to
re-enable (adopt SWR/TanStack Query, which obviates the pattern).

Unused eslint-disable in storage.ts (1) — the comments suppressed
no-unused-vars for parameters that already had `_` prefix. Added
`argsIgnorePattern: "^_"` to the project ESLint config (standard JS/TS
convention for "intentionally unused"), then dropped the now-redundant
disable comments. Two follow-on `_mimeType` warnings disappeared too.

Also picks up the same one-line null-guard in tests/database-integration
.spec.ts as PRs #188/#189, so this branch's `tsc --noEmit` is clean
independent of merge order.

Verification:
- npm run lint → 0 errors, 0 warnings
- npx tsc --noEmit → clean
- npm run build → succeeds

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
patrickrb added a commit that referenced this pull request May 11, 2026
Two concrete issues in error response bodies:

1. Awards routes (4 files) leaked raw error.message to clients in their
   typed `{ success: false, error }` responses. A catch over a DB query
   can surface column names, constraint names, or stack frames in the
   response body — useful in dev, a soft information disclosure in prod.
   Fixed: the real error stays in console.error for server-side
   observability; the client gets 'Internal server error'.

2. LoTW download routes (2 files) returned a `debug: {...}` object
   alongside credential-error responses, exposing internal state like
   `has_username: bool`, `credential_source`, and station identifiers
   to a 400 response. Leftover from the QRZ sync debug-strip pass
   (#189) — the frontend never consumed these fields. Stripped.

The discriminated-union `{ success, data, error }` shape used by
`/api/awards/*` and `/api/cloudlog/*` stays — they're documented
contracts with multiple consumers (frontend checks `data.success`;
cloudlog is a public Cloudlog-compatible API). The `details:` field
on install/cron error responses also stays — it's admin/diagnostic
flow and not reachable by untrusted callers.

CLAUDE.md updated:
- Documents both acceptable response patterns and when each applies
- Adds explicit "don't leak raw error.message" rule with an example
- Notes the cloudlog/* external API contract
- Refreshed the Logging section now that the no-console rule (from
  #189) has landed; points new code at src/lib/logger.ts

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
patrickrb added a commit that referenced this pull request May 11, 2026
Worked through every TODO in src/, sorted by what was actually actionable:

Implemented (4 → 0):
- src/app/api/awards/was/summary/route.ts — completed_awards now reflects
  the WAS Basic award (all 50 US states confirmed → 1 else 0). The
  /awards page already displays this prominently as "Awards Earned";
  it was always showing 0 before. total_was_awards = 1 (we track the
  Basic tier only; extensible when we add 5-Band/Triple Play/etc.).
- src/app/api/awards/dxcc/summary/route.ts — same pattern. DXCC Basic
  requires 100+ confirmed entities. total_dxcc_awards = 1 (Basic tier;
  extensible when we add 150/200/.../350, by-band, by-mode).

Fixed an honest-output issue (2 → 0):
- src/app/api/cloudlog/qso/route.ts:187 and modes/route.ts:137 hardcoded
  X-RateLimit-Remaining: 999. The cloudlog index docs advertise the
  rate-limit headers as part of the public API contract, but enforcement
  isn't implemented. Sending "999" to consumers is a lie. Now reports
  Remaining == Limit (effectively "no enforcement, unlimited within the
  documented limit") with a comment pointing at the path forward.

Deleted as redundant (2 → 0):
- src/app/admin/page.tsx:132,144 — "TODO: Implement bulk LoTW
  {upload,download}" sat one line above setSyncMessage('coming soon!').
  The UI message already documents the state; the TODO was clutter.

Deleted as dead code (1 → 0):
- src/app/search/page.tsx:624 — TODO marked a `messages` array that got
  built up but never displayed. It was a leftover from a console.log
  removed in #189. The actual user feedback (table refresh with new
  sync status indicators) still works. Removed the dead build + TODO.

Kept (1 → 1):
- src/lib/storage.ts:318 — "TODO: Implement AWS S3 deletion". The AWS
  S3 storage backend isn't implemented at all (uploadToS3 also fails
  gracefully); this TODO accurately documents the unimplemented branch.
  Removing it doesn't help; implementing AWS S3 is its own future PR.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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