Add centralized escapeHtml() utility and apply it to every dynamic value
inserted via innerHTML/template literals across the frontend. Data from
VRS JSON sources and external CSV files (airline names, countries) flows
through the backend as arbitrary strings that could contain HTML. While
Go's json.Marshal escapes < > &, JavaScript's JSON.parse reverses those
escapes before the values reach innerHTML — enabling script injection.
Affected modules: aircraft-manager, ui-manager, callsign-manager,
map-manager, and the 3D radar labels in app.js.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add conditional verbose logging controlled by ?verbose URL param or localStorage
- Reduce frequent WebSocket message logging to verbose mode only
- Minimize aircraft position update logging to prevent console spam
- Make 3D radar initialization logging conditional on verbose flag
- Reduce WebSocket message counter frequency from every 10 to every 500 messages
- Preserve important error messages and connection status logging
Users can enable verbose logging with:
- URL parameter: http://localhost:8080?verbose
- localStorage: localStorage.setItem('skyview-verbose', 'true')
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added missing icon types (heavy, large, light, medium) to the loadIcons() function.
The icon cache was only loading 6 out of 10 available SVG icons, causing aircraft
with weight-based classifications to display as plain circles instead of proper
aircraft icons.
Fixed icon types now loaded:
- ✅ commercial, helicopter, military, cargo, ga, ground (existing)
- ✅ heavy, large, light, medium (newly added)
This ensures all aircraft with known ADS-B emitter categories display the correct
type-specific icons instead of falling back to generic circle markers.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Resolves issue #3 where aircraft age field was always showing 0 seconds.
Backend Changes:
- Fix MarshalJSON in merger.go to calculate age dynamically using time.Since(a.LastUpdate)
- Add comprehensive tests for age calculation in merger_test.go
Frontend Changes:
- Add calculateAge() utility method to both aircraft-manager.js and ui-manager.js
- Update popup content and aircraft table to use client-side age calculation
- Implement real-time age updates every second in app.js
- Add updateOpenPopupAges() function to refresh popup displays
Key Benefits:
- Aircraft age now shows actual seconds since last transmission
- Real-time updates in UI without requiring new WebSocket data
- Proper data staleness indicators for aviation tracking
- No additional server load - client-side calculation using last_update timestamp
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Resolves issue #13 by implementing comprehensive aircraft legend improvements:
## New Features
- **Size-based aircraft icons**: Created distinct SVG icons for light, medium, large, and heavy aircraft with progressively larger visual representations
- **Visual aircraft icons in legend**: Replaced colored squares with actual aircraft silhouettes showing relative sizes and types
- **Enhanced categorization**: Added military category to legend and improved icon selection logic
## Improvements
- **Better differentiation**: Each weight class now has a unique icon shape, not just color
- **Accurate ADS-B mapping**: Icons correctly map to decoded ADS-B emitter categories
- **Clearer legend display**: Users can now see actual aircraft shapes instead of generic colored rectangles
## Technical Changes
- Created 4 new SVG icons: light.svg, medium.svg, large.svg, heavy.svg
- Updated legend HTML to embed aircraft SVG icons inline
- Enhanced JavaScript logic to better match categories to appropriate icon types
- Simplified color mapping function for cleaner code
This addresses the original concerns about confusing legend entries and lack of visual differentiation between aircraft types.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add callsign management module for enhanced aircraft information
- Integrate database status display in web interface
- Update aircraft manager with database-backed callsign resolution
- Enhance user interface with database connectivity indicators
- Add embedded asset management for new database interface components
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added High Vortex Large as distinct category in legend
- Assigned red-orange color (#ff4500) to differentiate from regular Large
- Updated JavaScript to check for high vortex before regular large
- Maintains proper ADS-B category distinctions for wake turbulence
High Vortex Large aircraft (like B757) create stronger wake turbulence
than typical large aircraft, warranting visual distinction for safety.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed incorrect category label: 34000-136000kg is Large, not Medium
- Updated JavaScript color matching to properly distinguish categories
- Simplified color logic to use category keywords (light/medium/large/heavy)
This ensures:
- Light aircraft (< 7000kg): Sky blue
- Medium aircraft (7000-34000kg): Green
- Large aircraft (34000-136000kg): Orange
- Heavy aircraft (> 136000kg): Red
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replaced simple geometric shapes with detailed, realistic SVG icons for all aircraft types
- Implemented color differentiation based on aircraft weight categories:
* Light (<7000kg): Sky blue
* Medium (7000-34000kg): Green
* Large (34000-136000kg): Orange
* Heavy (>136000kg): Red
- Created new icons for: commercial airliner, helicopter, cargo aircraft, general aviation, military fighter, ground vehicle
- Updated legend to reflect new weight-based categories
- Modified getAircraftColor() to assign colors based on aircraft category/weight
Closes#17🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Transponder Display Improvements:**
- Simplified transponder capability labels to be more concise
- "Level 2+ Transponder" → "Level 2+"
- "Enhanced Transponder" → "Enhanced"
- "Alert/Emergency Status" → "Alert/Emergency"
- Removes redundant "Transponder" suffix for cleaner popup display
**New Signal Quality Feature:**
- Added SignalQuality field combining NACp, NACv, and SIL into human-readable assessment
- Quality levels: "Excellent", "Good", "Fair", "Poor" based on aviation standards
- Prioritizes surveillance integrity (SIL) then position accuracy (NACp)
- Automatically calculated when operational status messages (TC 31) are received
- Displayed in aircraft popup when available
**Signal Quality Algorithm:**
- **Excellent**: High integrity (SIL ≥ 2) with precise position (NACp ≥ 9)
- **Good**: Good integrity with moderate accuracy OR very high accuracy
- **Fair**: Some integrity with basic accuracy OR high accuracy without integrity
- **Poor**: Low but usable quality indicators
- **Empty**: No quality data available
**Frontend Enhancements:**
- Added "Signal Quality" row to aircraft popup
- Only displays when quality data is available
- Clean integration with existing popup layout
- Shows alongside transponder information
**Data Quality Context:**
- NACp: Position accuracy (0-11, higher = more precise location)
- NACv: Velocity accuracy (0-4, higher = more precise speed/heading)
- SIL: Surveillance integrity (0-3, higher = more reliable data)
This gives users a quick understanding of data reliability without needing
to interpret technical NACp/NACv/SIL values directly.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add dedicated transponder fields to prevent Mode S decoder from overwriting
the aircraft Category field with transponder capability information.
**Problem Fixed:**
- DF11 All-Call Reply messages were setting aircraft.Category to "Enhanced Transponder"
- This overwrote the actual aircraft type (Light, Medium, Heavy, etc.) from ADS-B
- Users saw "Enhanced Transponder" instead of proper aircraft classification
**Solution:**
- Added dedicated TransponderCapability and TransponderLevel fields to Aircraft struct
- Updated JSON marshaling to include new transponder fields
- Modified decodeAllCallReply() to use dedicated fields instead of Category
- Enhanced popup display to show transponder info separately from aircraft type
- Removed Category overwriting in decodeCommD() for DF24 messages
**New Aircraft Fields:**
- TransponderCapability: Human-readable capability description
- TransponderLevel: Numeric capability level (0-7)
**Popup Display:**
- Aircraft type now shows correctly (Light, Medium, Heavy, etc.)
- Transponder capability displayed as separate "Transponder:" field when available
- Only shows transponder info when DF11 messages have been received
**Data Quality Indicators Clarification:**
- NACp: Navigation Accuracy Category - Position (0-11, higher = more accurate)
- NACv: Navigation Accuracy Category - Velocity (0-4, higher = more accurate)
- SIL: Surveillance Integrity Level (0-3, higher = more reliable)
Users now see both proper aircraft classification AND transponder capability
information without conflicts between different message types.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Move ARCHITECTURE.md and CLAUDE.md to docs/ directory
- Replace "real-time" terminology with accurate "low-latency" and "high-performance"
- Update README to reflect correct performance characteristics
- Add comprehensive ICAO country database with SQLite backend
- Fix display options positioning and functionality
- Add map scale controls and improved range ring visibility
- Enhance aircraft marker orientation and trail management
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Extract all aircraft type SVG designs to separate files in /static/icons/
- Add icon caching system with async loading and fallback mechanisms
- Implement dynamic marker icon updates when aircraft properties change
- Detect and respond to aircraft type/category, ground status, and rotation changes
- Use currentColor in SVG files for dynamic color application
- Maintain performance with intelligent change detection (5° rotation threshold)
- Support real-time marker updates for weight class transitions and ADS-B changes
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace client-side trail collection with server-provided position history
- Fix aircraft markers to properly orient based on track heading using SVG rotation
- Add beast-dump binary to debian package with comprehensive man pages
- Trail visualization now uses gradient effect where newer positions are brighter
- Marker icons update when track heading changes by more than 5 degrees for performance
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major improvements to map theming and aircraft type display:
Map Theme Changes:
- Changed default map from dark to light theme (CartoDB Positron)
- Added night mode toggle button with sun/moon icons
- Both main map and coverage map now switch themes together
- Light theme provides better daylight visibility
Aircraft Type Display:
- Now displays actual ADS-B category directly (e.g., "Medium 34000-136000kg")
- Removed guessing/interpretation of aircraft types
- Icons still use simplified categories for visual distinction
- More accurate and standards-compliant display
This provides a cleaner, more professional appearance with the light map
and gives users accurate ADS-B category information instead of interpreted types.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Enhanced popup text contrast and readability:
- Added text-shadow to all values for better contrast against dark background
- Properly handle zero/null values (e.g., Track: 0° now shows instead of N/A)
- Style N/A values with slightly dimmed gray (#aaaaaa) but still clearly visible
- Add 'no-data' class to distinguish missing data from actual zero values
- Ensure all text has strong white color with !important declarations
This fixes visibility issues where some values appeared too faint or were
incorrectly treated as missing when they were actually zero.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove verbose console.log statements from WebSocket, map, and aircraft managers
- Keep essential error messages and warnings for debugging
- Consolidate app-new.js into app.js to eliminate confusing duplicate files
- Update HTML reference to use clean app.js with incremented cache version
- Significantly reduce console noise for better user experience
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
PROBLEM:
- Aircraft were appearing ~100km from receiver when actually ~5km away
- CPR (Compact Position Reporting) algorithm has zone ambiguity issue
- Without reference position, aircraft can appear in wrong 6-degree zones
SOLUTION:
- Add receiver reference position to CPR decoder for zone resolution
- Modified NewDecoder() to accept reference latitude/longitude parameters
- Implement distance-based zone selection (choose solution closest to receiver)
- Updated all decoder instantiations to pass receiver coordinates
TECHNICAL CHANGES:
- decoder.go: Add refLatitude/refLongitude fields and zone ambiguity resolution
- beast.go: Pass source coordinates to NewDecoder()
- beast-dump/main.go: Use default coordinates (0,0) for command-line tool
- merger.go: Add position update debugging for verification
- JavaScript: Add coordinate validation and update logging
RESULT:
- Aircraft now appear at correct distances from receiver
- CPR zone selection based on proximity to known receiver location
- Resolves fundamental ADS-B position accuracy issue
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Root cause: The merger was blocking position updates from the same source
after the first position was established, designed for multi-source scenarios
but preventing single-source position updates.
Changes:
- Refactor JavaScript into modular architecture (WebSocketManager, AircraftManager, MapManager, UIManager)
- Add CPR coordinate validation to prevent invalid latitude/longitude values
- Fix merger to allow position updates from same source for moving aircraft
- Add comprehensive coordinate bounds checking in CPR decoder
- Update HTML to use new modular JavaScript with cache busting
- Add WebSocket debug logging to track data flow
Technical details:
- CPR decoder now validates coordinates within ±90° latitude, ±180° longitude
- Merger allows updates when currentBest == sourceID (same source continuous updates)
- JavaScript modules provide better separation of concerns and debugging
- WebSocket properly transmits updated aircraft coordinates to frontend
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>