- Replace gray->cool-steel, blue/indigo->cerulean, red->sweet-salmon, yellow/amber->wheat
- Dark sidebar: sidebar/footer use cool-steel-800 bg, text lightened for contrast
- ~11,600 color replacements across ~99 files
- Update tests for new color class names
- H6: batch interface stats query in get_site_capacity_summary, replacing
per-interface SELECT with a single grouped query
- H8: explicit expires_at check in MobileAuth and GraphQLAuth plugs as
defense in depth — the query already filters expired rows, but a future
refactor dropping the filter can't quietly re-enable revoked sessions
- H17: Reports LiveView (toggle/delete/run_now) now uses
Reports.get_organization_report/2 to scope by organization_id, fixing
IDOR where a user could manipulate other tenants' reports by ID
- H18: ToweropsWeb.Api.ParamFilter strips identity fields (id,
organization_id, user_id, created_by_id, inserted_at, updated_at) from
user-supplied API params; applied to devices, sites, checks, and
escalation_policies create/update paths to prevent mass-assignment of
tenant ownership fields if a changeset cast list ever drifts
Promoted pure presentation and utility helpers from `defp` to `def @doc false`
across ~20 LiveViews, Oban workers, and sync modules so they're reachable from
unit tests. Refactored several `cond` blocks into idiomatic function heads with
guards. Added ~250 new test cases in new files under test/towerops and
test/towerops_web, including DB-backed tests for CnMaestro.Sync and
AlertNotificationWorker, and removed dead LiveView tab components and
CapacityLive (no callers anywhere in lib/test).
Configured mix.exs test_coverage.ignore_modules to exclude vendored third-party
code (SnmpKit, protobuf-generated Towerops.Agent.*, Absinthe GraphQL types,
Phoenix HTML modules, Inspect protocol impls) from coverage calculations —
these are not our project code.
Coverage: 66.93% → 70.09%. Full suite: 10,127 tests, 0 failures.
- Changed sidebar from fixed to sticky positioning
- Wrapped sidebar and main content in flex container
- Sidebar now sticks to top along with header when scrolling
- Removed unused Ecto.Query import from gps_sync.ex
Credo improvements (17 → 0 remaining):
- Replaced all length/1 checks with empty list comparisons
- Extracted helper functions to reduce nesting depth
- Split complex functions into smaller, testable units
- Applied 'with' statements for clearer control flow
- Refactored high-complexity functions (cyclomatic complexity)
- Files improved: storm_detector, alert_notification_worker,
alert_digest_worker, gps_sync, statistics_sync, device_sync,
site_sync, site_correlation, reports_live, topology,
pagerduty/client, cn_maestro/sync
Reviewed-on: graham/towerops-web#32