- Session cookie: add encryption_salt and secure flag to endpoint
- CSP: remove unsafe-eval from script-src directive
- /metrics: wrap PromEx endpoint behind rate-limited pipeline
- LiveView signing_salt: move to env var in production config
- LiveView performance: defer heavy aggregation queries past initial mount
- SQL: replace correlated subquery with DISTINCT ON in get_heard_by_stations
Critical:
- Remove :protected from WeatherCache ETS (conflicted with :public)
- Register Aprsme.ReplayRegistry in supervision tree
- Route :continue_replay dead message to :start_replay handler
- Add 5000ms timeout to unbounded :rpc.call calls
- Fix falsy lat/lng check rejecting valid 0 coordinates
Medium:
- Fix live_reload pattern (temp_web -> aprsme_web)
- Remove duplicate ecto_repos config
- Make DB SSL configurable via DB_SSL env var
- Track sizeCheckTimeout on self for cleanup in destroyed()
- Wrap pushEvent calls in try/catch
- Remove unused size variable in marker cluster icon
- Capture touch coords at touchstart instead of stale TouchEvent
- Demote console.log to console.debug in production code
- Add catch-all to normalize_bounds preventing GenServer crash
Style:
- Add missing @impl true annotations in is.ex
- Improve migration failure error message
- Use textContent instead of innerHTML for error messages
- Use proper type for longPressTimer instead of any
Wire up prom_ex with built-in Application, Beam, Phoenix, PhoenixLiveView,
and Ecto plugins, plus a custom plugin that exposes the existing
app-specific telemetry (packet pipeline, spatial PubSub, repo pool,
postgres stats, insert optimizer) as Prometheus metrics.
Mount PromEx.Plug at /metrics — internal-only, intended to be scraped
by the cluster's external Prometheus through the kube-apiserver pod
proxy. K8s pod template now carries prometheus.io/{scrape,port,path}
annotations so the existing kubernetes-pods scrape job picks it up
automatically.
PromEx is disabled in the test environment.
Also harden the packet cleanup and partition manager tests with
Repo.delete_all setup hooks so they aren't poisoned by residual rows
committed outside a sandbox transaction in earlier runs (which were
inflating delete counts and triggering ATTACH PARTITION check_violation
errors against packets_default).
- Delete config/appsignal.exs (was never wired into mix.exs or any
other config file)
- Migration: fix decrement_packet_sequence trigger to handle the case
where currval() hasn't been called in the current DB session, matching
the same exception handling already present in get_packet_count()
- Fix get_historical_packet_count test: invalid non-list bounds are
silently ignored (no error), so assert is_integer not count == 0
- Add Repo.delete_all(Packet) setup blocks in PacketsOldestTest and
PacketConsumerTest to clear any committed DB state before tests that
depend on an empty packets table
Remove faker, floki, igniter, ecto_psql_extras (zero usages), exvcr
(zero usages), and resend. Replace resend with Aprsme.Swoosh.ResendAdapter
using the already-present req dependency. Frees 23 packages total from
the lockfile including hackney, certifi, and the tesla dependency chain.
Fix two pre-existing test isolation bugs:
- signal_handler_test called the real ShutdownHandler.shutdown() via SIGTERM
simulation without restoring state, causing page_controller_test to see
shutting_down: true and return 503
- page_controller_test setup now resets ShutdownHandler state defensively
Move packet_retention_days configuration from config.exs (compile-time)
to runtime.exs so it properly reads the PACKET_RETENTION_DAYS environment
variable at runtime instead of baking in the default value during build.
This fixes the issue where the app was using 7 days retention despite
PACKET_RETENTION_DAYS being set to 1 in the deployment, causing disk
to fill up with 54GB of old partition data.
Convert app.js, info_map.js, error_boundary.js, and time_ago_hook.js
to TypeScript with proper typing for Phoenix hooks, Leaflet, DOM
interactions, and timer management. Update esbuild hex package to
~> 0.10 and binary to 0.25.4. Entry point changed to app.ts.
Convert the packets table to a time-partitioned table with daily
partitions (PARTITION BY RANGE on received_at). This replaces the
expensive CTE-based batch DELETE cleanup with instant DROP TABLE
partition drops — no dead tuples, no WAL pressure, no VACUUM needed.
- Add PartitionManager GenServer to create/drop daily partitions
- Simplify PacketCleanupWorker to delegate to PartitionManager
- Replace gridsquare/geocalc deps with local Maidenhead module
- Remove gettext_pseudolocalize dependency
- Fix Decimal comparison in packet consumer test
Delete 5 unused modules: Presence (untracked), LiveView ShutdownHandler
(unused mixin), RateLimiterWrapper (pointless delegation), Passcode
(only used by own test), MapLive.Utils (pure delegates).
Fix ShutdownHandler to not call deleted Presence. Inline ParamUtils
at call sites. Remove cachex dep and 27 stale entries from mix.lock.
Clean commented-out Exq/Redis config from application.ex.
DNSSRV strategy resolves to IP-based names but nodes were named by
pod name, causing connection failures. Switch to DNS strategy with
IP-based node naming so libcluster discovery matches actual node names.
When the PacketProducer buffer crosses 80% capacity, signal Aprsme.Is
to switch its TCP socket to passive mode, leveraging TCP flow control
to slow APRS-IS intake. Resume active mode when buffer drains below 30%.
A 30-second safety valve timer auto-resumes if backpressure gets stuck.
Disconnect/reconnect/terminate paths all clear backpressure state.
Use CF-IPLatitude/CF-IPLongitude headers instead of making HTTP calls
to ip-api.com on every page load. Eliminates ~500ms latency, external
API dependency, and flaky tests.
Also disable test server to prevent port conflicts during development.
Connect to 204.110.191.232 instead of the default dallas.aprs2.net.
runtime.exs now reads APRS_HOST (over APRS_SERVER) and APRS_PASSWORD
(over APRS_PASSCODE) so both naming conventions work.
- Add Phoenix.LiveViewTest import to ConnCase to fix warnings
- Disable AppSignal in dev and test (only enable in prod)
- Explicitly disable clustering in test environment
- Fix PacketDistributor to check cluster_enabled before calling LeaderElection
- Add Phoenix.CodeReloader listener to mix.exs
This prevents tests from trying to call cluster-specific GenServers
(ConnectionMonitor, LeaderElection) that don't exist in test mode.
- Remove Exq dependency from mix.exs and application config
- Remove all Exq configuration from config files (config.exs, dev.exs, runtime.exs, test.exs)
- Update CleanupScheduler to run cleanup tasks directly using Task.start instead of queuing jobs
- Update PacketCleanupWorker documentation to remove Exq references
- Cleanup functionality preserved but now runs in supervised Tasks instead of job queue
This resolves the Redis connection error on startup by eliminating the dependency on external job queues.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove phoenix_pubsub_redis dependency from mix.exs
- Update PubSub configuration to use Phoenix's native distributed capabilities
- Simplify clustering logic - no longer requires Redis URL for PubSub
- Phoenix PubSub automatically distributes messages across connected Erlang nodes
- Benefits: lower latency, automatic failure handling, simpler deployment
- Redis still available for caching and job processing when needed
- Maintains backward compatibility for both clustered and non-clustered modes
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Combine Chart.js and date adapter into single bundle to ensure proper loading order
- Add validation to skip chart rendering when insufficient weather data (< 2 points)
- Update vendor loader to not load date adapter separately
- Prevents date adapter errors when weather stations have limited data
The Wallaby integration tests were timing out in CI. This adds proper
configuration for running browser tests in the CI environment.
Changes:
- Start ChromeDriver explicitly in the background on port 4444
- Pass CHROMEDRIVER_URL environment variable to tests
- Add chromedriver_base_url configuration to use env var if available
- Increase test timeout to 60 seconds for integration tests
- Add additional Chrome flags for better CI stability:
- --disable-setuid-sandbox
- --disable-extensions
- --disable-background-timer-throttling
- --disable-backgrounding-occluded-windows
- --disable-renderer-backgrounding
These changes ensure ChromeDriver is properly started and accessible
in the CI environment, preventing connection timeouts.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major performance improvements to test execution:
- Increase max_cases from 16 to 48 for better parallelization
- Increase DB pool size for concurrent tests
- Reduce DB timeouts and enable queue optimization
- Disable logging during tests (level: :error)
- Tag slow tests and exclude them by default
- Only seed devices for tests that need them
- Fixed log capture test for packet consumer
- Fixed flaky leader election test with proper timing
Performance improvements:
- Fast tests: 43.2s -> 24.1s (48% faster)
- All tests still pass with --exclude flags removed
- Created .test-commands with helpful aliases
Usage:
- mix test --exclude slow --exclude integration # Fast development tests
- mix test # All tests including slow ones
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Prevents database ownership errors during LiveView tests by disabling
ErrorTracker's database integration in the test environment.
This resolves the recurring "Handler ErrorTracker.Integrations.Phoenix
has failed and has been detached" errors that were occurring when
LiveView processes tried to write to the database without proper
ownership setup.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Address browser testing reliability in CI environments:
## CI/CD Improvements
- **ChromeDriver**: Use latest stable version instead of pinned version for better compatibility
- **Timeouts**: Add 10-minute timeout for integration tests to prevent CI hangs
- **Environment Variables**: Configure WALLABY_MAX_WAIT_TIME for CI-specific timeouts
## Wallaby Configuration Enhancements
- **Chrome Args**: Add CI-stable Chrome options (--no-sandbox, --disable-dev-shm-usage)
- **Window Size**: Set consistent 1280x720 window size for reproducible tests
- **Dynamic Timeouts**: Environment-configurable max wait time with sensible defaults
- **Pool Size**: Limit to single browser instance to prevent resource conflicts
## Benefits
- ✅ More reliable test execution in CI environments
- ✅ Better error handling and timeout management
- ✅ Consistent browser behavior across environments
- ✅ Reduced flakiness from resource constraints
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit implements browser-based integration testing for the Phoenix LiveView
application using Wallaby and ChromeDriver to test the complete user experience
including JavaScript interactions.
## Changes Made
### Testing Infrastructure
- Add Wallaby dependency for browser automation testing
- Configure Chrome driver with headless mode for CI/CD
- Set up Phoenix server integration for test environment
- Enable screenshot capture on test failures
### Integration Tests
- `test/integration/simple_integration_test.exs` - Basic homepage functionality
- `test/integration/map_integration_test.exs` - Map interface and routing tests
- Tests validate page loading, content rendering, and navigation
### CI/CD Integration
- Update GitHub Actions workflow to install ChromeDriver
- Add separate integration test step in CI pipeline
- Configure headless Chrome for automated testing
### Configuration Updates
- Enable Phoenix server in test environment for Wallaby
- Configure Wallaby with proper base URL and screenshot settings
- Initialize Wallaby application in test helper
## Features Tested
- ✅ Homepage loads with APRS content
- ✅ Main page structure renders correctly
- ✅ Route navigation functions properly
- ✅ Basic Phoenix LiveView functionality
## Next Steps
This provides a solid foundation for expanding to test:
- Interactive map controls and JavaScript functionality
- Real-time packet updates via LiveView PubSub
- User authentication flows and form submissions
- Mobile responsive behavior
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix zero coordinate handling to distinguish between invalid coordinates and valid 0.0 (equator/prime meridian)
- Add to_float_safe() function that preserves nil for proper coordinate validation
- Add comprehensive coordinate validation with descriptive logging in JavaScript
- Make position change threshold configurable via application config (default: 0.001°)
- Add extensive test coverage for edge cases including nil coordinates and equator crossing
- Improve robustness for real-world APRS coordinate edge cases
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add DATABASE_SSL and DATABASE_SSL_VERIFY environment variables
- Configure Postgrex to use SSL with optional certificate verification
- Allow connecting to PostgreSQL with self-signed certificates
- Simplify APRS_PORT parsing to avoid syntax errors
- Disable Exq properly in test environment to prevent startup issues
- Disable Prometheus telemetry in test mode to avoid port conflicts
- Update telemetry module to conditionally start Prometheus metrics
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add robust integer parsing for APRS_PORT environment variable
- Fallback to default port 14580 if parsing fails
- Prevents crashes when environment variables contain unexpected values
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Make APRS-IS port configurable via APRS_PORT environment variable
- Defaults to 14580 (filtered port) if not specified
- Allows switching to 10152 (unfiltered port) for full packet stream
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix race condition in map bundle loading by waiting for script to load before initializing map
- Ensure Leaflet is properly exposed as window.L in map bundle
- Add Leaflet availability check in map initialization function
- Disable Exq background jobs in development environment to remove Redis dependency
- Remove invalid TelemetryMetricsPrometheus plug from endpoint
- Application now starts successfully without Redis in development mode
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Only include password in Exq config if it's not empty
- Prevents "ERR AUTH <password>" error when Redis has no authentication
- Build config dynamically to exclude empty password field
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Wrap String.to_integer in try/rescue block properly
- Fix CompileError caused by rescue clause inside case statement
- Ensures runtime.exs can compile and load Redis configuration
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>