Commit Graph

127 Commits

Author SHA1 Message Date
aa55158347 feat: add WAE (Worked All Europe) award implementation
Implement DARC's WAE award with dual metrics tracking (countries + bandpoints).

Features:
- 54 European countries with correct DXCC entityIds from ARRL
- 8 WAE-specific entities (Shetland, Sicily, Sardinia, Crete, etc.)
- Bandpoints calculation: 1 pt/band (2 pts for 160m/80m), max 5 bands/country
- 5 award levels: WAE III (40/100), WAE II (50/150), WAE I (60/200),
  WAE TOP (70/300), WAE Trophy (all/365)
- Mode groups: CW, SSB, RTTY, FT8, Digi-Modes, Mixed-Mode
- Admin UI support for creating/editing WAE awards
- Award detail page with dual metrics display

Files:
- award-data/wae-country-list.json: WAE country definitions
- award-definitions/wae.json: Award configuration
- src/backend/services/awards.service.js: WAE calculation functions
- src/frontend: Admin and award detail views

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 18:07:52 +01:00
joerg
e4e7f3c208 Awawrdd 2026-01-23 14:18:56 +01:00
a35731f626 fix: use smart default for displayField based on entityType
When displayField is omitted in award definitions, the backend now
selects the appropriate default field based on the entityType:
- dxcc → entity (country name)
- state → state
- grid → grid (4-character)
- callsign → callsign

Previously, it used a fixed fallback order that prioritized entity
over other fields, causing grid-based awards to show DXCC names.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 14:14:05 +01:00
2ae47232cb fix: improve dark mode contrast for Points and Target badges in award detail view
Replace inline styles with CSS classes that use semi-transparent
backgrounds in dark mode instead of bright solid colors.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 14:07:23 +01:00
8b846bffbe docs: add super-admin role documentation
Add comprehensive documentation for the new super-admin role feature:

README.md:
- Update Users Table schema with isAdmin, isSuperAdmin, lastSeen fields
- Add Admin API section with all endpoints
- Add User Roles and Permissions section with security rules

docs/DOCUMENTATION.md:
- Update Users Table schema
- Add Admin System section with overview, roles, security rules
- Document all admin API endpoints
- Add audit logging details
- Include JWT token structure
- Add setup and deployment instructions

CLAUDE.md:
- Add Admin System and User Roles section
- Document admin service functions
- Include security rules
- Add JWT token claims structure
- Document frontend admin interface

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 13:53:48 +01:00
ed433902d9 feat: add super-admin role with admin impersonation support
Add a new super-admin role that can impersonate other admins. Regular
admins retain all existing permissions but cannot impersonate other
admins or promote users to super-admin.

Backend changes:
- Add isSuperAdmin field to users table with default false
- Add isSuperAdmin() check function to auth service
- Update JWT tokens to include isSuperAdmin claim
- Allow super-admins to impersonate other admins
- Add security rules for super-admin role changes

Frontend changes:
- Display "Super Admin" badge with gradient styling
- Add "Super Admin" option to role change modal
- Enable impersonate button for super-admins targeting admins
- Add "Super Admins Only" filter option

Security rules:
- Only super-admins can promote/demote super-admins
- Regular admins cannot promote users to super-admin
- Super-admins cannot demote themselves
- Cannot demote the last super-admin

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 13:32:55 +01:00
a5f0e3b96f fix: include Alaska and Hawaii DXCC entities in WAS award
WAS award was only counting states in DXCC entity 291 (United States),
which excluded Alaska (DXCC 6) and Hawaii (DXCC 110). Updated filter to
use "in" operator with all three relevant DXCC entity IDs.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 12:47:09 +01:00
b09e2b3ea2 feat: add achievements system to awards with mode filter support
Implement achievements milestone feature for awards with configurable
levels (Silver, Gold, Platinum, etc.) that track progress beyond the
base award target. Achievements display earned badges and progress bar
toward next level.

Backend:
- Add calculateAchievementProgress() helper in awards.service.js
- Include achievements field in getAllAwards() and getAwardById()
- Add achievements validation in awards-admin.service.js
- Update PUT endpoint validation schema to include achievements field

Frontend:
- Add achievements section to award detail page with gold badges
- Add reactive achievement progress calculation that respects mode filter
- Add achievements tab to admin create/edit pages with full CRUD

Award Definitions:
- Add achievements to DXCC (100/200/300/500)
- Add achievements to DLD (50/100/200/300)
- Add achievements to WAS (30/40/50)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 12:42:32 +01:00
239963ed89 feat: implement theme switching system with light and dark modes
Add complete theme switching system supporting Light Mode, Dark Mode, and
System preference (follows OS setting). Uses CSS custom properties for all
colors and Svelte store for state management with localStorage persistence.

New files:
- src/frontend/src/lib/stores/theme.js: Theme state management store
- src/frontend/src/app.css: CSS variables for light/dark themes
- src/frontend/src/lib/components/ThemeSwitcher.svelte: Theme switcher UI

Updated all components to use CSS variables instead of hardcoded colors:
- Main pages (home, awards, QSOs, settings, auth)
- Admin dashboard and award management pages
- Shared components (BackButton, ErrorDisplay, Loading)

Features:
- localStorage persistence for user preference
- System preference detection via matchMedia API
- FOUC prevention with inline script in app.html
- Smooth theme transitions across entire application

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 11:46:41 +01:00
d1e4c39ad6 feat: add last_seen tracking for users
Adds last_seen field to track when users last accessed the tool:
- Add lastSeen column to users table schema (nullable timestamp)
- Create migration to add last_seen column to existing databases
- Add updateLastSeen() function to auth.service.js
- Update auth derive middleware to update last_seen on each authenticated request (async, non-blocking)
- Add lastSeen to admin getUserStats() query for display in admin users table
- Add "Last Seen" column to admin users table in frontend

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 09:57:45 +01:00
24e0e3bfdb fix: correct target and needed calculation in award detail view
Fixes incorrect calculation of target and needed values in award detail page:
- Changed award.target to award.rules?.target (correct path in JSON structure)
- Added missing Target display card for non-points awards (DXCC, DLD, etc.)
- Added null checks to prevent broken calculations for awards without targets

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 09:33:42 +01:00
36453c8922 fix: resolve stations editor reactivity issue in award admin
Use Svelte stores with value/on:input instead of bind:value for
stations array to properly track nested property changes. Add invisible
reactivity triggers to force Svelte to track station callsign/points properties.

Also update award sorting to handle numeric prefixes in numerical order
(44 before 73) and update RS-44 satellite award category.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 09:27:08 +01:00
bd89ea0855 feat: implement award definition editor with safety validation
Add comprehensive admin-only UI for managing award definitions stored as JSON files.

Backend changes:
- Add awards-admin.service.js with file operations and validation
- Add clearAwardCache() function to invalidate in-memory cache after changes
- Add API routes: GET/POST/PUT/DELETE /api/admin/awards, POST /api/admin/awards/:id/test
- Support testing unsaved awards by passing award definition directly

Frontend changes:
- Add awards list view at /admin/awards
- Add create form at /admin/awards/create with safety checks for:
  - Impossible filter combinations (e.g., mode=CW AND mode=SSB)
  - Redundant filters and mode groups
  - Logical contradictions (e.g., satellite_only with HF-only bands)
  - Duplicate callsigns, empty mode groups, etc.
- Add edit form at /admin/awards/[id] with same validation
- Add FilterBuilder component for nested filter structures
- Add TestAwardModal with deep validation and test calculation
- Add Awards tab to admin dashboard

Safety validation includes:
- Schema validation (required fields, types, formats)
- Business rule validation (valid rule types, operators, bands, modes)
- Cross-field validation (filter contradictions, allowed_bands conflicts)
- Edge case detection (complex filters, impossible targets)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 08:16:28 +01:00
b9b6afedb8 docs: add modeGroups feature to award system specification
Document the modeGroups property for award definitions, which allows
creating convenient multi-mode filters in the award detail view.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 07:27:29 +01:00
85d171adc8 docs: document mode groups feature in CLAUDE.md and README.md
Add documentation for the new configurable mode groups feature:
- CLAUDE.md: Add modeGroups to Award Rule Options section
- CLAUDE.md: Update Award Detail View section with mode group info
- CLAUDE.md: Add to Recent Development Work (January 2026)
- README.md: Add GET /api/awards/:awardId endpoint
- README.md: Add new Mode Groups section in Features in Detail

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 07:19:49 +01:00
cd361115fe feat: add configurable mode groups to award detail view
Add per-award configurable mode groups for filtering multiple modes
together in the award detail view. Mode groups are displayed with
visual separators in the mode filter dropdown.

Backend changes:
- Add modeGroups to getAllAwards() return mapping
- Add getAwardById() function to fetch single award definition
- Add GET /api/awards/:awardId endpoint

Frontend changes:
- Fetch award definition separately to get modeGroups
- Update availableModes to include mode groups with separator
- Update filteredEntities logic to handle mode groups
- Update groupDataForTable() and applyFilter() for mode groups
- Disable separator option in dropdown

Award definitions:
- DXCC: Add Digi-Modes, Classic Digi-Modes, Mixed-Mode w/o WSJT-Modes,
  Phone-Modes groups
- DLD: Add same mode groups (adjusted for available modes)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 07:06:12 +01:00
69b33720b3 fix: prevent infinite retry loop for auto-sync users without credentials
When auto-sync is enabled but credentials (LoTW/DCL) are removed, the
scheduler would continuously try to sync every minute, logging the same
warning forever.

Now:
- Split pending users into those with and without credentials
- For users without credentials, update nextSyncAt to retry in 24 hours
- Log a warning with affected user IDs
- Only return users with valid credentials for job processing

This prevents log spam and unnecessary database queries while still
periodically checking if credentials have been restored.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 13:17:16 +01:00
648cf2c5a5 feat: implement auto-sync scheduler for LoTW and DCL
Add automatic synchronization scheduler that allows users to configure
periodic sync intervals for LoTW and DCL via the settings page.

Features:
- Users can enable/disable auto-sync per service (LoTW/DCL)
- Configurable sync intervals (1-720 hours)
- Settings page UI for managing auto-sync preferences
- Dashboard shows upcoming scheduled auto-sync jobs
- Scheduler runs every minute, triggers syncs when due
- Survives server restarts via database persistence
- Graceful shutdown support (SIGINT/SIGTERM)

Backend:
- New autoSyncSettings table with user preferences
- auto-sync.service.js for CRUD operations and scheduling logic
- scheduler.service.js for periodic tick processing
- API endpoints: GET/PUT /auto-sync/settings, GET /auto-sync/scheduler/status

Frontend:
- Auto-sync settings section in settings page
- Upcoming auto-sync section on dashboard with scheduled job cards
- Purple-themed UI for scheduled jobs with countdown animation

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 12:40:55 +01:00
cce520a00e chore: code cleanup - remove duplicates and add caching
- 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>
2026-01-22 10:22:00 +01:00
d9e0e462b9 docs: update CLAUDE.md with recent changes
Rewrote documentation to reflect current state of the application:

- Updated award list (DXCC, DXCC SAT, DLD, WAS, VUCC SAT, SAT-RS44, 73 on 73)
- Added allowed_bands and satellite_only rule options
- Added DXCC SAT award documentation
- Added QSO deletion endpoint
- Updated award detail view features (unique entity progress, satellite grouping, band sorting)
- Removed outdated DLD variant examples
- Streamlined and reorganized sections

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 09:47:11 +01:00
ebdd75e03f fix: invalidate caches after deleting QSOs
After deleting all QSOs, invalidate the stats and user caches so the
QSO page shows updated statistics instead of stale cached data.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 09:28:37 +01:00
205b311244 fix: handle foreign key constraints when deleting QSOs
The qso_changes table has a foreign key reference to qsos.id, which
was preventing QSO deletion. Now deletes related qso_changes records
first before deleting QSOs.

Also added better error logging to the DELETE endpoint.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 09:26:43 +01:00
6bc0a2f9b2 fix: return correct count from deleteQSOs function
The db.delete() returns a result object with a 'changes' property
indicating the number of affected rows, not the count directly.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 09:22:13 +01:00
8550b91255 feat: add DXCC SAT award for satellite-only QSOs
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>
2026-01-22 08:25:13 +01:00
a93d4ff85b refactor: remove DLD 80m CW award variant
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>
2026-01-22 08:22:58 +01:00
f3ee1be651 refactor: remove DLD variant awards (80m, 40m, CW)
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>
2026-01-22 08:22:09 +01:00
6c9aa1efe7 feat: add allowed_bands filter to award definitions
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>
2026-01-22 08:19:32 +01:00
14c7319c9e refactor: remove DXCC CW award and rename DXCC Mixed Mode to DXCC
- 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>
2026-01-22 08:14:33 +01:00
5792a98dca feat: sort band columns by wavelength instead of alphabetically
Band columns are now sorted by wavelength (longest to shortest):
160m, 80m, 60m, 40m, 30m, 20m, 17m, 15m, 12m, 10m, 6m, 2m, 70cm, SAT.

Unknown bands are sorted to the end.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 08:10:24 +01:00
aa25d21c6b fix: count unique entities in column sums instead of QSO counts
Column sums now correctly count unique entities (e.g., unique DXCC
countries per band) instead of counting individual entity entries or
QSOs. This matches the award progress semantics.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 08:07:38 +01:00
e14da11a93 fix: correct column sum calculation for satellite QSOs
The SAT column sum was always showing 0 because it was filtering by
e.band === 'SAT', but entities still have their original band in the
data. Now it correctly identifies satellite QSOs by checking if any
QSOs have satName.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 08:04:51 +01:00
dc34fc20b1 feat: group satellite QSOs under SAT column in award detail
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>
2026-01-22 08:03:03 +01:00
c75e55d130 feat: show unique entity progress in award summary
Summary cards now display unique entity counts (e.g., unique DXCC countries)
instead of per-band/mode slot counts. This shows actual award progress:
Total entities worked, confirmed, and needed to reach the award target.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 07:58:21 +01:00
89edd07722 feat: make award summary respect mode filter and remove mode from table headers
Summary cards (Total, Confirmed, Worked, Needed) now update based on the
selected mode filter. Also removed redundant mode display from table column
headers since the mode is already visible in the filter dropdown.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 07:52:13 +01:00
dd3beef9af feat: add award detail view with QSO count per slot and mode filter
- 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>
2026-01-22 07:34:55 +01:00
695000e35c docs: add comprehensive award system specification
Add complete specification document for the JSON-driven award
calculation system. Documents all rule types, filter operators,
QSO schema, and implementation guidance suitable for porting
to any programming language.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-21 18:50:38 +01:00
bdd8aa497d fix: admin action log and impersonation improvements
- Fix admin action log not displaying entries (use raw sqlite for self-join)
- Add global impersonation banner to all pages during impersonation
- Fix timestamp display in action log (convert Unix seconds to milliseconds)
- Add loginWithToken method to auth store for direct token authentication
- Fix /api/auth/me to include impersonatedBy field from JWT
- Remove duplicate impersonation code from admin page

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-21 18:26:20 +01:00
7c209e3270 fix: correct last-sync date and logout redirect issues
- Fix admin users last-sync showing 1970 instead of actual sync date
  - Changed from MAX(qsos.createdAt) to MAX(syncJobs.completedAt)
  - Added timestamp conversion (seconds to milliseconds) for proper Date serialization
- Fix logout redirect not working from admin dashboard
  - Changed from goto() to window.location.href for hard redirect
  - Ensures proper navigation after auth state changes

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-21 17:49:27 +01:00
6d3291e331 chore: consolidate env templates and remove Docker docs from master
- Merge .env.production.template into .env.example
- Remove Docker Deployment section from CLAUDE.md (now on docker branch)
- Update README.md to reference .env.example
- Update environment variable documentation

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-21 14:08:27 +01:00
c0a471f7c2 chore: remove Docker files from master branch
Master is now for standalone/run-on-metal deployment only.
Docker-related files moved to dedicated 'docker' branch.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-21 14:05:39 +01:00
ae4e60f966 chore: remove old phase documentation and development notes
Remove outdated phase markdown files and optimize.md that are no longer relevant to the active codebase.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-21 14:03:25 +01:00
dbca64a03c fix: use correct user id field for admin impersonate and role change modals
The modals were using selectedUser.userId but the user object has the field
named id, not userId. This caused undefined to be passed to the backend,
resulting in "Invalid user ID" error when trying to impersonate or change
user roles.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-21 13:57:11 +01:00
c56226e05b feat: add 73 on 73 satellite award
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>
2026-01-21 13:48:44 +01:00
8f8abfc651 refactor: remove redundant role field, keep only is_admin
- Remove role column from users schema (migration 0003)
- Update auth and admin services to use is_admin only
- Remove role from JWT token payloads
- Update admin CLI to use is_admin field
- Update frontend admin page to use isAdmin boolean
- Fix security: remove console.log dumping credentials in settings

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-21 11:41:41 +01:00
fc44fef91a feat: add migration for admin actions and role fields
Adds new tables and columns for admin functionality:

- Create admin_actions table for audit logging
- Create qso_changes table for sync job rollback support
- Add role column to users (default: 'user')
- Add is_admin column to users (default: false)

No data loss - uses ALTER TABLE with safe defaults.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-21 10:37:05 +01:00
7026f2bca7 perf: optimize LoTW and DCL sync with batch operations
Fixes frontend freeze during large sync operations (8000+ QSOs).

Root cause: Sequential processing with individual database operations
(~24,000 queries for 8000 QSOs) blocked the event loop, preventing
polling requests from being processed.

Changes:
- Process QSOs in batches of 100
- Single SELECT query per batch for duplicate detection
- Batch INSERTs for new QSOs and change tracking
- Add yield points (setImmediate) after each batch to allow
  event loop processing of polling requests

Performance: ~98% reduction in database operations
Before: 8000 QSOs × 3 queries = ~24,000 sequential operations
After: 80 batches × ~4 operations = ~320 operations

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-21 10:28:24 +01:00
e88537754f feat: implement comprehensive admin functionality
- Add admin role system with role and isAdmin fields to users table
- Create admin_actions audit log table for tracking all admin operations
- Implement admin CLI tool for user management (create, promote, demote, list, check)
- Add admin authentication with role-based access control
- Create admin service layer with system statistics and user management
- Implement user impersonation system with proper security checks
- Add admin API endpoints for user management and system statistics
- Create admin dashboard UI with overview, users, and action logs
- Fix admin stats endpoint and user deletion with proper foreign key handling
- Add admin link to navigation bar for admin users

Database:
- Add role and isAdmin columns to users table
- Create admin_actions table for audit trail
- Migration script: add-admin-functionality.js

CLI:
- src/backend/scripts/admin-cli.js - Admin user management tool

Backend:
- src/backend/services/admin.service.js - Admin business logic
- Updated auth.service.js with admin helper functions
- Enhanced index.js with admin routes and middleware
- Export sqlite connection from config for raw SQL operations

Frontend:
- src/frontend/src/routes/admin/+page.svelte - Admin dashboard
- Updated api.js with adminAPI functions
- Added Admin link to navigation bar

Security:
- Admin-only endpoints with role verification
- Audit logging for all admin actions
- Impersonation with 1-hour token expiration
- Foreign key constraint handling for user deletion
- Cannot delete self or other admins
- Last admin protection
2026-01-21 09:43:56 +01:00
fe305310b9 feat: implement Phase 2 - caching, performance monitoring, and health dashboard
Phase 2.1: Basic Caching Layer
- Add QSO statistics caching with 5-minute TTL
- Implement cache hit/miss tracking
- Add automatic cache invalidation after LoTW/DCL syncs
- Achieve 601x faster cache hits (12ms → 0.02ms)
- Reduce database load by 96% for repeated requests

Phase 2.2: Performance Monitoring
- Create comprehensive performance monitoring system
- Track query execution times with percentiles (P50/P95/P99)
- Detect slow queries (>100ms) and critical queries (>500ms)
- Implement performance ratings (EXCELLENT/GOOD/SLOW/CRITICAL)
- Add performance regression detection (2x slowdown)

Phase 2.3: Cache Invalidation Hooks
- Invalidate stats cache after LoTW sync completes
- Invalidate stats cache after DCL sync completes
- Automatic 5-minute TTL expiration

Phase 2.4: Monitoring Dashboard
- Enhance /api/health endpoint with performance metrics
- Add cache statistics (hit rate, size, hits/misses)
- Add uptime tracking
- Provide real-time monitoring via REST API

Files Modified:
- src/backend/services/cache.service.js (stats cache, hit/miss tracking)
- src/backend/services/lotw.service.js (cache + performance tracking)
- src/backend/services/dcl.service.js (cache invalidation)
- src/backend/services/performance.service.js (NEW - complete monitoring system)
- src/backend/index.js (enhanced health endpoint)

Performance Results:
- Cache hit time: 0.02ms (601x faster than database)
- Cache hit rate: 91.67% (10 queries)
- Database load: 96% reduction
- Average query time: 3.28ms (EXCELLENT rating)
- Slow queries: 0
- Critical queries: 0

Health Endpoint API:
- GET /api/health returns:
  - status, timestamp, uptime
  - performance metrics (totalQueries, avgTime, slow/critical, topSlowest)
  - cache stats (hitRate, total, size, hits/misses)
2026-01-21 07:41:12 +01:00
1b0cc4441f chore: add log files to gitignore 2026-01-21 07:12:58 +01:00
21263e6735 feat: optimize QSO statistics query with SQL aggregates and indexes
Replace memory-intensive approach (load all QSOs) with SQL aggregates:
- Query time: 5-10s → 3.17ms (62-125x faster)
- Memory usage: 100MB+ → <1MB (100x less)
- Concurrent users: 2-3 → 50+ (16-25x more)

Add 3 critical database indexes for QSO statistics:
- idx_qsos_user_primary: Primary user filter
- idx_qsos_user_unique_counts: Unique entity/band/mode counts
- idx_qsos_stats_confirmation: Confirmation status counting

Total: 10 performance indexes on qsos table

Tested with 8,339 QSOs:
- Query time: 3.17ms (target: <100ms) 
- All tests passed
- API response format unchanged
- Ready for production deployment
2026-01-21 07:11:21 +01:00