- Delete duplicate getCacheStats() function in cache.service.js
- Fix date calculation bug in lotw.service.js (was Date.now()-Date.now())
- Extract duplicate helper functions (yieldToEventLoop, getQSOKey) to sync-helpers.js
- Cache award definitions in memory to avoid repeated file I/O
- Delete unused parseDCLJSONResponse() function
- Remove unused imports (getPerformanceSummary, resetPerformanceMetrics)
- Auto-discover award JSON files instead of hardcoded list
Co-Authored-By: Claude <noreply@anthropic.com>
Added new award "DXCC SAT" that only counts satellite QSOs (QSOs with
satName field set). This adds a new "satellite_only" key to award
definitions that filters to only include satellite communications.
Award definition:
- ID: dxcc-sat
- Name: DXCC SAT
- Target: 100 DXCC entities
- Only satellite QSOs count
Co-Authored-By: Claude <noreply@anthropic.com>
Removed dld-80m-cw.json award definition. Only the main DLD award
remains, which covers all bands and modes.
Co-Authored-By: Claude <noreply@anthropic.com>
Removed the following DLD award variants:
- dld-80m.json
- dld-40m.json
- dld-cw.json
Kept dld-80m-cw.json as it represents a more specific combination.
Co-Authored-By: Claude <noreply@anthropic.com>
Adds a new "allowed_bands" key to award definitions that restricts which
bands count toward an award. If absent, all bands are allowed (default
behavior).
Applied to DXCC award to only count HF bands (160m-10m), excluding
VHF/UHF bands like 6m, 2m, and 70cm.
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed dxcc-cw.json award definition
- Renamed "DXCC Mixed Mode" to "DXCC" in dxcc.json
- Changed award ID from "dxcc-mixed" to "dxcc"
- Removed dxcc-cw.json from awards service file list
Co-Authored-By: Claude <noreply@anthropic.com>
Satellite QSOs are now grouped under a "SAT" column instead of their
frequency band. The backend now includes satName in QSO data, and the
frontend detects satellite QSOs and groups them appropriately.
Co-Authored-By: Claude <noreply@anthropic.com>
- Award detail page now shows QSO counts per (entity, band, mode) slot
- Click count to open modal with all QSOs for that slot
- Click QSO in list to view full details
- Add mode filter: "Mixed Mode" aggregates by band, specific modes show (band, mode) columns
- Backend groups by slot and collects all confirmed QSOs in qsos array
- Frontend displays clickable count links (removed blue bubbles)
Backend changes:
- calculateDOKAwardProgress(): groups by (DOK, band, mode), collects qsos array
- calculatePointsAwardProgress(): updated for all count modes with qsos array
- getAwardEntityBreakdown(): groups by (entity, band, mode) slots
Frontend changes:
- Add mode filter dropdown with "Mixed Mode" default
- Update grouping logic to handle mixed mode vs specific mode
- Replace count badges with simple clickable links
- Add QSO list modal showing all QSOs per slot
- Add Mode column to QSO list (useful in mixed mode)
Co-Authored-By: Claude <noreply@anthropic.com>
Add new award for confirming 73 unique QSO partners via AO-73 satellite.
Counts unique callsigns confirmed via LoTW with satName filter.
Co-Authored-By: Claude <noreply@anthropic.com>
Fix N+1 query, add database indexes, and implement award progress caching:
- Fix N+1 query in getUserQSOs by using SQL COUNT instead of loading all records
- Add 7 performance indexes for filter queries, sync operations, and award calculations
- Implement in-memory caching service for award progress (5-minute TTL)
- Auto-invalidate cache after LoTW/DCL syncs
Expected impact:
- 90% memory reduction for QSO listing
- 80% faster filter queries
- 95% reduction in award calculation time for cached requests
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The DLD award detail page was only showing the mode in QSO entries
because the entity breakdown didn't include the callsign field.
Changes:
- Backend: Add callsign field to DOK award entity details
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The award page was filtering QSOs by callsign/date/band/mode, which
could return the wrong QSO when multiple QSOs with the same callsign
exist on the same band/mode combination.
Changes:
- Backend: Add qsoId field to award entity breakdown responses
- Backend: Add GET /api/qsos/:id endpoint to fetch QSO by ID
- Backend: Implement getQSOById() function in lotw.service.js
- Frontend: Update openQSODetailModal() to fetch by qsoId instead of filtering
- Frontend: Include qsoId in QSO entry objects for modal click handler
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The DOK award type (used for DLD award) now supports filtering by band,
mode, and other QSO fields. This allows creating award variants like:
- DLD on specific bands (80m, 40m, etc.)
- DLD on specific modes (CW, SSB, etc.)
- DLD with combined filters (e.g., 80m + CW)
Changes:
- Modified calculateDOKAwardProgress() to apply filters before processing
- Added example awards: dld-80m, dld-40m, dld-cw, dld-80m-cw
- Filter system uses existing applyFilters() function
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add DOK-based award tracking with DCL confirmation. Counts unique
(DOK, band, mode) combinations toward the 100 DOK target.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Frontend now uses @sveltejs/adapter-static for production builds
- Backend serves both API and static files from single port (originally port 3000)
- Removed all throw statements from services to avoid Elysia prototype errors
- Fixed favicon serving and SvelteKit assets path handling
- Added ecosystem.config.js for PM2 process management
- Comprehensive deployment documentation (PM2 + HAProxy)
- Updated README with single-port architecture
- Created start.sh script for easy production start
- Fix WAS award filter to use entityId (291) instead of entity string
- Fix backend to use normalized rules.target for all award types
- Fix frontend to distinguish point-based from entity-based awards
- Fix "Needed" calculation for entity awards: target - worked
- Remove points display from non-point awards (WAS, DXCC, etc.)
- Add proper target field to all award API responses
Fixes issue where:
- WAS showed 0 states (filter didn't match "UNITED STATES OF AMERICA")
- DXCC CW showed "Needed: 0" (target not extracted from nested rules)
- Entity awards showed "Points: NaN" (incorrectly detected as point-based)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add caption field to all award definitions with detailed rule explanations
- Rename Special Stations Award to Wavelog Award
- Add configurable countMode for point-based awards:
- perBandMode: count unique (callsign, band, mode) combinations
- perStation: count each station once
- perQso: count every QSO
- Update backend to respect countMode in progress calculation
- Add target field to award API responses
- Fix "Needed" calculation for point-based awards
- Display caption on award detail pages with styled info box
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Rename 'stations' variable to 'stationList' to avoid conflict with
destructured 'stations' from rules.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implement a new award type where stations have different point values.
Each confirmed QSO with a special station adds its points to the total.
New Award: Special Stations Award
- 10-point stations: DF2ET, DJ7NT, HB9HIL, LA8AJA
- 5-point stations: DB4SCW, DG2RON, DG0TM, DO8MKR
- Target: 50 points to complete
Backend Changes
- Add support for 'points' award type
- Add calculatePointsAwardProgress() for point calculation
- Add getPointsAwardEntityBreakdown() for station details
- Track worked, confirmed, and totalPoints separately
Frontend Changes
- Awards page: Show stations and points for point awards
- Details page: Show point summary cards
- Details page: Show points badge next to station callsign
- Gold/amber gradient badge for point values
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
For VUCC awards, ensure the grid square is truncated to 4 characters
both when counting unique entities AND when displaying.
This fixes VUCC award details to show 'FN31' instead of 'FN31pr',
making it clear that we're counting unique 4-character grid squares.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add configurable displayField to award definitions to control what
is shown in award details instead of always using the entity value.
## Award Definitions Updated
- DXCC: displayField = 'entity' (shows country name)
- DXCC CW: displayField = 'entity' (shows country name)
- WAS: displayField = 'state' (shows state name)
- VUCC: displayField = 'grid' (shows grid square)
- RS-44: displayField = 'callsign' (shows callsign)
## Backend Changes
- Preserve displayField when normalizing award rules
- Use displayField to determine entity name in details
- Fallback logic for awards without displayField
- Add satName to entity data for better display
This fixes VUCC showing grid squares instead of country names.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add entityName field to backend entity breakdown
- For DXCC: Show country name (e.g., 'Germany') with ID in parentheses
- For WAS: Show state name
- For VUCC: Show grid square
- For RS-44: Show callsign
- Update sorting to use entity names for better UX
- Add subtle styling for entity IDs (gray, smaller font)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Handle 'counter' type awards that count unique callsigns
- Add debug logging to track QSO filtering progress
- Normalize counter awards to use entityType: 'callsign'
This fixes RS-44 satellite award to count unique callsigns worked
via RS-44 satellite.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
## Frontend
- Create award detail page at /awards/[id]
- Show all entities with worked/confirmed status
- Add filtering (all, worked, confirmed, unworked)
- Add sorting (name, status)
- Display summary cards (total, confirmed, worked, needed)
- Show entity details (callsign, band, mode, date)
## Backend Fixes
- Fix award progress calculation for filtered awards
- Add normalizeAwardRules to handle "filtered" type awards
- Fix satellite filter to check satName field instead of satellite
- Add case-insensitive contains matching
- Apply normalization to both progress and entity breakdown functions
This fixes the 0/0 issue for DXCC CW, WAS, VUCC, and satellite awards.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implement awards display with progress calculation based on QSO data.
## Backend
- Add awards service with progress calculation logic
- Support for DXCC, WAS, VUCC, and satellite awards
- Filter QSOs by band, mode, and other criteria
- Calculate worked/confirmed entities per award
- API endpoints:
- GET /api/awards - List all awards
- GET /api/awards/:id/progress - Get award progress
- GET /api/awards/:id/entities - Get detailed entity breakdown
## Frontend
- Create awards listing page with progress cards
- Add Awards link to navigation bar
- Display award progress bars with worked/confirmed counts
- Link to individual award detail pages (to be implemented)
- Copy award definitions to static folder
## Award Definitions
- DXCC Mixed Mode (100 entities)
- DXCC CW (100 entities, CW only)
- WAS Mixed Mode (50 states)
- VUCC Satellite (100 grids)
- RS-44 Satellite Award (100 QSOs)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>