Replace Status column with Confirmed column that displays both the QSL service type (LoTW) and confirmation date, making it ready for future QSL services like eQSL and ClubLog.
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>
Convert entity to string before calling localeCompare to handle
numeric entity IDs (like DXCC entityId values).
Fixes TypeError on award detail pages when sorting by name.
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>
Fix the suppressURIErrorPlugin to properly handle malformed URIs from
browser extensions without throwing errors.
Changes:
- Move next() outside try block to only call for valid URLs
- Return 200 OK instead of 400 for malformed URIs
- Early return to prevent further processing of bad requests
Fixes errors appearing on every page load from browser extension requests.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add environment variable configuration to support deployment on custom
domains like https://awards.dj7nt.de
## Changes
- Add .env.example with configuration template
- Update API client to use VITE_API_BASE_URL with fallback to /api
- Update SvelteKit config to use VITE_APP_URL for CSRF trusted origins
- Update backend CORS to use configurable allowed origins
- Add ALLOWED_ORIGINS environment variable for production
- Add build and preview scripts to package.json
- Update README with production deployment guide and nginx example
## Environment Variables
- VITE_APP_URL: Application hostname (e.g., https://awards.dj7nt.de)
- VITE_API_BASE_URL: API base URL (empty = relative paths)
- ALLOWED_ORIGINS: Comma-separated CORS origins
- JWT_SECRET: Strong secret for production
- NODE_ENV: development/production
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Configure SvelteKit dev server to proxy API requests to Elysia backend,
allowing users to access the application on a single port (5173).
## Changes
- Add proxy config to vite.config.js for /api requests
- Update API client to use relative URLs (/api)
- Add convenience 'dev' script to start both servers
- Update README with single-port instructions
- Add architecture section explaining proxy setup
Benefits:
- Single port to access (5173)
- HMR still works for frontend
- No CORS issues
- Backend runs hidden on port 3001
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
## Backend
- Add Pino logging framework with timestamps and structured output
- Replace all console.error statements (49+) with proper logging levels
- Fix Drizzle ORM bug: replace invalid .get() calls with .limit(1)
- Remove unused auth routes file (already in index.js)
- Make internal functions private (remove unnecessary exports)
- Simplify code by removing excessive debug logging
## Frontend
- Add navigation bar to layout with:
- User's callsign display
- Navigation links (Dashboard, QSOs, Settings)
- Logout button with red color distinction
- Navigation only shows when user is logged in
- Dark themed design matching footer
## Documentation
- Update README.md with new project structure
- Update docs/DOCUMENTATION.md with logging and nav bar info
- Add logger.js to configuration section
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Describe project purpose and features
- Document tech stack (Bun, Elysia, SvelteKit, SQLite, Drizzle)
- Add project structure overview
- Include setup and installation instructions
- Document all API endpoints
- Include database schema for all tables
- Explain background job queue system
- Document LoTW sync logic and pagination features
- Add development commands
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add backend pagination support for /api/qsos endpoint (page, limit params)
- Return paginated results with metadata (totalCount, totalPages, hasNext, hasPrev)
- Add pagination UI to QSOs page with prev/next buttons and page numbers
- Add back button to QSO Log and Settings pages linking to main menu
- Reset to page 1 when applying filters
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Backend changes:
- Add sync_jobs table for background job tracking with Drizzle schema
- Create job queue service (job-queue.service.js) for async job processing
- Only ONE active sync job per user enforced at queue level
- Refactor LoTW service with Wavelog download logic:
- Validate for "Username/password incorrect" in response
- Check file starts with "ARRL Logbook of the World Status Report"
- Use last LoTW QSL date for incremental sync (qso_qslsince)
- Wavelog-compatible timeouts and error handling
- Add deleteQSOs function to clear all user QSOs
- Fix database path to use absolute path for consistency
- Register job processor for lotw_sync job type
API endpoints:
- POST /api/lotw/sync - Queue background sync job, returns jobId immediately
- GET /api/jobs/:jobId - Get job status with progress tracking
- GET /api/jobs/active - Get user's active job
- GET /api/jobs - Get user's recent jobs
- DELETE /api/qsos/all - Delete all QSOs for authenticated user
Frontend changes:
- Add job polling every 2 seconds during sync
- Show real-time progress indicator during sync
- Add "Clear All QSOs" button with type-to-confirm ("DELETE")
- Check for active job on mount to resume polling after refresh
- Clean up polling interval on component unmount
- Update API client with jobsAPI methods (getStatus, getActive, getRecent)
Database:
- Add sync_jobs table: id, userId, status, type, startedAt, completedAt,
result, error, createdAt
- Foreign key to users table
- Path fix: now uses src/backend/award.db consistently
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add detailed documentation covering architecture, components, code structure
- Document award system with multiple examples (DXCC, WAS, VUCC, Satellite)
- Implement LoTW sync service with ADIF parsing and long-polling
- Add QSO logbook page with filtering and statistics
- Add settings page for LoTW credentials management
- Add API endpoints for LoTW sync, QSO retrieval, and statistics
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>