fix: enable debug logging and improve DCL sync observability
- Fix logger bug where debug level (0) was treated as falsy - Change `||` to `??` in config.js to properly handle log level 0 - Debug logs now work correctly when LOG_LEVEL=debug - Add server startup logging - Log port, environment, and log level on server start - Helps verify configuration is loaded correctly - Add DCL API request debug logging - Log full API request parameters when LOG_LEVEL=debug - API key is redacted (shows first/last 4 chars only) - Helps troubleshoot DCL sync issues - Update CLAUDE.md documentation - Add Logging section with log levels and configuration - Document debug logging feature for DCL service - Add this fix to Recent Commits section Note: .env file added locally with LOG_LEVEL=debug (not committed) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
104
CLAUDE.md
104
CLAUDE.md
@@ -19,6 +19,22 @@ Default to using Bun instead of Node.js.
|
||||
- Prefer `Bun.file` over `node:fs`'s readFile/writeFile
|
||||
- Bun.$`ls` instead of execa.
|
||||
|
||||
## Logging
|
||||
|
||||
The application uses a custom logger in `src/backend/config.js`:
|
||||
- **Log levels**: `debug` (0), `info` (1), `warn` (2), `error` (3)
|
||||
- **Default**: `debug` in development, `info` in production
|
||||
- **Override**: Set `LOG_LEVEL` environment variable (e.g., `LOG_LEVEL=debug`)
|
||||
- **Output format**: `[timestamp] LEVEL: message` with JSON data
|
||||
|
||||
**Important**: The logger uses the nullish coalescing operator (`??`) to handle log levels. This ensures that `debug` (level 0) is not treated as falsy.
|
||||
|
||||
Example `.env` file:
|
||||
```
|
||||
NODE_ENV=development
|
||||
LOG_LEVEL=debug
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Use `bun test` to run tests.
|
||||
@@ -170,12 +186,33 @@ The award system is JSON-driven and located in `award-definitions/` directory. E
|
||||
- `normalizeMode(mode)`: Standardize mode names (CW, FT8, SSB, etc.)
|
||||
- Used by both LoTW and DCL services for consistency
|
||||
|
||||
**Job Queue Service**: `src/backend/services/job-queue.service.js`
|
||||
- Manages async background jobs for LoTW and DCL sync
|
||||
- `enqueueJob(userId, jobType)`: Queue a sync job ('lotw_sync' or 'dcl_sync')
|
||||
- `processJobAsync(jobId, userId, jobType)`: Process job asynchronously
|
||||
- `getUserActiveJob(userId, jobType)`: Get active job for user (optional type filter)
|
||||
- `getJobStatus(jobId)`: Get job status with parsed result
|
||||
- `updateJobProgress(jobId, progressData)`: Update job progress during processing
|
||||
- Supports concurrent LoTW and DCL sync jobs
|
||||
- Job types: 'lotw_sync', 'dcl_sync'
|
||||
- Job status: 'pending', 'running', 'completed', 'failed'
|
||||
|
||||
**Backend API Routes** (`src/backend/index.js`):
|
||||
- `POST /api/lotw/sync`: Queue LoTW sync job
|
||||
- `POST /api/dcl/sync`: Queue DCL sync job
|
||||
- `GET /api/jobs/:jobId`: Get job status
|
||||
- `GET /api/jobs/active`: Get active job for current user
|
||||
|
||||
**DCL Service**: `src/backend/services/dcl.service.js`
|
||||
- `fetchQSOsFromDCL(dclApiKey, sinceDate)`: Fetch from DCL API
|
||||
- API Endpoint: `https://dings.dcl.darc.de/api/adiexport`
|
||||
- Request: POST with JSON body `{ key, limit: 50000, qsl_since, qso_since, cnf_only }`
|
||||
- `parseDCLJSONResponse(jsonResponse)`: Parse example/test payloads
|
||||
- `syncQSOs(userId, dclApiKey, sinceDate, jobId)`: Sync QSOs to database
|
||||
- `getLastDCLQSLDate(userId)`: Get last QSL date for incremental sync
|
||||
- Ready for when DCL publishes their API
|
||||
- Debug logging (when `LOG_LEVEL=debug`) shows API params with redacted key (first/last 4 chars)
|
||||
- Fully implemented and functional
|
||||
- **Note**: DCL API is a custom prototype by DARC; contact DARC for API specification details
|
||||
|
||||
### DLD Award Implementation (COMPLETED)
|
||||
|
||||
@@ -214,6 +251,20 @@ The DLD (Deutschland Diplom) award was recently implemented:
|
||||
|
||||
**Documentation**: See `docs/DOCUMENTATION.md` for complete documentation including DLD award example.
|
||||
|
||||
**Frontend**: `src/frontend/src/routes/qsos/+page.svelte`
|
||||
- Separate sync buttons for LoTW (blue) and DCL (orange)
|
||||
- Independent progress tracking for each sync type
|
||||
- Both syncs can run simultaneously
|
||||
- Job polling every 2 seconds for status updates
|
||||
- Import log displays after sync completion
|
||||
- Real-time QSO table refresh after sync
|
||||
|
||||
**Frontend API** (`src/frontend/src/lib/api.js`):
|
||||
- `qsosAPI.syncFromLoTW()`: Trigger LoTW sync
|
||||
- `qsosAPI.syncFromDCL()`: Trigger DCL sync
|
||||
- `jobsAPI.getStatus(jobId)`: Poll job status
|
||||
- `jobsAPI.getActive()`: Get active job on page load
|
||||
|
||||
### Adding New Awards
|
||||
|
||||
To add a new award:
|
||||
@@ -230,20 +281,23 @@ To add a new award:
|
||||
|
||||
- **LoTW (Logbook of The World)**: ARRL's confirmation system
|
||||
- Service: `src/backend/services/lotw.service.js`
|
||||
- API: `https://lotw.arrl.org/lotwuser/lotwreport.adi`
|
||||
- Fields: `lotwQslRstatus`, `lotwQslRdate`
|
||||
- Used for DXCC, WAS, VUCC, most awards
|
||||
- ADIF format with `<EOR>` delimiters
|
||||
- Supports incremental sync by date
|
||||
- Supports incremental sync by `qso_qslsince` parameter (format: YYYY-MM-DD)
|
||||
|
||||
- **DCL (DARC Community Logbook)**: DARC's confirmation system
|
||||
- Service: `src/backend/services/dcl.service.js`
|
||||
- API: `https://dings.dcl.darc.de/api/adiexport`
|
||||
- Fields: `dclQslRstatus`, `dclQslRdate`
|
||||
- DOK fields: `darcDok` (partner's DOK), `myDarcDok` (user's DOK)
|
||||
- Required for DLD award
|
||||
- German amateur radio specific
|
||||
- API in development (parser ready)
|
||||
- Request format: POST JSON `{ key, limit, qsl_since, qso_since, cnf_only }`
|
||||
- Response format: JSON with ADIF string in `adif` field
|
||||
- Supports DOK (DARC Ortsverband Kennung) data
|
||||
- Supports incremental sync by `qsl_since` parameter (format: YYYYMMDD)
|
||||
- Updates QSOs only if confirmation data has changed
|
||||
|
||||
### ADIF Format
|
||||
|
||||
@@ -262,10 +316,50 @@ Both LoTW and DCL return data in ADIF (Amateur Data Interchange Format):
|
||||
|
||||
### Recent Commits
|
||||
|
||||
- **Uncommitted**: fix: logger debug level not working
|
||||
- Fixed bug where debug logs weren't showing due to falsy value handling
|
||||
- Changed `||` to `??` in logger config to properly handle log level 0 (debug)
|
||||
- Added `.env` file with `LOG_LEVEL=debug` for development
|
||||
- Debug logs now show DCL API request parameters with redacted API key
|
||||
- `27d2ef1`: fix: preserve DOK data when DCL doesn't send values
|
||||
- DCL sync only updates DOK/grid fields when DCL provides non-empty values
|
||||
- Prevents accidentally clearing DOK data from manual entry or other sources
|
||||
- Preserves existing DOK when DCL syncs QSO without DOK information
|
||||
- `e09ab94`: feat: skip QSOs with unchanged confirmation data
|
||||
- LoTW/DCL sync only updates QSOs if confirmation data has changed
|
||||
- Tracks added, updated, and skipped QSO counts
|
||||
- LoTW: Checks if lotwQslRstatus or lotwQslRdate changed
|
||||
- DCL: Checks if dclQslRstatus, dclQslRdate, darcDok, myDarcDok, or grid changed
|
||||
- `3592dbb`: feat: add import log showing synced QSOs
|
||||
- Backend returns addedQSOs and updatedQSOs arrays in sync result
|
||||
- Frontend displays import log with callsign, date, band, mode for each QSO
|
||||
- Separate sections for "New QSOs" and "Updated QSOs"
|
||||
- Sync summary shows total, added, updated, skipped counts
|
||||
- `8a1a580`: feat: implement DCL ADIF parser and service integration
|
||||
- Add shared ADIF parser utility (src/backend/utils/adif-parser.js)
|
||||
- Implement DCL service with API integration ready
|
||||
- Implement DCL service with API integration
|
||||
- Refactor LoTW service to use shared parser
|
||||
- Tested with example DCL payload (6 QSOs parsed successfully)
|
||||
- `c982dcd`: feat: implement DLD (Deutschland Diplom) award
|
||||
- `322ccaf`: docs: add DLD (Deutschland Diplom) award documentation
|
||||
|
||||
### Sync Behavior
|
||||
|
||||
**Import Log**: After each sync, displays a table showing:
|
||||
- New QSOs: Callsign, Date, Band, Mode
|
||||
- Updated QSOs: Callsign, Date, Band, Mode (only if data changed)
|
||||
- Skipped QSOs: Counted but not shown (data unchanged)
|
||||
|
||||
**Duplicate Handling**:
|
||||
- QSOs matched by: userId, callsign, qsoDate, timeOn, band, mode
|
||||
- If confirmation data unchanged: Skipped (not updated)
|
||||
- If confirmation data changed: Updated with new values
|
||||
- Prevents unnecessary database writes and shows accurate import counts
|
||||
|
||||
**DOK Update Behavior**:
|
||||
- If QSO imported via LoTW (no DOK) and later DCL confirms with DOK: DOK is added ✓
|
||||
- If QSO already has DOK and DCL sends different DOK: DOK is updated ✓
|
||||
- If QSO has DOK and DCL syncs without DOK (empty): Existing DOK is preserved ✓
|
||||
- LoTW never sends DOK data; only DCL provides DOK fields
|
||||
|
||||
**Important**: DCL sync only updates DOK/grid fields when DCL provides non-empty values. This prevents accidentally clearing DOK data that was manually entered or imported from other sources.
|
||||
|
||||
Reference in New Issue
Block a user