- credentialProfilesApi.list now unwraps {profiles: [...]} wrapper
- CredentialProfilesPage handles both array and wrapped responses
- Renamed privacy_protocol → priv_protocol to match backend schema
- Renamed privacy_passphrase → priv_passphrase to match backend
- Renamed security_name → username (SNMPv3 uses username field)
- Removed security_name from CredentialProfileCreate type
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add missing fields to SNMPProfileResponse (sys_object_id, vendor, category, tenant_id)
- Fix security level values to snake_case (no_auth_no_priv, auth_no_priv, auth_priv) matching backend
- Fix auth protocols to SHA256/SHA384/SHA512 (was MD5/SHA/SHA256)
- Fix privacy protocols to AES128/AES256 (was DES/AES/AES256)
- Apply same protocol fixes to ProfileTestPanel
- Fix BulkAddForm to show both v2c and v3 credential profiles (was hardcoded to v2c)
- Simplify SNMP tab in AddDeviceForm to IP + credential profile + discover-and-add button
- Show guidance link when no SNMP credential profiles exist
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The list endpoint returns {profiles: [...]} but the client expected
a flat array. Now correctly unwraps r.data.profiles.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create CredentialProfilesPage component with full CRUD for RouterOS and SNMP profiles
- Add credentialProfilesApi types and client to api.ts (blocking dependency from 19-01)
- Profile list grouped by type with device count, edit, and delete actions
- Create/edit dialog with conditional fields per credential type
- SNMPv3 form shows auth/privacy fields based on security_level selection
- Delete confirmation with 409 error handling for linked devices
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reverted from MapLibre/PMTiles to Leaflet with nginx-proxied OSM raster
tiles — the MapLibre approach had unresolvable CSP and theme compat
issues. The proxy keeps all browser requests local (no third-party).
Also:
- Add CPE signal strength and parent AP name to fleet summary SQL
and map popup cards (e.g. "Signal: -62 dBm to ap-shady-north")
- Add .dockerignore to exclude 8GB PMTiles and node_modules from
Docker build context (was causing 10+ minute builds)
- Configure mailpit SMTP in dev compose
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace Leaflet + OSM raster tiles with MapLibre GL JS + PMTiles:
- Full continental US vector tiles (8GB PMTiles, zoom 0-14 with overzoom)
- Dark theme via @protomaps/basemaps (official supported path)
- Clustered device markers with status colors (green/yellow/red)
- Popup cards show CPU, memory, wireless client count + avg signal
- Font glyphs proxied through nginx, sprites served locally
- Zero third-party requests from the browser
- Fleet summary SQL now includes wireless client count and avg signal
via LEFT JOIN LATERAL on wireless_links
Also removes alert toast spam and fixes map container height.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- signalHistoryApi: GET signal history with mac_address and range params
- alertRulesApi: full CRUD for site alert rules
- alertEventsApi: list, resolve, and activeCount methods
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SiteHealthGrid shows device cards with status dots, CPU/memory bars, uptime
- SectorFormDialog supports create and edit modes for sectors
- SiteSectorView groups APs by sector with collapsible sections, connected CPE lists, aggregate stats, sector assignment dropdown
- SiteLinksTab wraps WirelessLinksTable with siteId filtering
- Add sector_id and sector_name to DeviceResponse, site_id/sector_id to DeviceListParams
- Add site_id (Optional[UUID]) and site_name (Optional[str]) to backend DeviceResponse schema
- Include site fields in _build_device_response helper
- Add selectinload(Device.site) to _device_with_relations for eager loading
- Add site_id and site_name to frontend DeviceResponse interface
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Sites API client with CRUD, device assignment, and bulk-assign methods
- SiteFormDialog handles create and edit with mutation and cache invalidation
- Form fields: name, address, lat/lng, elevation, notes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add device_id to the audit log API response and frontend type, then
use DeviceLink to make device hostnames navigable in AuditLogTable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix _commit_and_sync infinite recursion
- Use admin session for subnet_index allocation (bypass RLS)
- Auto-set VPN endpoint from CORS_ORIGINS hostname
- Remove server address field from VPN setup UI
- Add DELETE endpoint and button for VPN config removal
- Add wg-reload watcher for reliable config hot-reload via wg syncconf
- Add wg_status.json writer for live peer handshake status in UI
- Per-tenant SNAT for poller-to-device routing through VPN
- Restrict VPN→eth0 forwarding to Docker networks only (block exit node abuse)
- Use 10.10.0.0/16 allowed-address in RouterOS commands
- Fix structlog event= conflict (use audit=True)
- Export backup_scheduler proxy for firmware/upgrade imports
- Add SnapshotResponse interface and getSnapshot API method
- Add deviceName prop to ConfigHistorySection
- Add download handler that fetches snapshot and triggers .rsc file download
- Add Download icon button on each timeline entry with stopPropagation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add DiffResponse interface and getDiff method to configHistoryApi
- Create DiffViewer component with unified diff rendering
- Green highlighting for added lines, red for removed lines
- Blue styling for hunk headers, loading skeleton, error state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ConfigChangeEntry interface and configHistoryApi.list() to api.ts
- Create ConfigHistorySection with timeline, loading skeleton, and empty state
- Poll every 60s via TanStack Query refetchInterval
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>