Commit graph

32 commits

Author SHA1 Message Date
2b64beac34
reliability: N+1 query audit complete, handoff updated
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2s
- Audit found no high-severity N+1 patterns. Cache layers and batch queries
  already eliminate classic patterns in hot paths
- Two medium-priority edge cases documented: InfoLive double-query per update,
  popup weather fallback cache key mismatch
- Handoff: marked reliability #4 as done
2026-07-26 15:32:51 -05:00
e1da1716b1
refactor: split MapLive.Index into focused modules
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2s
- State (177 lines): mount assigns, defaults, slideover, connection status
- Events (540 lines): 22 handle_event handlers, rate limiting, URL helpers
- Subscriptions (122 lines): PubSub setup, spatial registration, cleanup
- BoundsUpdater (172 lines): bounds pipeline, validation, debouncing
- index.ex: 2,062 -> 1,202 lines (42% reduction)
- Credo: initial_historical_completed, bounds_update_timer added to ignored_assigns
  (consumed by extracted modules, invisible to credo)
- All 361 map_live tests pass across multiple random seeds
- Handoff: marked maintainability #1 as done
2026-07-26 15:30:08 -05:00
eb389af64b
reliability: bound ingress buffers, payload limits, overflow telemetry
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2s
- PacketProducer: 15s periodic buffer depth telemetry, overflow events
- MobileChannel: 500-packet ring buffer with overflow drops, payload validation
  (query max 20 chars, callsign max 20 chars, results capped at 200,
   bounds area max 1000 sq deg), rejection telemetry
- PromEx: buffer depth/max/overflow metrics, mobile overlay, payload rejected
- Tests: 2491 passed, 0 failures
- Handoff document: marked reliability #1 and #2 as done
2026-07-26 15:10:54 -05:00
4e92bbfc9f
docs: supervision tree ownership map, naming issues documented
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2s
- Mapped 18 top-level children + 2 nested supervisors in application.ex
- Ownership: Is->PacketPipelineSupervisor (ingestion), PartitionManager (retention),
  SpatialPubSub (broadcast), CleanupScheduler+PacketCleanupWorker (bad-packet cleanup)
- Removed Exq comment fossil from application.ex:72
- Known naming issues: PacketCleanupWorker only handles bad_packets,
  PostgresNotifier scope narrower than name, PacketConsumer is 776-line multi-concern
- Handoff document: marked maintainability #2 as done
2026-07-26 14:59:55 -05:00
a4991c1401
docs: callsign naming distinction, test coverage review, handoff updates
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2s
- Aprsme.Callsign: enhanced @moduledoc with explicit AX.25 vs transport-safe
  identifier distinction, four validation layers documented
- Test coverage review: confirmed no gaps from deleted packet_pipeline_integration_test
  All ingestion scenarios covered across 5 test files; 2491 passed, 0 failures
- Handoff document: marked maintainability #4 (callsign naming), #6 (test coverage) as done
2026-07-26 14:57:42 -05:00
9ba4dac53a
maintainability: obsolete config cleanup, focused migration tests
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2s
- Removed stale .dialyzer_ignore.exs entry for deleted packet_replay_test.exs
- Removed orphaned :initialize_replay_delay config key from test.exs
- Updated CLAUDE.md: StreamingPacketsPubSub -> SpatialPubSub
- Added migration_validation_test.exs: 12 tests covering geometry GiST indexes,
  counter reconciliation, and partition boundary cutoff behavior
- Updated handoff document: marked maintainability #3 and #5 as done
2026-07-26 14:15:39 -05:00
9f45937a82
security: sobelow triage, admin route review, k8s secrets hardening
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2s
- Admin route authorization: all routes verified with dual protection, negative tests exist
- Sobelow: regenerated .sobelow-skips (14 documented findings, no stale entries)
- k8s: moved APRS_PASSWORD to APRS_PASSCODE secretKeyRef in deployment
- Handoff document: marked remaining security items #4-6 as done
2026-07-26 14:08:27 -05:00
0f2195ef9d
security: CSP nonces, RemoteIp CIDR gating, rate limiting, NetworkPolicies, deadlock fixes
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2s
- Content-Security-Policy: nonce-based per-request plug replacing unsafe-inline scripts
- RemoteIp: CIDR-based trust gating via InetCidr, skips forwarded headers from untrusted peers
- Rate limiting: auth pipeline (20/min), LiveView event handlers, existing mobile channel limits
- NetworkPolicy: 4 k8s policies (web ingress, cluster, metrics, egress) for least-privilege networking
- PartitionManager: deadlock retry with exponential backoff in drop_partition
- Tests: reduced parallelism (max_cases 4), packets_test async:false to prevent trigger contention
- k8s: APRS_PASSWORD -> APRS_PASSCODE secretRef, vendor/aprs submodule hardened
2026-07-26 14:04:56 -05:00
b0832e5a9c
refactor: harden packet delivery and operations
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2s
2026-07-26 13:11:26 -05:00
Graham McInitre
0e322a2403 docs: add structured documentation covering architecture, contexts, web, infra, and dev setup 2026-07-21 11:01:27 -05:00
09f92c6738
feat(mobile): rate-limit socket + batch historical packet delivery
- MobileUserSocket: cap new socket connections per IP at 30/min via
  Aprsme.RateLimiter. Denials log and return :error at handshake.
  Tests bypass the check (no real peer_data).

- MobileChannel: rate-limit the expensive client-initiated handlers
  (subscribe_bounds, subscribe_callsign, search_callsign) at
  30/minute per socket. Streaming packet delivery is unaffected.

- MobileChannel: historical packet loads now arrive as a batched
  `packets` event (100 per frame) instead of one `packet` frame per
  row. Live streaming still uses the single `packet` event.

- Updated docs/mobile-api.md with the `packets` event and rate-limit
  semantics; migration note preserves compatibility for clients that
  only handle live `packet` events.
2026-04-21 09:38:51 -05:00
6ed10d11f4
docs: add weather nearby API implementation plan
Detailed TDD implementation plan for GET /api/v1/weather/nearby endpoint.
Includes database queries, JSON views, controller logic, and comprehensive
testing strategy.
2026-03-22 11:27:45 -05:00
bc6fdcd9c2
Add design doc for weather nearby API endpoint
Documents new GET /api/v1/weather/nearby endpoint for finding weather
stations within a radius of a lat/lon point. Uses PostGIS ST_DWithin
for efficient spatial queries with configurable time window and result
limits.
2026-03-22 11:27:44 -05:00
0705c1478e
add docs 2026-03-02 08:34:50 -06:00
a939913114
docs: clarify trail line should connect all points regardless of distance
- Continuous path connection for long-distance travel
- No distance-based filtering or gap detection
- Important for aircraft, vehicles, intermittent coverage scenarios
2026-03-01 15:01:08 -06:00
d23ac8cb38
docs: add design for trail line visualization at low zoom for tracked callsigns
- Show polyline trail instead of heat map when tracking callsign at zoom ≤ 8
- Individual markers remain at zoom > 8
- Trail line connects positions chronologically
- Respects trail duration setting
2026-03-01 15:01:07 -06:00
f6730b282a
Fix API documentation to match implementation
- REST API: Fix id type from integer to UUID, add device/equipment
  fields, correct rate limiting info (100 req/min, not "none"),
  add 429 status code
- Mobile API: Fix search_callsign response field (lon not lng),
  add path to packet fields, correct rate limiting/timeout docs,
  clarify update_bounds behavior
- Fix flaky pipeline tests (async race on global Application config)
2026-02-19 10:22:10 -06:00
447a76b3cc
update 2026-02-18 14:14:49 -06:00
2da935b1af
Add callsign search and tracking to mobile API
Implements comprehensive callsign search and live tracking:

- search_callsign: Search for callsigns with wildcard support
  - "W5ISP" finds W5ISP and all SSIDs (W5ISP-1, W5ISP-9, etc.)
  - "W5ISP-9" finds only that specific SSID
  - "W5ISP*" finds all callsigns starting with W5ISP

- subscribe_callsign: Subscribe to live updates for a callsign
  - Loads historical packets for the callsign
  - Receives real-time streaming updates
  - Supports wildcard patterns
  - Works with or without geographic bounds

- unsubscribe_callsign: Stop tracking callsign

When both bounds and callsign are subscribed, packets are filtered
by both criteria (callsign AND within bounds).

Generated with Claude Code https://claude.com/claude-code
2025-10-25 13:11:10 -05:00
d6c3ada6c4
Add historical packet loading to mobile API
When mobile clients subscribe to bounds, the server now loads and sends
historical packets immediately, followed by real-time streaming packets.
This matches the web UI behavior and provides a complete view of APRS
activity in the requested area.

Optional parameters:
- limit: Max historical packets to load (default: 1000, max: 5000)
- hours_back: Hours of historical data (default: 1, max: 24)

Generated with Claude Code https://claude.com/claude-code
2025-10-25 12:31:30 -05:00
ddbb72b1b2
Add mobile API for iOS/Android real-time packet streaming
- Create MobileChannel for geographic bounds-based packet filtering
- Add MobileUserSocket for mobile client connections
- Implement subscribe_bounds, update_bounds, and unsubscribe events
- Leverage existing StreamingPacketsPubSub infrastructure
- Add comprehensive mobile API documentation with Swift examples
- WebSocket endpoint: wss://aprs.me/mobile/websocket
- Channel: mobile:packets

This enables iOS/Android apps to receive real-time APRS packets
filtered by geographic viewport, with efficient bandwidth usage.
2025-10-25 11:25:18 -05:00
047cd3a7ce
fix: Show all packets for tracked callsigns including non-position data
- Modified get_recent_packets to not filter by has_position when tracking a specific callsign
- Ensures users can see status updates, messages, and other non-position packets
- Fixes issue where callsigns without recent position data wouldn't show any packets
- Updated documentation to reflect this behavior

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 14:02:44 -05:00
8c84706c6b
Fix live updates for /info/:call page by sending all packet fields
Update the PostgreSQL notify_packets_insert trigger to send all necessary
fields when broadcasting new packets. Previously only minimal fields were
sent (id, sender, lat, lon, inserted_at), which prevented the info page
from displaying complete packet information during live updates.

The trigger now includes:
- Position data (lat, lon, altitude, course, speed)
- Symbol data (symbol_table_id, symbol_code)
- Device data (device_identifier, path)
- Metadata (received_at, comment, raw_packet)
- PHG data (phg_power, phg_height, phg_gain, phg_directivity)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-28 17:57:16 -05:00
f6b0454d79
db indexes 2025-07-26 18:41:08 -05:00
91b0288202
Update improvement-todos.md with recent changes
Document all the improvements made today:
- Docker optimizations (removed Node.js, faster builds)
- Multiple bug fixes (PgBouncer, Redis, compilation warnings)
- CI/CD improvements (faster deployments, concurrency control)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-26 16:44:18 -05:00
eeeebef34e
Fix PgBouncer database connection and graceful shutdown
- Add SKIP_DB_CREATE env var to skip database creation when using PgBouncer
- Fix redis_children() to return proper child specs
- Implement zero-downtime graceful shutdown without user notifications
- Add health check plug for Kubernetes probes
- Remove user-facing shutdown notifications for seamless deployments

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-26 15:51:06 -05:00
e00d1bdf47
Update documentation with completed improvements
- Add reminder in CLAUDE.md to update improvement todos
- Document completed Redis PubSub integration
- Document completed PgBouncer deployment
- Document completed distributed caching implementation
- Document completed distributed rate limiting
- Add current architecture summary

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-26 15:32:19 -05:00
226a53bf61
Add Redis-based distributed caching and rate limiting
This commit introduces a dual-mode caching and rate limiting system that can use
either Redis (for distributed deployments) or ETS/Cachex (for single-node setups).

Key changes:
- Add Cache abstraction layer that automatically switches between Redis and Cachex
- Implement RedisCache module with full distributed cache functionality
- Implement RedisRateLimiter with sliding window algorithm for accurate rate limiting
- Add RateLimiterWrapper to provide unified API for both implementations
- Update application startup to conditionally use Redis when REDIS_URL is set
- Migrate all cache operations to use the new Cache abstraction
- Support graceful fallback to ETS-based solutions when Redis is unavailable

The system automatically detects Redis availability via REDIS_URL environment
variable and switches between implementations without code changes. This enables
proper distributed caching and rate limiting in Kubernetes deployments while
maintaining backward compatibility for development environments.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-26 15:29:38 -05:00
dadfef8a5b
cleanup 2025-07-18 10:41:26 -05:00
8eb1e90622
use postgis for testing 2025-07-09 16:48:55 -05:00
3903c1b26c
refactor 2025-06-19 15:20:18 -05:00
fe96abca59
symbols 2025-06-16 08:59:28 -05:00