Skip to content

chore(lint): drive ESLint warnings to zero - #190

Merged
patrickrb merged 2 commits into
mainfrom
cleanup/lint-zero
May 11, 2026
Merged

chore(lint): drive ESLint warnings to zero#190
patrickrb merged 2 commits into
mainfrom
cleanup/lint-zero

Conversation

@patrickrb

Copy link
Copy Markdown
Owner

Summary

Starting state: 52 warnings. End state: 0 errors, 0 warnings.

Mix of substantive fixes and one documented rule downgrade — not a blanket suppression sweep.

Substantive fixes (19 warnings)

Hoisting / stale-closure (17) — wrapped fetcher functions in useCallback and moved their declarations above the useEffects that call them, adding proper dep arrays. This is the canonical React fix for the stale-closure risk the React-19 compiler is warning about. Affected pages: adif, admin/storage, admin/users, awards/dxcc, awards/was, new-contact, stations/[id]/edit, stations/new, stations, stats, search.

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

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

Documented rule downgrade (33 warnings)

react-hooks/set-state-in-effect is now off. All 33 hits fired on the standard "fetch data on mount → setState with the result" pattern. Per-line suppression would add 33 comments across the codebase — noisier than the warning itself. The config carries a comment explaining the decision and the path to re-enable: adopt SWR or TanStack Query, which obviates the pattern.

This is the only rule I downgraded. react-hooks/immutability and react-hooks/preserve-manual-memoization stay on (the substantive fixes above satisfied them).

Notes for review

Test plan

  • npm run lint → 0 errors, 0 warnings
  • npx tsc --noEmit → clean
  • npm run build → succeeds
  • Manual: open /search, type a callsign, confirm debounced search still fires
  • Manual: navigate /stats and /awards/dxcc — confirm data loads (these touched useCallback wrapping)
  • Manual: edit a station at /stations/[id]/edit — confirm all dropdowns (DXCC, states, certificates) still load

🤖 Generated with Claude Code

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>
@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:39am

Request Review

…nup/lint-zero

# Conflicts:
#	eslint.config.mjs
@patrickrb
patrickrb merged commit 2f0b251 into main May 11, 2026
7 checks passed
@patrickrb
patrickrb deleted the cleanup/lint-zero branch May 11, 2026 00:43
patrickrb added a commit that referenced this pull request May 11, 2026
Builds on #194. Resolves the schema-source-of-truth problem: the dev DB
and the in-app installer were producing different schemas, and #194's
introspect ran against the dev DB (subset). This PR locks in the in-app
installer (install-database.sql + propagation-schema.sql + migrations)
as canonical and regenerates schema.ts against that.

What changed:
- Built a temporary nextlog_canonical Postgres database, applied the
  canonical install scripts in order (install-database.sql then
  propagation-schema.sql then migrations/sync_qrz_lotw_fixes.sql then
  migrations/add_name_to_lotw_credentials.sql then system_settings table
  from migrate-schema endpoint).
- drizzle-kit pull against that DB now yields 18 tables / 284 columns
  / 69 indexes / 19 foreign keys / 22 check constraints. Includes
  dxcc_entities, states_provinces, qsl_images, storage_config,
  admin_audit_log, system_settings, and the four propagation tables
  that #194 was missing.
- Regenerated baseline migration:
  drizzle/migrations/0000_baseline_canonical_schema.sql. Produced by
  drizzle-kit generate (not introspect), so it is executable as-is
  rather than wrapped in block comments. The old dev-DB baseline (which
  also contained a malformed is_valid_api_key_format check constraint)
  is removed.
- Same bytea customType helper applied to fix the two p12 cert columns
  Drizzle still introspects as unknown().
- Deleted postgres-init.sql. It was the Docker-bootstrap path that
  diverged from canonical (5 tables vs 13, plus the dev-only
  api_key_usage_logs table and is_valid_api_key_format function). Local
  dev DBs bootstrapped from it need to be wiped and reinstalled via the
  in-app installer for parity. Documented in CLAUDE.md.

Still deferred (next follow-up):
- Switching /api/install/database and /api/install/migrate-schema to
  use drizzle-kit migrate. Requires a backfill so existing prod installs
  get __drizzle_migrations seeded with "baseline applied" rather than
  re-running the baseline against an already-populated schema.
- Deleting install-database.sql, propagation-schema.sql,
  postgres-lotw-migration.sql, migrations/*.sql. Safe only after the
  runtime path is on drizzle-kit migrate.

Verification:
- npm run typecheck clean (after applying the bytea customType fix)
- npm run lint baseline unchanged (this branch is stacked on
  cleanup/migrations and predates #190's lint cleanup)
- 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
Builds on #194. Resolves the schema-source-of-truth problem: the dev DB
and the in-app installer were producing different schemas, and #194's
introspect ran against the dev DB (subset). This PR locks in the in-app
installer (install-database.sql + propagation-schema.sql + migrations)
as canonical and regenerates schema.ts against that.

What changed:
- Built a temporary nextlog_canonical Postgres database, applied the
  canonical install scripts in order (install-database.sql then
  propagation-schema.sql then migrations/sync_qrz_lotw_fixes.sql then
  migrations/add_name_to_lotw_credentials.sql then system_settings table
  from migrate-schema endpoint).
- drizzle-kit pull against that DB now yields 18 tables / 284 columns
  / 69 indexes / 19 foreign keys / 22 check constraints. Includes
  dxcc_entities, states_provinces, qsl_images, storage_config,
  admin_audit_log, system_settings, and the four propagation tables
  that #194 was missing.
- Regenerated baseline migration:
  drizzle/migrations/0000_baseline_canonical_schema.sql. Produced by
  drizzle-kit generate (not introspect), so it is executable as-is
  rather than wrapped in block comments. The old dev-DB baseline (which
  also contained a malformed is_valid_api_key_format check constraint)
  is removed.
- Same bytea customType helper applied to fix the two p12 cert columns
  Drizzle still introspects as unknown().
- Deleted postgres-init.sql. It was the Docker-bootstrap path that
  diverged from canonical (5 tables vs 13, plus the dev-only
  api_key_usage_logs table and is_valid_api_key_format function). Local
  dev DBs bootstrapped from it need to be wiped and reinstalled via the
  in-app installer for parity. Documented in CLAUDE.md.

Still deferred (next follow-up):
- Switching /api/install/database and /api/install/migrate-schema to
  use drizzle-kit migrate. Requires a backfill so existing prod installs
  get __drizzle_migrations seeded with "baseline applied" rather than
  re-running the baseline against an already-populated schema.
- Deleting install-database.sql, propagation-schema.sql,
  postgres-lotw-migration.sql, migrations/*.sql. Safe only after the
  runtime path is on drizzle-kit migrate.

Verification:
- npm run typecheck clean (after applying the bytea customType fix)
- npm run lint baseline unchanged (this branch is stacked on
  cleanup/migrations and predates #190's lint cleanup)
- npm run build succeeds

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