Commit graph

76 commits

Author SHA1 Message Date
c18f034997 improve agent status display and fix two pre-existing test failures (#83)
- Wrap agent name + icon inside the offline amber badge so it's clear
  what is offline on the device detail page
- Add "Agent:" label before the agent indicator for all states
- Fix TimeSeriesTest deadlock: switch to async: false since check_results
  is a TimescaleDB hypertable and concurrent chunk creation deadlocks
- Fix unicode property test: String.length/1 counts grapheme clusters,
  not code points; combining chars can make a 2-codepoint string have
  only 1 grapheme, legitimately failing the min: 2 validation

Reviewed-on: graham/towerops-web#83
2026-03-19 11:43:42 -05:00
f05cc32ef6 fix dns/ping check execution and checks table alignment (#72)
## Summary
- **DNS checks**: `parse_server` returned a flat 5-tuple `{a,b,c,d,53}` instead of `{{a,b,c,d}, 53}` — the format `:inet_res` requires for nameservers. All DNS checks using a custom server failed with argument error.
- **Ping checks**: `System.cmd` `:timeout` option not supported on Elixir 1.19.4 (staging). Replaced with `Task.async`/`Task.yield` wrapper for cross-version compatibility.
- **Checks table UI**: Removed unnecessary flex div wrapper on status badge column that caused vertical misalignment with other table cells.

## Test plan
- [x] DNS executor tests pass (custom server resolution now succeeds)
- [x] Ping executor tests pass (no more ArgumentError)
- [x] Full test suite passes (8593 tests, 0 new failures)

Reviewed-on: graham/towerops-web#72
2026-03-18 14:05:37 -05:00
76b3dd6a93 add ssl/tls certificate expiration check type (#64)
add ssl check executor that connects via TLS, reads peer certificate
expiry, and returns OK/WARNING/CRITICAL based on configurable
warning_days threshold. includes protobuf config, liveview form fields,
agent channel encoding, oban worker dispatch, and unit tests.

Reviewed-on: graham/towerops-web#64
2026-03-17 16:14:22 -05:00
150ffb421d delegate service checks to agents and fix ui issues (#63)
- Skip HTTP/TCP/DNS checks in Phoenix when device is assigned to agent
- Agents now execute service checks from the device's network location
- Fix cancel button in service check modal (text link instead of button)
- Fix status badge alignment in checks table

Reviewed-on: graham/towerops-web#63
2026-03-17 15:43:31 -05:00
cd19db0680 fix-sticky-header-overlap (#60)
Reviewed-on: graham/towerops-web#60
2026-03-17 13:21:58 -05:00
c6913685ee wire up service checks (HTTP/TCP/DNS) to remote agents (#50)
send check_jobs protobuf to agents during job dispatch cycle, handle
check_result messages back with state transitions and alert
creation/resolution. auto-assign checks to device's effective agent
token on creation, broadcast check changes via PubSub so connected
agents get immediate updates.

add edit/delete support for service checks on device show page with
form pre-population from existing check config. auto-fill TCP host
from device IP address.

includes validate_check_result/1 for protobuf validation and
list_checks_for_agent/2 for querying agent-assigned service checks.

also fixes pre-existing broken device_type_icon reference in device
index template.

Reviewed-on: graham/towerops-web#50
2026-03-16 17:25:02 -05:00
19abd5508a
ux: improve mobile responsiveness across all pages
- Hide less-critical table columns on small screens (IP, subs, MRR, etc.)
- Add overflow-x-auto wrappers on tables to prevent horizontal scroll
- Fix <.header> component to flex-wrap action buttons on mobile
- Make page action button labels icon-only on small screens
- Add min-w-0 on grid children to prevent viewport overflow
- Right-align device detail dt/dd values consistently
- Fix schedule timeline cards with overflow-x-auto wrappers
2026-03-12 16:49:59 -05:00
6fd03ace16
feat: add comprehensive wireless client tracking and monitoring
Implements real-time wireless client monitoring with historical tracking,
LiveView UI, proactive alerting, and cross-browser e2e tests.

Phase 1: Historical Tracking
- Add TimescaleDB hypertable for wireless_client_readings
- Batch insert client metrics every 60 seconds from DevicePollerWorker
- 90-day retention with compression after 7 days
- Continuous aggregates for hourly (1 year) and daily (5 years) rollups

Phase 2: LiveView UI
- Add wireless tab to device detail page
- Real-time client list with PubSub updates
- Signal strength and SNR badges with 5-level thresholds
- Display MAC, IP, subscriber, TX/RX rates, distance, uptime
- Subscriber matching via device_subscriber_links
- Empty state handling

Phase 3: Proactive Alerting
- WirelessInsightWorker runs every 5 minutes via Oban cron
- 4 insight types with auto-resolution:
  * wireless_signal_weak: < -75 dBm (warning), < -85 dBm (critical)
  * wireless_snr_low: < 15 dB (warning), < 10 dB (critical)
  * wireless_ap_overloaded: > 50 clients (warning), > 75 clients (critical)
  * wireless_client_missing: expected subscribers not connecting
- Hysteresis thresholds prevent alert flapping
- Multi-organization isolation with proper deduplication

Code Quality:
- Refactored reload_current_tab_data to reduce cyclomatic complexity
- Combined double Enum.filter into single pass for efficiency
- Fixed length/1 comparison to use empty list check
- All Credo checks passing

Testing:
- 28 unit tests (ExUnit) - 100% passing
- 15 e2e tests (Playwright) - 100% passing across chromium/firefox/webkit
- Total: 73 tests, all passing

Files changed:
- lib/towerops/workers/wireless_insight_worker.ex (NEW)
- lib/towerops_web/live/device_live/show.ex (wireless tab + refactoring)
- lib/towerops_web/live/device_live/show.html.heex (wireless template)
- lib/towerops/snmp.ex (5 new query functions)
- lib/towerops/gaiia.ex (list_missing_subscribers)
- lib/towerops/preseem/insight.ex (5 new insight types)
- config/runtime.exs (Oban cron schedule)
- test/support/fixtures/snmp_fixtures.ex (NEW)
- test/towerops/workers/wireless_insight_worker_test.exs (NEW)
- test/towerops_web/live/device_live/show_test.exs (9 new tests)
- e2e/tests/wireless-clients.spec.ts (NEW - 15 cross-browser tests)
2026-03-10 09:57:12 -05:00
4e3f732f21
ui: comprehensive button styling audit - convert all text-styled actions to proper buttons
Fixed 10 text-styled action buttons across 7 files:

Agent Management:
- Delete Agent buttons (2x) → danger variant
- View Setup links (already fixed) → secondary variant

Organization Settings:
- Remove Member button → danger variant

Admin Pages:
- Edit Overrides button → secondary variant
- Delete Organization button → danger variant
- Remove IP/CIDR button → danger variant
- Delete User button → danger variant

Device Management:
- Delete Backup button → danger variant

All action buttons now use proper .button component with appropriate
variants (danger for destructive actions, secondary for neutral actions).
This provides consistent visual hierarchy and makes destructive actions
more clearly identifiable.
2026-03-09 15:32:42 -05:00
1c222f8ff5
feat: add capacity insight worker, UI, and reporting views
Add CapacityInsightWorker (every 15 min) that generates critical/warning
insights when backhaul utilization exceeds 90%/75% and auto-resolves
when it drops below 70%.

Add capacity and utilization columns to the device ports tab with
set/clear capacity controls. Add organization-level /capacity page
with summary cards and per-site capacity table. Add capacity summary
card to site show page. Add Capacity link to nav menu.
2026-03-07 14:42:40 -06:00
cc53dd6a64
fix: access interface stats through latest_stat association
The template accessed if_in_octets/if_out_octets directly on the
Interface struct, but these fields live on InterfaceStat. Access
through interface.latest_stat with nil guard to prevent KeyError
when the association is not loaded.
2026-03-06 13:02:21 -06:00
de986bddf6
Prevent Oban polling/monitoring job stacking per device
When the Oban queue backs up, the 60-second uniqueness window expires
and duplicate jobs stack up per device. Switch to period: :infinity so
only one poll/monitor job exists per device at any time. Add replace
option to supersede stale scheduled jobs with updated scheduled_at.
Remove :executing from unique states so self-scheduling works while
the current job runs. Set max_attempts: 1 since retrying stale polls
is pointless.

Also fix all credo --strict issues across the codebase.
2026-02-16 16:37:48 -06:00
6e3db720fd Collapse device page tabs into header row — single line nav 2026-02-16 15:54:42 -06:00
7ec2b2a00a Fix dark mode inconsistencies across all pages
Add missing dark: variant classes to:
- consent_prompt, check_live/form_component: modal overlays
- error pages (404, 500): body background
- marketing_layouts: page background
- home page: pricing card, CTA button, feature card
- totp_enrollment: QR container
- admin audit_live/monitoring_live: badge colors, event borders
- alert_live: acknowledged-by text
- dashboard_live: severity color fallback
- device_live (index, show, form): status text, spinners
- settings_live: checkbox borders
- trace_live: status colors, labels, table headers
2026-02-16 10:31:52 -06:00
2735c1a032 Add onboarding flow for new organizations 2026-02-16 10:14:45 -06:00
866715fdcc Hide MikroTik API/SSH features from UI
Temporarily disable all MikroTik-related UI elements using false guards.
Code is preserved and can be re-enabled by removing the guards.

Hidden: org settings tab/panel, device form config section,
device show backups/timeline tabs, site form config section,
help page nav item.
2026-02-15 17:18:55 -06:00
5041ac8e25 ui: polish auth pages, core components, and visual consistency 2026-02-14 21:11:33 -06:00
02474c529f ui: major redesign - NOC dashboard, consolidated nav, dense tables, flat alerts 2026-02-14 20:15:07 -06:00
8752dfec49 fix: netbox url field type, gaiia ipRange→block, remove unknown webhook log 2026-02-14 17:44:01 -06:00
a3730db579 i18n: add Spanish locale with full translations, language selector, and locale hook 2026-02-14 17:44:01 -06:00
243b773e39 i18n: wrap all user-facing strings in gettext() 2026-02-14 17:44:01 -06:00
9e7ee5099d refactor: fix all credo strict issues, format all code, fix broken routes
- Fix broken route paths in dashboard (/discovery, /subscribers/trace, /config-changes)
- Fix insights empty state settings link (org-scoped route)
- Add underscores to all 86400 literals across 6 files
- Alphabetize aliases in search.ex and agent_channel.ex
- Extract changelog parser helper to reduce nesting
- Extract dashboard impact calculation to reduce nesting
- Refactor agent_channel config change detection (pattern match, extract function)
- Combine double Enum.reject into single call in trace.ex
- Fix line length in trace.ex search query
- Replace length/1 > 0 with != [] in trace_live
- Run mix format on all files
2026-02-13 19:34:40 -06:00
bc128388ba feat: add loading skeletons and page transitions 2026-02-13 19:18:28 -06:00
5a3ede1f71 feat: config change → performance correlation system (Roadmap #2)
- New config_change_events table linking backup diffs to time windows
- ConfigChanges context with record/list functions and date filters
- Auto-detect changed sections from MikroTik config diffs
- Agent channel emits change events after backup creation
- Correlator engine: 2h before / 4h after QoE metric comparison
- Creates suspect_config_change insights on significant degradation
- Config Timeline LiveView with chart data, change list, detail view
- Device page: Config Timeline tab + Recent Config Changes card
- Dashboard: Recent Config Changes section with impact indicators
- Fix pre-existing integrations_live.html.heex scope bug
2026-02-13 17:56:55 -06:00
872bef3512
feat: add 12/24-hour time format setting with consistent timezone display
wire time_format into scope, add settings UI selector, change defaults
to 24h, and replace all user-facing Calendar.strftime calls with
centralized TimeHelpers using the user's timezone and time format.
2026-02-13 15:16:29 -06:00
ce85fb0465
add gaiia subscriber context to device detail pages
Stage 4 of Gaiia integration: when a device is mapped to a Gaiia
inventory item, show a Gaiia tab with inventory details, linked
subscriber info, billing subscriptions, network site, and IP
mismatch indicators.
2026-02-13 10:59:05 -06:00
860fb7c3b6
Merge remote-tracking branch 'origin/main' into feature/preseem-integration
# Conflicts:
#	lib/towerops_web/live/device_live/show.ex
#	lib/towerops_web/live/device_live/show.html.heex
2026-02-13 09:11:45 -06:00
62b8ec7afd
add contextual insights to device preseem tab 2026-02-13 08:58:19 -06:00
59cf53144f
add preseem context and device detail preseem tab 2026-02-12 18:05:26 -06:00
d7741cdc0e
feat: implement unified checks system (Phase 1-4)
This commit implements the unified checks architecture that consolidates
SNMP monitoring with HTTP/TCP/DNS checks under a single "check" abstraction,
enabling consistent graphing, alerting, and management across all check types.

Database Changes:
- Add source_type and source_id to checks table for tracking auto-discovered
  vs manually created checks
- Add value field to check_results for storing numeric sensor readings
- Maintain backward compatibility with existing check_results data

New SNMP Executors:
- SnmpSensorExecutor: Poll sensor OIDs and return formatted values with
  status determination (OK/WARNING/CRITICAL based on limits)
- SnmpInterfaceExecutor: Poll interface stats (bandwidth, packets, errors)
- SnmpProcessorExecutor: Poll CPU/processor usage
- SnmpStorageExecutor: Poll disk/memory usage with percentage calculations

Check Execution Worker:
- CheckExecutorWorker: Unified Oban worker that dispatches to appropriate
  executor based on check_type (snmp_sensor, snmp_interface, http, tcp, etc.)
- Self-schedules next execution with distributed polling offsets
- Records results in check_results TimescaleDB hypertable
- Updates check state (OK/WARNING/CRITICAL/UNKNOWN)

Discovery Integration:
- Auto-creates checks during SNMP discovery for sensors, interfaces,
  processors, and storage
- Links checks to source entities via source_id for data lookup
- Enables/disables checks based on discovery results

UI Enhancements:
- Checks tab on device detail page with grouped display
- FormComponent for adding manual HTTP/TCP/DNS checks
- Empty state with "Run Discovery" prompt
- Check status badges and last checked times

Graphing:
- Update GraphLive to accept check_id parameter
- Query check_results table for time-series data
- Support all check types (SNMP, HTTP response times, etc.)

Testing:
- Comprehensive test suite for SnmpSensorExecutor (5 tests)
- Test suite for CheckExecutorWorker (7 tests)
- Test coverage for discovery check creation (6 tests)
- Remove deprecated monitoring_test.exs testing old API

Bug Fixes:
- Fix SNMP executors reading credentials from correct Device schema fields
  (device.snmp_version instead of device.snmp_device.version)
- Update agent channel test to query MonitoringCheck table directly

Code Quality:
- Extract add_snmp_credentials helper to reduce cyclomatic complexity
- Use map-based lookups for sensor formatting and check type grouping
- Apply pattern matching in dispatcher to reduce complexity
- All credo checks passing with no issues

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-12 16:58:40 -06:00
a61abd836c
fix: cloud poller automatic rebalancing
- create MonitoringCheck schema for the monitoring_checks table, fixing
  silent data loss where ping results were dropped by the wrong schema
- update agent channel and device monitor worker to use new schema
- fix Stats queries to use MonitoringCheck instead of Check schema
- add list_online_cloud_pollers and list_cloud_polled_devices queries
- add CloudLatencyProbeWorker to dispatch cross-agent latency probes
  every 8 hours via PubSub to all online cloud pollers
- scope AgentLatencyEvaluator to cloud pollers only with cloud_only
  filter, lower min_checks (5), wider time window (48h), and
  device-level assignments to avoid changing site/org defaults
- update cron schedule: probes at 0/8/16h, evaluation at 0:30/8:30/16:30
- refactor monitoring.ex and http_executor.ex to fix credo complexity
2026-02-12 15:32:33 -06:00
07a6128877
feat: add checks tab to device detail page (TDD cycle 1)
- Add 'Checks' tab link to device navigation
- Display empty state when no checks configured
- Add tests for tab visibility and empty state
- Fix unused variable warnings in monitoring context
- Remove unused CheckResult alias and module attributes
- Add stub for legacy get_latency_data for backward compatibility

Tests: 2 new tests added, all passing
Following TDD: RED-GREEN cycle verified for each feature
2026-02-12 14:50:14 -06:00
7371ceb942
feat: add automatic network topology inference
Build a rich network topology from SNMP polling data using evidence-based
confidence scoring. LLDP/CDP neighbors, MAC address tables, and ARP data
are combined to infer device links with weighted confidence merging.

- Add DeviceLink and DeviceLinkEvidence schemas for persistent topology
- Implement evidence collectors: LLDP (0.95), CDP (0.95), MAC (0.7), ARP (0.6)
- Add device role inference from sysObjectID/sysDescr patterns
- Hook topology inference into DevicePollerWorker pipeline
- Add stale link cleanup (24h mark stale, 72h delete) via NeighborCleanupWorker
- Update NetworkMapLive with "Added" vs "All Devices" tabs
- Add connected devices section to device detail page
- Add device role selector to device edit form
- Update Cytoscape.js with role-based node shapes/colors and confidence edges
2026-02-12 13:28:01 -06:00
475dea639a
remove agent last_seen_at display from device detail page
the offline badge already communicates agent health status,
so the relative timestamp is redundant.
2026-02-11 15:35:59 -06:00
10d1157ec3
fix agent discovery system OIDs returning no_such_name
gosnmp returns OIDs with leading dots (e.g., ".1.3.6.1.2.1.1.1.0")
but the Replay adapter did exact-match lookups without the dot.
Walks already normalized both sides, so interfaces worked. GETs
did not, breaking all system OID resolution (sysDescr, sysName, etc).
2026-02-11 12:46:44 -06:00
d36fcbe628
fix raw discovery data timestamp to use user's timezone 2026-02-11 12:41:31 -06:00
623fe07081
wip 2026-02-09 12:44:37 -06:00
b12a03b82f
update 2026-02-09 08:47:53 -06:00
7a57f7c9d2
fix: resolve critical sensor discovery pipeline data loss
Critical fixes to sensor discovery and display pipeline:

- Fix float value rejection: Change is_integer guards to is_number in
  vendor.ex, dynamic.ex to accept decimal sensor values (temperature,
  counters, etc.)
- Fix scale factor calculation: Rewrite base.ex divisor calculation
  using pure integer arithmetic to prevent rounding errors
- Add missing sensor type support: Current, power, fan, load, and
  signal quality sensor categories now filtered and assigned in UI
- Refactor resolve_snmp_community to reduce cyclomatic complexity

Impact:
- Sensors with float values (DHCP leases, connection counts, precise
  temperatures) no longer silently dropped before database
- ENTITY-SENSOR-MIB divisors calculated correctly without float errors
- UI coverage increased from ~35% to ~60% of discovered sensor types

Files modified:
- lib/towerops/snmp/profiles/vendors/vendor.ex
- lib/towerops/snmp/profiles/dynamic.ex
- lib/towerops/snmp/profiles/base.ex
- lib/towerops_web/live/device_live/show.ex
- lib/towerops/devices.ex

Documentation: SENSOR_PIPELINE_FIXES.md
2026-02-09 08:32:24 -06:00
b823b5e848
feat: display cloud poller name on device page
Show the specific cloud poller name (e.g., dfw, lon) alongside "Cloud"
when a device is assigned to a cloud poller. Displays as "Cloud (dfw)"
instead of just "Cloud" for better visibility of which poller is being used.

When no agent is assigned, continues to show just "Cloud".
2026-02-08 11:40:58 -06:00
156d9a47bf
UI improvements 2026-02-05 14:57:11 -06:00
6689eb27b4
prevent poller fallback when assigned poller is selected 2026-02-04 16:24:19 -06:00
1a054fd598
make sites optional 2026-02-04 13:05:32 -06:00
e181c17f78
fix: resolve MikroTik sensor values and empty SNMP communities
Fixes three critical issues affecting agent-based SNMP polling:

1. MikroTik gauge sensors incorrectly showing 10x values (223°C instead of 22.3°C)
   - Root cause: get_int_value() rejected zero values, causing mtxrGaugeUnit
     to be treated as nil and bypassing divisor logic
   - Fixed: Accept zero values and apply correct divisor=10 for temp/voltage/current/power

2. Empty SNMP community strings sent to agents causing authentication failures
   - Root cause: Devices with source="device" but null community weren't falling
     back to organization/site inheritance
   - Fixed: Enhanced resolve_snmp_community() to fall back to inheritance chain
     even when source="device" but community is empty

3. Continuous MikroTik API commands sent every 60s instead of once per 24h
   - Root cause: MikroTik jobs built on every poll cycle, not just discovery
   - Fixed: Only build MikroTik jobs during discovery phase

Migrations update existing data to fix incorrect divisor values and community
source tracking. Added comprehensive debug logging to diagnose future issues.
2026-02-02 17:12:36 -06:00
aaf8c38b78
handle mikrotik ssh 2026-02-02 16:42:18 -06:00
f938b263cd
Mikrotik backup and gettext start 2026-02-02 09:11:22 -06:00
7232dab601
live device polling 2026-02-01 13:19:32 -06:00
612bed2dd5
mikrotik version upgrade tracking 2026-02-01 12:35:41 -06:00
fcf3ce154f
Add firmware update indicator to device detail page
- Load available firmware in DeviceLive.Show
- Add firmware_update_available? and format_date helpers
- Display blue indicator banner when newer firmware available
- Show current vs latest version with release date
- Add download link and release notes link
- Support MikroTik initially, extensible to other vendors

Phase 6 (final) of firmware tracking complete. All phases implemented:
 Database schema (firmware_releases, device_firmware_history)
 Version comparison logic (VersionComparator)
 RSS fetching worker (daily Oban cron)
 Firmware context with logging and PubSub
 Version change detection in Discovery
 LiveView UI indicators
2026-02-01 10:49:00 -06:00
480789c3e2 banner dissmiss and mikrotik version and license 2026-01-31 13:07:09 -06:00