fix: untrack .planning/ files and add .superpowers/ to .gitignore
.planning/ files were committed before the gitignore rule was added. Untracked them so local planning docs stay local. Added .superpowers/ to prevent brainstorming artifacts from being pushed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -44,6 +44,7 @@ infrastructure/helm/values-local.yaml
|
||||
|
||||
# Local-only planning and design docs
|
||||
.planning/
|
||||
.superpowers/
|
||||
docs/superpowers/
|
||||
docs/comparison-*.md
|
||||
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
# Requirements: TOD v9.7 — Tower & Site Management
|
||||
|
||||
**Defined:** 2026-03-18
|
||||
**Core Value:** Operators can organize their MikroTik fleet by physical site, see tower-level health with sector/CPE views, and collect full wireless radio statistics — without disrupting the flat-list MSP workflow.
|
||||
|
||||
## v9.7 Requirements
|
||||
|
||||
### Sites
|
||||
|
||||
- [x] **SITE-01**: Operator can create a site with name, coordinates (lat/lng), address, elevation, and notes
|
||||
- [x] **SITE-02**: Operator can edit and delete sites
|
||||
- [x] **SITE-03**: Operator can assign devices to a site (single and bulk assignment)
|
||||
- [x] **SITE-04**: Operator can remove a device from a site (device returns to "unassigned")
|
||||
- [x] **SITE-05**: Devices without a site assignment continue to work normally in all existing views
|
||||
- [x] **SITE-06**: Sites are tenant-scoped — each tenant manages their own sites independently
|
||||
|
||||
### Site Dashboard
|
||||
|
||||
- [x] **DASH-01**: Operator can view a site list page showing all sites with health rollup (device count, online %, alert count)
|
||||
- [x] **DASH-02**: Operator can click into a site to see a device health grid (status, CPU, memory, uptime for all devices at that site)
|
||||
- [x] **DASH-03**: Operator can switch to a sector-centric view within a site dashboard showing APs grouped by sector with connected CPEs, aggregate bandwidth, and signal distribution
|
||||
- [x] **DASH-04**: Site dashboard shows wireless link topology (which CPEs connect to which APs) with signal quality indicators
|
||||
|
||||
### Sectors
|
||||
|
||||
- [x] **SECT-01**: Operator can define sectors within a site (name, optional azimuth/bearing)
|
||||
- [x] **SECT-02**: Operator can assign APs to sectors
|
||||
- [x] **SECT-03**: Sector view shows aggregate client count, bandwidth, and signal statistics per sector
|
||||
|
||||
### Wireless Collection
|
||||
|
||||
- [x] **WRCL-01**: Poller collects per-client registration table data from APs (MAC, signal, CCQ, TX/RX rates, distance, uptime) on a 5-minute cadence
|
||||
- [x] **WRCL-02**: Poller collects per-interface RF stats (noise floor, channel width, TX power, registered client count) via monitor command
|
||||
- [x] **WRCL-03**: Per-client wireless data publishes to a dedicated NATS stream (separate from DEVICE_EVENTS) to prevent stream saturation
|
||||
- [x] **WRCL-04**: Per-client wireless data stores in a dedicated hypertable with 30-day retention (separate from existing wireless_metrics)
|
||||
- [x] **WRCL-05**: Poller handles RouterOS v6/v7 field differences gracefully (CCQ absent in v7 wifi package)
|
||||
- [x] **WRCL-06**: Signal strength parsing handles RouterOS format variations (e.g., `-67@5GHz` suffix)
|
||||
|
||||
### Link Discovery
|
||||
|
||||
- [x] **LINK-01**: Backend auto-discovers AP-CPE relationships by matching registration table MAC addresses against known device interface MACs
|
||||
- [x] **LINK-02**: Link state uses a temporal state machine (discovered -> active -> degraded -> down -> stale) with consecutive-miss threshold to prevent false flapping
|
||||
- [x] **LINK-03**: Wireless links are stored in a materialized table for fast dashboard queries
|
||||
- [x] **LINK-04**: Unmanaged wireless clients (MACs not matching any TOD device) are displayed as "unknown clients" with signal/rate data
|
||||
|
||||
### Wireless UI
|
||||
|
||||
- [x] **WRUI-01**: Device detail page shows a per-station wireless table (connected clients with MAC, signal, CCQ, TX/RX rates, distance, uptime)
|
||||
- [x] **WRUI-02**: Device detail page shows per-interface RF stats (noise floor, channel width, TX power)
|
||||
- [x] **WRUI-03**: Wireless links page shows all discovered AP-CPE relationships with signal quality and link state
|
||||
|
||||
### Signal Trending
|
||||
|
||||
- [x] **TRND-01**: Operator can view per-station signal history charts showing signal strength over time
|
||||
- [x] **TRND-02**: System detects signal degradation trends (e.g., "signal dropped 8dB over 2 weeks")
|
||||
|
||||
### Site Alerting
|
||||
|
||||
- [x] **ALRT-01**: Operator can create site-scoped alert rules (e.g., "alert when >20% of devices at this site go offline")
|
||||
- [x] **ALRT-02**: Operator can create sector-scoped alert rules (e.g., "alert when sector average signal drops below -75dBm")
|
||||
|
||||
## Future Requirements
|
||||
|
||||
### Map View
|
||||
|
||||
- **MAP-01**: Operator can view sites on a geographic map with health-status-colored markers
|
||||
- **MAP-02**: Operator can click a map marker to drill into the site dashboard
|
||||
|
||||
### Advanced Wireless
|
||||
|
||||
- **ADV-01**: Cross-reference wireless anomalies with config change timeline
|
||||
- **ADV-02**: CAPsMAN read-only discovery (discover CAPsMAN-managed APs and display status)
|
||||
- **ADV-03**: On-demand spectral scan trigger with result display
|
||||
|
||||
### Config Restore (deferred from v9.6)
|
||||
|
||||
- **REST-01**: User can restore a config snapshot to a router via SSH
|
||||
- **REST-02**: Restore confirmation dialog with diff preview
|
||||
|
||||
## Out of Scope
|
||||
|
||||
| Feature | Reason |
|
||||
|---------|--------|
|
||||
| Map/geo visualization | Deferred to future milestone — adds tile provider complexity, dashboards deliver value faster |
|
||||
| Config restore via UI | Deferred from v9.6 — still out of scope |
|
||||
| Subscriber/customer management | BSS territory (Sonar/Powercode) — TOD is NMS, not billing |
|
||||
| RF planning / link budget calculator | Dedicated RF planning tools exist — TOD monitors deployed infrastructure |
|
||||
| Automated radio parameter changes | Dangerous in production WISPs — TOD provides visibility, not automation |
|
||||
| Real-time spectrum analyzer | Requires continuous high-frequency polling — offer on-demand scan instead (future) |
|
||||
| CAPsMAN configuration management | Complex and version-sensitive — read-only discovery deferred |
|
||||
| Spectral scan during automated polling | Takes interface offline (destructive) — never auto-poll |
|
||||
|
||||
## Traceability
|
||||
|
||||
| Requirement | Phase | Status |
|
||||
|-------------|-------|--------|
|
||||
| SITE-01 | Phase 11 | Complete |
|
||||
| SITE-02 | Phase 11 | Complete |
|
||||
| SITE-03 | Phase 11 | Complete |
|
||||
| SITE-04 | Phase 11 | Complete |
|
||||
| SITE-05 | Phase 11 | Complete |
|
||||
| SITE-06 | Phase 11 | Complete |
|
||||
| DASH-01 | Phase 11 | Complete |
|
||||
| DASH-02 | Phase 14 | Complete |
|
||||
| DASH-03 | Phase 14 | Complete |
|
||||
| DASH-04 | Phase 14 | Complete |
|
||||
| SECT-01 | Phase 14 | Complete |
|
||||
| SECT-02 | Phase 14 | Complete |
|
||||
| SECT-03 | Phase 14 | Complete |
|
||||
| WRCL-01 | Phase 12 | Complete |
|
||||
| WRCL-02 | Phase 12 | Complete |
|
||||
| WRCL-03 | Phase 12 | Complete |
|
||||
| WRCL-04 | Phase 12 | Complete |
|
||||
| WRCL-05 | Phase 12 | Complete |
|
||||
| WRCL-06 | Phase 12 | Complete |
|
||||
| LINK-01 | Phase 13 | Complete |
|
||||
| LINK-02 | Phase 13 | Complete |
|
||||
| LINK-03 | Phase 13 | Complete |
|
||||
| LINK-04 | Phase 13 | Complete |
|
||||
| WRUI-01 | Phase 14 | Complete |
|
||||
| WRUI-02 | Phase 14 | Complete |
|
||||
| WRUI-03 | Phase 14 | Complete |
|
||||
| TRND-01 | Phase 15 | Complete |
|
||||
| TRND-02 | Phase 15 | Complete |
|
||||
| ALRT-01 | Phase 15 | Complete |
|
||||
| ALRT-02 | Phase 15 | Complete |
|
||||
|
||||
**Coverage:**
|
||||
- v9.7 requirements: 30 total
|
||||
- Mapped to phases: 30
|
||||
- Unmapped: 0
|
||||
|
||||
---
|
||||
*Requirements defined: 2026-03-18*
|
||||
*Last updated: 2026-03-18 after roadmap creation*
|
||||
@@ -1,152 +0,0 @@
|
||||
# Roadmap: TOD v9.7 — Tower & Site Management
|
||||
|
||||
## Overview
|
||||
|
||||
v9.7 transforms TOD from a flat device list into a site-aware fleet management platform. The build follows strict data flow dependencies: site data model first (immediately useful, no poller changes), then per-client wireless collection in the Go poller, then backend ingestion and link discovery, then the full site dashboard and wireless UI, and finally signal trending and alerting which require accumulated data. Each phase delivers a coherent, verifiable capability that unblocks the next.
|
||||
|
||||
## Milestones
|
||||
|
||||
- **v9.6 Config Backup** - Phases 1-10 (in progress)
|
||||
- **v9.7 Tower & Site Management** - Phases 11-15 (planned)
|
||||
|
||||
## Phases
|
||||
|
||||
<details>
|
||||
<summary>v9.6 Config Backup & Change Tracking (Phases 1-10)</summary>
|
||||
|
||||
- [x] **Phase 1: Database Schema** - Config snapshot, diff, and change tables with encryption and RLS (completed 2026-03-13)
|
||||
- [x] **Phase 2: Poller Config Collection** - SSH export, normalization, and NATS publishing from Go poller (completed 2026-03-13)
|
||||
- [ ] **Phase 3: Snapshot Ingestion** - Backend NATS subscriber stores snapshots with SHA256 deduplication
|
||||
- [x] **Phase 4: Manual Backup Trigger** - API endpoint for on-demand config backup via poller (completed 2026-03-13)
|
||||
- [x] **Phase 5: Diff Engine** - Unified diff generation and structured change parsing (completed 2026-03-13)
|
||||
- [x] **Phase 6: History API** - REST endpoints for timeline, snapshot view, and diff retrieval with RBAC (completed 2026-03-13)
|
||||
- [x] **Phase 7: Config History UI** - Timeline section on device page with change summaries (completed 2026-03-13)
|
||||
- [ ] **Phase 8: Diff Viewer & Download** - Unified diff display with syntax highlighting and .rsc download
|
||||
- [x] **Phase 9: Retention & Cleanup** - 90-day retention policy with automatic snapshot deletion (completed 2026-03-13)
|
||||
- [x] **Phase 10: Audit & Observability** - Audit event logging for all config backup operations (completed 2026-03-13)
|
||||
|
||||
</details>
|
||||
|
||||
### v9.7 Tower & Site Management (Phases 11-15)
|
||||
|
||||
**Phase Numbering:**
|
||||
- Continues from v9.6 (ended at Phase 10)
|
||||
- Integer phases (11, 12, 13): Planned milestone work
|
||||
- Decimal phases (11.1, 11.2): Urgent insertions (marked with INSERTED)
|
||||
|
||||
- [x] **Phase 11: Site Data Model + Foundation** - Sites CRUD, device assignment, site list with health rollup (completed 2026-03-19)
|
||||
- [x] **Phase 12: Per-Client Wireless Collection** - Poller extension to collect registration table and per-interface RF stats (completed 2026-03-19)
|
||||
- [x] **Phase 13: Link Discovery + Registration Ingestion** - Backend NATS consumer, MAC resolution, AP-CPE link state machine (completed 2026-03-19)
|
||||
- [x] **Phase 14: Site Dashboard + Sector Views + Wireless UI** - Site detail page, sector-centric view, per-station wireless tables (completed 2026-03-19)
|
||||
- [x] **Phase 15: Signal Trending + Site Alerting** - Signal history charts, degradation detection, site/sector alert rules (completed 2026-03-19)
|
||||
|
||||
## Phase Details
|
||||
|
||||
### Phase 11: Site Data Model + Foundation
|
||||
**Goal**: Operators can organize devices by physical site and see a site list with aggregate health — without disrupting the existing flat-list workflow
|
||||
**Depends on**: Nothing (first phase of v9.7; existing v9.6 foundation)
|
||||
**Requirements**: SITE-01, SITE-02, SITE-03, SITE-04, SITE-05, SITE-06, DASH-01
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Operator can create, edit, and delete a site with name, coordinates, address, elevation, and notes
|
||||
2. Operator can assign one or many devices to a site, and remove a device back to "unassigned"
|
||||
3. Site list page shows all tenant sites with device count, online percentage, and alert count
|
||||
4. Devices without a site assignment work identically in all existing views (device list, device detail, remote access, config backup)
|
||||
5. Sites are tenant-scoped — one tenant cannot see or modify another tenant's sites
|
||||
**Plans:** 3/3 plans complete
|
||||
|
||||
Plans:
|
||||
- [ ] 11-01-PLAN.md — Backend data model, migration, service, and REST API for sites
|
||||
- [ ] 11-02-PLAN.md — Frontend site list page, CRUD dialogs, and navigation integration
|
||||
- [ ] 11-03-PLAN.md — Device-to-site assignment UI and fleet table site column
|
||||
|
||||
### Phase 12: Per-Client Wireless Collection
|
||||
**Goal**: The Go poller collects per-client registration table data and per-interface RF stats from all wireless devices, publishing to a dedicated NATS stream
|
||||
**Depends on**: Phase 11 (schema for wireless_registrations hypertable created in Phase 11 migrations)
|
||||
**Requirements**: WRCL-01, WRCL-02, WRCL-03, WRCL-04, WRCL-05, WRCL-06
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Poller collects per-client registration data (MAC, signal, CCQ, TX/RX rates, distance, uptime) from APs on a 5-minute cadence
|
||||
2. Poller collects per-interface RF stats (noise floor, channel width, TX power, client count) via the monitor command
|
||||
3. Per-client data publishes to a dedicated WIRELESS_REGISTRATIONS NATS stream (not DEVICE_EVENTS)
|
||||
4. Per-client data stores in a dedicated hypertable with 30-day retention
|
||||
5. Collection works correctly on both RouterOS v6 (wireless package) and v7 (wifi package) with graceful handling of missing fields
|
||||
**Plans:** 2/2 plans complete
|
||||
|
||||
Plans:
|
||||
- [ ] 12-01-PLAN.md — Go poller per-client registration collector, signal parser, RF monitor, NATS stream and publisher
|
||||
- [ ] 12-02-PLAN.md — Backend wireless_registrations hypertable migration and NATS subscriber
|
||||
|
||||
### Phase 13: Link Discovery + Registration Ingestion
|
||||
**Goal**: Backend automatically discovers AP-CPE relationships from wireless registration data and maintains link state with temporal stability
|
||||
**Depends on**: Phase 12 (per-client data flowing through NATS)
|
||||
**Requirements**: LINK-01, LINK-02, LINK-03, LINK-04
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Backend matches registration table MAC addresses against known device interface MACs to discover AP-CPE links
|
||||
2. Link state follows a temporal state machine (discovered, active, degraded, down, stale) with consecutive-miss threshold to prevent false flapping
|
||||
3. Discovered links are stored in a materialized wireless_links table for fast dashboard queries
|
||||
4. Wireless clients whose MACs do not match any managed device appear as "unknown clients" with their signal and rate data preserved
|
||||
**Plans:** 3/3 plans complete
|
||||
|
||||
Plans:
|
||||
- [ ] 13-01-PLAN.md — Go poller interface collector (/interface/print) and DEVICE_EVENTS publisher
|
||||
- [ ] 13-02-PLAN.md — Backend device_interfaces and wireless_links table migrations with ORM models
|
||||
- [ ] 13-03-PLAN.md — Link discovery subscriber, interface subscriber, link REST API, and app wiring
|
||||
|
||||
### Phase 14: Site Dashboard + Sector Views + Wireless UI
|
||||
**Goal**: Operators can drill into any site to see device health, sector-organized AP/CPE views, and per-station wireless details on device pages
|
||||
**Depends on**: Phase 13 (wireless_links populated, registration data queryable)
|
||||
**Requirements**: DASH-02, DASH-03, DASH-04, SECT-01, SECT-02, SECT-03, WRUI-01, WRUI-02, WRUI-03
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Site dashboard shows a device health grid with status, CPU, memory, and uptime for all devices at the site
|
||||
2. Sector-centric view within the site dashboard groups APs by sector, showing connected CPEs, aggregate bandwidth, and signal distribution
|
||||
3. Site dashboard displays wireless link topology showing which CPEs connect to which APs with signal quality indicators
|
||||
4. Device detail page shows a per-station wireless table (connected clients with MAC, signal, CCQ, TX/RX rates, distance, uptime) and per-interface RF stats
|
||||
5. Operator can define sectors within a site, assign APs to sectors, and view aggregate stats per sector
|
||||
**Plans:** 3/3 plans complete
|
||||
|
||||
Plans:
|
||||
- [ ] 14-01-PLAN.md — Sector backend (migration, model, service, router), site_id device filter, wireless data APIs, frontend API clients
|
||||
- [ ] 14-02-PLAN.md — Device detail wireless station table, RF stats card, standalone wireless links page
|
||||
- [ ] 14-03-PLAN.md — Site dashboard with tabbed views (Health Grid, Sectors, Links)
|
||||
|
||||
### Phase 15: Signal Trending + Site Alerting
|
||||
**Goal**: Operators can track signal quality over time and receive alerts when site or sector conditions degrade
|
||||
**Depends on**: Phase 14 (dashboards exist to surface trends and alerts); requires accumulated wireless data from Phases 12-13
|
||||
**Requirements**: TRND-01, TRND-02, ALRT-01, ALRT-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Operator can view per-station signal history charts showing signal strength over time
|
||||
2. System detects and surfaces signal degradation trends (e.g., "signal dropped 8dB over 2 weeks")
|
||||
3. Operator can create site-scoped alert rules (e.g., "alert when >20% of devices at this site go offline")
|
||||
4. Operator can create sector-scoped alert rules (e.g., "alert when sector average signal drops below -75dBm")
|
||||
**Plans:** 3/3 plans complete
|
||||
|
||||
Plans:
|
||||
- [ ] 15-01-PLAN.md — Backend data model, services, and REST API for site alert rules, alert events, and signal history
|
||||
- [ ] 15-02-PLAN.md — Backend scheduled tasks (trend detection + alert evaluation) and frontend API clients
|
||||
- [ ] 15-03-PLAN.md — Frontend signal history charts, alert rules UI, alert events table, and notification bell
|
||||
|
||||
## Coverage
|
||||
|
||||
| Category | Requirements | Phase | Count |
|
||||
|----------|-------------|-------|-------|
|
||||
| Sites | SITE-01, SITE-02, SITE-03, SITE-04, SITE-05, SITE-06 | 11 | 3/3 | Complete | 2026-03-19 | DASH-01 | 11 | 1 |
|
||||
| Site Dashboard | DASH-02, DASH-03, DASH-04 | 14 | 3/3 | Complete | 2026-03-19 | SECT-01, SECT-02, SECT-03 | 14 | 3 |
|
||||
| Wireless Collection | WRCL-01, WRCL-02, WRCL-03, WRCL-04, WRCL-05, WRCL-06 | 12 | 2/2 | Complete | 2026-03-19 | LINK-01, LINK-02, LINK-03, LINK-04 | 13 | 3/3 | Complete | 2026-03-19 | WRUI-01, WRUI-02, WRUI-03 | 14 | 3 |
|
||||
| Signal Trending | TRND-01, TRND-02 | 15 | 3/3 | Complete | 2026-03-19 | ALRT-01, ALRT-02 | 15 | 2 |
|
||||
| **Total** | | | **30** |
|
||||
|
||||
## Progress
|
||||
|
||||
**Execution Order:**
|
||||
Phases execute in numeric order: 11 -> 11.x -> 12 -> 12.x -> 13 -> 13.x -> 14 -> 14.x -> 15
|
||||
|
||||
| Phase | Plans Complete | Status | Completed |
|
||||
|-------|----------------|--------|-----------|
|
||||
| 11. Site Data Model + Foundation | 0/3 | Planning complete | - |
|
||||
| 12. Per-Client Wireless Collection | 0/2 | Planning complete | - |
|
||||
| 13. Link Discovery + Registration Ingestion | 0/3 | Planning complete | - |
|
||||
| 14. Site Dashboard + Sector Views + Wireless UI | 0/3 | Planning complete | - |
|
||||
| 15. Signal Trending + Site Alerting | 0/3 | Planning complete | - |
|
||||
|
||||
---
|
||||
*Roadmap created: 2026-03-18*
|
||||
*Last updated: 2026-03-19*
|
||||
@@ -1,113 +0,0 @@
|
||||
---
|
||||
gsd_state_version: 1.0
|
||||
milestone: v9.7
|
||||
milestone_name: Tower & Site Management
|
||||
status: unknown
|
||||
stopped_at: Completed 15-03-PLAN.md
|
||||
last_updated: "2026-03-19T12:26:34.674Z"
|
||||
progress:
|
||||
total_phases: 5
|
||||
completed_phases: 5
|
||||
total_plans: 14
|
||||
completed_plans: 14
|
||||
---
|
||||
|
||||
# Project State
|
||||
|
||||
## Project Reference
|
||||
|
||||
See: .planning/PROJECT.md (updated 2026-03-18)
|
||||
|
||||
**Core value:** Operators can monitor, configure, and troubleshoot their entire MikroTik fleet from a single pane of glass
|
||||
**Current focus:** Phase 15 — signal-trending-site-alerting
|
||||
|
||||
## Current Position
|
||||
|
||||
Phase: 15 (signal-trending-site-alerting) — EXECUTING
|
||||
Plan: 2 of 3
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
**Velocity:**
|
||||
|
||||
- Total plans completed: 7
|
||||
- Average duration: 3 min
|
||||
- Total execution time: 0.35 hours
|
||||
|
||||
**By Phase:**
|
||||
|
||||
| Phase | Plans | Total | Avg/Plan |
|
||||
|-------|-------|-------|----------|
|
||||
| 11 | 3 | 12min | 4min |
|
||||
| 12 | 2 | 6min | 3min |
|
||||
| 13 | 2 | 5min | 2.5min |
|
||||
| Phase 13 P01 | 5min | 2 tasks | 4 files |
|
||||
| Phase 13 P03 | 3min | 2 tasks | 6 files |
|
||||
| Phase 14 P01 | 3min | 2 tasks | 15 files |
|
||||
| Phase 14 P02 | 3min | 2 tasks | 9 files |
|
||||
| Phase 14 P03 | 3min | 2 tasks | 6 files |
|
||||
| Phase 15 P02 | 3min | 2 tasks | 4 files |
|
||||
| Phase 15 P01 | 4min | 2 tasks | 10 files |
|
||||
| Phase 15 P03 | 5min | 3 tasks | 9 files |
|
||||
|
||||
## Accumulated Context
|
||||
|
||||
| Phase 11 P01 | 3min | 2 tasks | 9 files |
|
||||
| Phase 11 P02 | 6min | 3 tasks | 8 files |
|
||||
| Phase 11 P03 | 3min | 2 tasks | 5 files |
|
||||
| Phase 12 P01 | 3min | 2 tasks | 6 files |
|
||||
| Phase 12 P02 | 3min | 2 tasks | 3 files |
|
||||
| Phase 13 P01 | 3min | 2 tasks | 6 files |
|
||||
| Phase 13 P02 | 2min | 2 tasks | 5 files |
|
||||
|
||||
### Decisions
|
||||
|
||||
Decisions are logged in PROJECT.md Key Decisions table.
|
||||
|
||||
- Sites must use nullable site_id FK (never mandatory) to preserve flat-list workflow
|
||||
- Per-client wireless data gets its own NATS stream and hypertable (not DEVICE_EVENTS or wireless_metrics)
|
||||
- Link state machine requires 3 consecutive missed polls before marking down (prevents false flapping)
|
||||
- [Phase 11]: alert_count set to 0 with TODO -- alert_events integration deferred to avoid coupling
|
||||
- [Phase 11]: Site detail page kept minimal (info + stats) -- full dashboard deferred to Phase 14
|
||||
- [Phase 11]: Used Dialog for delete confirmation (no AlertDialog component in UI library)
|
||||
- [Phase 11]: Site column placed after Model in fleet table for logical grouping
|
||||
- [Phase 11]: Viewers see site name text, operators get Select dropdown for assignment
|
||||
- [Phase 12]: Used unified tenant_isolation RLS policy with super_admin OR clause (matching codebase convention) instead of separate super_admin_bypass policy
|
||||
- [Phase 12]: WIRELESS_REGISTRATIONS NATS stream uses 30-day retention (vs 24h for DEVICE_EVENTS) for historical client analytics
|
||||
- [Phase 12]: RF monitor collection gated on wireless interface presence to avoid unnecessary API calls
|
||||
- [Phase 13]: No backref on DeviceInterface.device relationship -- link discovery reads interfaces directionally
|
||||
- [Phase 13]: MAC addresses lowercased at collection time for consistent downstream matching
|
||||
- [Phase 13]: InterfaceInfo (identity/link discovery) kept separate from InterfaceStats (traffic counters)
|
||||
- [Phase 13]: Link discovery uses separate durable consumer on WIRELESS_REGISTRATIONS for independent processing
|
||||
- [Phase 13]: Unknown clients query uses DISTINCT ON (mac_address) for most recent data per MAC
|
||||
- [Phase 14]: Sector CRUD nested under sites path (/sites/{sid}/sectors) matching REST hierarchy
|
||||
- [Phase 14]: Device sector assignment uses PUT /devices/{did}/sector with nullable sector_id for set/clear
|
||||
- [Phase 14]: Wireless registration queries join device_interfaces for MAC-to-hostname resolution
|
||||
- [Phase 14]: Shared signalColor helper in separate module for reuse across wireless components
|
||||
- [Phase 14]: Wireless links grouped by AP hostname with nested CPE rows for topology clarity
|
||||
- [Phase 14]: Sidebar Wireless Links href is tenant-scoped for non-super_admin users
|
||||
- [Phase 14]: Used fleet summary API for CPU/memory data since devicesApi.list does not return health metrics
|
||||
- [Phase 15]: Used getattr with fallback for config settings so trend/alert services work before Plan 01 adds them to Settings class
|
||||
- [Phase 15]: Alert events created with consecutive_hits=1 immediately; UI/API filters for >= 2 to confirm (hysteresis pattern)
|
||||
- [Phase 15]: Site alert tables are separate from device-level alert_rules/alert_events (no coupling between systems)
|
||||
- [Phase 15]: Signal history uses TimescaleDB time_bucket with 3 range presets (5min/1h/4h buckets)
|
||||
- [Phase 15]: Alert event count endpoint returns simple JSON for notification bell badge
|
||||
- [Phase 15]: NotificationBell placed in ContextStrip for consistent header integration
|
||||
- [Phase 15]: Expandable chart rows use React.Fragment pattern with per-component state
|
||||
- [Phase 15]: Alert rule type selector is context-aware (sector types when sectorId provided, site types otherwise)
|
||||
|
||||
### Pending Todos
|
||||
|
||||
None yet.
|
||||
|
||||
### Blockers/Concerns
|
||||
|
||||
- OpenBao dev instance loses Transit keys on data wipe — device creds need re-entry
|
||||
- RouterOS 7 WiFi registration-table field names need validation on real hardware (Phase 12)
|
||||
- MAC-to-device resolution data source needs codebase audit (Phase 13)
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-03-19T12:26:34.671Z
|
||||
Stopped at: Completed 15-03-PLAN.md
|
||||
Resume file: None
|
||||
@@ -1,116 +0,0 @@
|
||||
---
|
||||
phase: 11-site-data-model-foundation
|
||||
plan: 02
|
||||
subsystem: ui, frontend
|
||||
tags: [react, tanstack-router, tanstack-query, tailwind, lucide]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 11-site-data-model-foundation plan 01
|
||||
provides: Sites CRUD REST API with health rollup
|
||||
provides:
|
||||
- Site list page with sortable table, search, and CRUD dialogs
|
||||
- Site detail page with health stats summary
|
||||
- sitesApi frontend client with CRUD + device assignment methods
|
||||
- Sites navigation in sidebar and tenant index
|
||||
affects: [11-03, 14-site-dashboard]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "SiteTable follows FleetTable pattern (SortHeader, EmptyState, TableSkeleton)"
|
||||
- "SiteFormDialog uses useMutation with queryClient.invalidateQueries for cache sync"
|
||||
- "Delete confirmation via Dialog component (no separate AlertDialog needed)"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- frontend/src/lib/api.ts (sitesApi section)
|
||||
- frontend/src/components/sites/SiteFormDialog.tsx
|
||||
- frontend/src/components/sites/SiteTable.tsx
|
||||
- frontend/src/routes/_authenticated/tenants/$tenantId/sites/index.tsx
|
||||
- frontend/src/routes/_authenticated/tenants/$tenantId/sites/$siteId.tsx
|
||||
modified:
|
||||
- frontend/src/components/layout/Sidebar.tsx
|
||||
- frontend/src/routes/_authenticated/tenants/$tenantId/index.tsx
|
||||
- frontend/src/routeTree.gen.ts
|
||||
|
||||
key-decisions:
|
||||
- "Used Dialog component for delete confirmation instead of AlertDialog (not present in UI library)"
|
||||
- "Textarea rendered as native element with project styling (no Textarea UI component exists)"
|
||||
- "Site detail page is intentionally minimal -- full dashboard deferred to Phase 14"
|
||||
|
||||
patterns-established:
|
||||
- "Sites components in frontend/src/components/sites/ directory"
|
||||
- "canWrite(user) gates edit/delete actions in table rows"
|
||||
|
||||
requirements-completed: [DASH-01, SITE-01, SITE-02]
|
||||
|
||||
# Metrics
|
||||
duration: 6min
|
||||
completed: 2026-03-19
|
||||
---
|
||||
|
||||
# Phase 11 Plan 02: Frontend Site List and Detail Pages Summary
|
||||
|
||||
**Site list page with sortable table, health rollup columns, CRUD dialogs, delete confirmation, and site detail page with stats cards**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 6 min
|
||||
- **Started:** 2026-03-19T02:41:33Z
|
||||
- **Completed:** 2026-03-19T02:47:05Z
|
||||
- **Tasks:** 3
|
||||
- **Files modified:** 8
|
||||
|
||||
## Accomplishments
|
||||
- sitesApi client with all CRUD methods plus assignDevice, removeDevice, and bulkAssign
|
||||
- Site list page at /tenants/{tenantId}/sites with sortable table, search filter, create/edit dialogs, and delete confirmation
|
||||
- Site detail page at /tenants/{tenantId}/sites/{siteId} with info card and health stats (devices, online, online %, alerts)
|
||||
- Sites navigation integrated into sidebar Fleet section and tenant index page with count card
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Add sitesApi client and SiteFormDialog component** - `3a965e0` (feat)
|
||||
2. **Task 2: Create SiteTable, site list page, and site detail page** - `40f2bcd` (feat)
|
||||
3. **Task 3: Add Sites to sidebar navigation and tenant index page** - `e8c69fb` (feat)
|
||||
|
||||
## Files Created/Modified
|
||||
- `frontend/src/lib/api.ts` - Added SiteResponse, SiteListResponse, SiteCreate, SiteUpdate interfaces and sitesApi client
|
||||
- `frontend/src/components/sites/SiteFormDialog.tsx` - Create/edit site dialog with mutation and cache invalidation
|
||||
- `frontend/src/components/sites/SiteTable.tsx` - Sortable table with delete confirmation, unassigned row, empty state
|
||||
- `frontend/src/routes/_authenticated/tenants/$tenantId/sites/index.tsx` - Site list page route
|
||||
- `frontend/src/routes/_authenticated/tenants/$tenantId/sites/$siteId.tsx` - Site detail page with health stats
|
||||
- `frontend/src/components/layout/Sidebar.tsx` - Added MapPin icon and Sites nav link
|
||||
- `frontend/src/routes/_authenticated/tenants/$tenantId/index.tsx` - Added Sites count card and "Manage sites" link
|
||||
- `frontend/src/routeTree.gen.ts` - Regenerated with new site routes
|
||||
|
||||
## Decisions Made
|
||||
- Used Dialog component for delete confirmation instead of AlertDialog (AlertDialog not present in the project UI library)
|
||||
- Used native textarea element with project Tailwind styling since no Textarea UI component exists
|
||||
- Site detail page kept intentionally minimal (info + stats) -- full site dashboard with device list deferred to Phase 14
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None - plan executed exactly as written.
|
||||
|
||||
## Issues Encountered
|
||||
- Route tree (routeTree.gen.ts) needed regeneration via vite build to register new site routes -- resolved by running `npx vite build`
|
||||
|
||||
## User Setup Required
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
- Site list and detail pages ready for map integration (Plan 03)
|
||||
- Site detail page ready for Phase 14 full dashboard expansion (device list, map, sector views)
|
||||
- Frontend can connect to backend sites API once backend migration 030 is run
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
All created files verified on disk. All 3 task commits (3a965e0, 40f2bcd, e8c69fb) verified in git log.
|
||||
|
||||
---
|
||||
*Phase: 11-site-data-model-foundation*
|
||||
*Completed: 2026-03-19*
|
||||
@@ -1,108 +0,0 @@
|
||||
---
|
||||
phase: 11-site-data-model-foundation
|
||||
plan: 03
|
||||
subsystem: ui, api
|
||||
tags: [react, tanstack-router, tanstack-query, tailwind, lucide, pydantic, sqlalchemy]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 11-site-data-model-foundation plan 01
|
||||
provides: Sites CRUD API with device assignment endpoints
|
||||
- phase: 11-site-data-model-foundation plan 02
|
||||
provides: sitesApi frontend client and site routes
|
||||
provides:
|
||||
- Site column in fleet table with clickable site name links
|
||||
- Multi-select bulk assign devices to sites from fleet list
|
||||
- Site selector dropdown on device detail page (assign/unassign)
|
||||
- DeviceResponse includes site_id and site_name fields (backend + frontend)
|
||||
affects: [14-site-dashboard]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Bulk assign uses dialog with site select and mutation invalidation"
|
||||
- "Multi-select checkboxes with Set<string> state and select-all toggle"
|
||||
|
||||
key-files:
|
||||
created: []
|
||||
modified:
|
||||
- backend/app/schemas/device.py
|
||||
- backend/app/services/device.py
|
||||
- frontend/src/lib/api.ts
|
||||
- frontend/src/components/fleet/FleetTable.tsx
|
||||
- frontend/src/routes/_authenticated/tenants/$tenantId/devices/$deviceId.tsx
|
||||
|
||||
key-decisions:
|
||||
- "Site column placed after Model column for logical grouping of device identity fields"
|
||||
- "Viewers see site name as text, operators get a Select dropdown for assignment"
|
||||
|
||||
patterns-established:
|
||||
- "Multi-select pattern: checkbox column + Set<string> state + action bar with bulk operation"
|
||||
|
||||
requirements-completed: [SITE-03, SITE-04, SITE-05]
|
||||
|
||||
# Metrics
|
||||
duration: 3min
|
||||
completed: 2026-03-19
|
||||
---
|
||||
|
||||
# Phase 11 Plan 03: Device-Site Assignment UI Summary
|
||||
|
||||
**Site column in fleet table with multi-select bulk assign, site selector on device detail, and DeviceResponse site fields**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 3 min
|
||||
- **Started:** 2026-03-19T02:49:59Z
|
||||
- **Completed:** 2026-03-19T02:53:16Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 5
|
||||
|
||||
## Accomplishments
|
||||
- DeviceResponse now includes site_id and site_name on backend and frontend
|
||||
- Fleet table has checkbox column for multi-select with bulk "Assign to site" action
|
||||
- Fleet table has Site column showing clickable site name links (or "--" for unassigned)
|
||||
- Device detail page has site selector dropdown for assign/change/remove site
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Add site_id and site_name to DeviceResponse** - `ddb2b3e` (feat)
|
||||
2. **Task 2: Add Site column, multi-select bulk assign, and site selector** - `98e328c` (feat)
|
||||
|
||||
## Files Created/Modified
|
||||
- `backend/app/schemas/device.py` - Added site_id and site_name optional fields to DeviceResponse
|
||||
- `backend/app/services/device.py` - Added site fields to _build_device_response, selectinload(Device.site) to eager loading
|
||||
- `frontend/src/lib/api.ts` - Added site_id and site_name to DeviceResponse interface
|
||||
- `frontend/src/components/fleet/FleetTable.tsx` - Checkbox column, Site column, multi-select state, bulk assign dialog
|
||||
- `frontend/src/routes/_authenticated/tenants/$tenantId/devices/$deviceId.tsx` - Site selector dropdown with assign/unassign mutation
|
||||
|
||||
## Decisions Made
|
||||
- Site column placed after Model column for logical grouping of device identity fields
|
||||
- Viewers see site name as plain text; operators get a Select dropdown for changing assignment
|
||||
- Bulk assign uses a Dialog component with site selector and mutation pattern
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None - plan executed exactly as written.
|
||||
|
||||
## Issues Encountered
|
||||
None
|
||||
|
||||
## User Setup Required
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
- Device-site relationship fully wired end-to-end (backend model, API, frontend views)
|
||||
- Site detail page ready for Phase 14 dashboard expansion with device list
|
||||
- All site management features operational: CRUD, assign, unassign, bulk assign
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
All 5 modified files verified on disk. Both task commits (ddb2b3e, 98e328c) verified in git log.
|
||||
|
||||
---
|
||||
*Phase: 11-site-data-model-foundation*
|
||||
*Completed: 2026-03-19*
|
||||
@@ -1,117 +0,0 @@
|
||||
---
|
||||
phase: 13-link-discovery-registration-ingestion
|
||||
plan: 01
|
||||
subsystem: poller
|
||||
tags: [routeros, nats, interfaces, mac-address, link-discovery, go]
|
||||
|
||||
requires:
|
||||
- phase: 12-wireless-registration-collection
|
||||
provides: "NATS publisher pattern, WIRELESS_REGISTRATIONS stream, withTimeout wrapper"
|
||||
provides:
|
||||
- "InterfaceInfo struct with name, MAC, type, running fields"
|
||||
- "CollectInterfaceInfo function for RouterOS /interface/print"
|
||||
- "DeviceInterfaceEvent NATS publisher on device.interfaces.{device_id}"
|
||||
- "DEVICE_EVENTS stream includes device.interfaces.> subject"
|
||||
affects: [13-link-discovery-registration-ingestion, link-state-machine, topology-map]
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [interface-identity-collector, mac-normalization]
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- poller/internal/device/interfaces.go
|
||||
- poller/internal/device/interfaces_test.go
|
||||
modified:
|
||||
- poller/internal/bus/publisher.go
|
||||
- poller/internal/poller/worker.go
|
||||
|
||||
key-decisions:
|
||||
- "MAC addresses lowercased at collection time for consistent downstream matching"
|
||||
- "Entries without mac-address skipped (loopback, bridge without MAC)"
|
||||
- "Interface info collected separately from traffic counters (InterfaceInfo vs InterfaceStats)"
|
||||
|
||||
patterns-established:
|
||||
- "MAC normalization: all MAC addresses lowercased at the collection layer before publishing"
|
||||
- "InterfaceInfo vs InterfaceStats: identity data (link discovery) separate from traffic counters (metrics)"
|
||||
|
||||
requirements-completed: [LINK-01]
|
||||
|
||||
duration: 5min
|
||||
completed: 2026-03-19
|
||||
---
|
||||
|
||||
# Phase 13 Plan 01: Interface Info Collector Summary
|
||||
|
||||
**Go poller InterfaceInfo collector publishing MAC addresses to DEVICE_EVENTS NATS stream for link discovery**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 5 min
|
||||
- **Started:** 2026-03-19T11:00:38Z
|
||||
- **Completed:** 2026-03-19T11:06:20Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 4
|
||||
|
||||
## Accomplishments
|
||||
- InterfaceInfo struct and CollectInterfaceInfo function collect name, MAC, type, running from /interface/print
|
||||
- MAC addresses lowercased at collection time for consistent downstream link resolution
|
||||
- DeviceInterfaceEvent publisher sends to device.interfaces.{device_id} on DEVICE_EVENTS stream
|
||||
- Wired into PollDevice cycle after traffic counters, before health metrics
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Create interface info collector with v6/v7 routing** - `4b5bb94` (test) + `6939584` (feat)
|
||||
2. **Task 2: Add DeviceInterfaceEvent publisher, update DEVICE_EVENTS stream, wire into PollDevice** - `397a33a` (feat)
|
||||
|
||||
_Note: Task 1 used TDD with separate test and implementation commits_
|
||||
|
||||
## Files Created/Modified
|
||||
- `poller/internal/device/interfaces.go` - InterfaceInfo struct, CollectInterfaceInfo function, MAC normalization (added alongside existing InterfaceStats)
|
||||
- `poller/internal/device/interfaces_test.go` - Unit tests for struct fields, MAC lowercasing, running bool parsing
|
||||
- `poller/internal/bus/publisher.go` - DeviceInterfaceEvent type, PublishDeviceInterfaces method, device.interfaces.> added to DEVICE_EVENTS stream
|
||||
- `poller/internal/poller/worker.go` - Interface info collection wired into PollDevice after traffic counters
|
||||
|
||||
## Decisions Made
|
||||
- MAC addresses lowercased at collection time (strings.ToLower) so downstream consumers never need to normalize
|
||||
- Entries without mac-address are silently skipped (loopback, bridge without MAC are not useful for link discovery)
|
||||
- InterfaceInfo is a separate type from InterfaceStats -- identity data for link discovery vs traffic counters for metrics
|
||||
- Collection placed after traffic counters, before health metrics in PollDevice to group interface-related work
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 3 - Blocking] Restored InterfaceStats collector overwritten during file creation**
|
||||
- **Found during:** Task 1
|
||||
- **Issue:** Creating interfaces.go overwrote the pre-existing InterfaceStats type and CollectInterfaces function that publisher.go and worker.go depend on
|
||||
- **Fix:** Restored InterfaceStats and CollectInterfaces, appended new InterfaceInfo types below
|
||||
- **Files modified:** poller/internal/device/interfaces.go
|
||||
- **Verification:** go build ./... succeeds
|
||||
- **Committed in:** 6939584 (Task 1 commit)
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 1 auto-fixed (1 blocking)
|
||||
**Impact on plan:** File creation overwrote existing code; restored immediately. No scope creep.
|
||||
|
||||
## Issues Encountered
|
||||
None beyond the deviation noted above.
|
||||
|
||||
## User Setup Required
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
- Interface MAC data now published to NATS on every poll cycle
|
||||
- Backend subscriber (Plan 03) can consume device.interfaces.> to populate device_interfaces table
|
||||
- Link discovery (Plan 02) can match registration MACs against interface MACs for topology resolution
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
All 4 files verified present. All 3 commits verified in git log.
|
||||
|
||||
---
|
||||
*Phase: 13-link-discovery-registration-ingestion*
|
||||
*Completed: 2026-03-19*
|
||||
@@ -1,95 +0,0 @@
|
||||
---
|
||||
phase: 13-link-discovery-registration-ingestion
|
||||
plan: 02
|
||||
subsystem: database
|
||||
tags: [alembic, sqlalchemy, rls, wireless-links, device-interfaces, postgres]
|
||||
|
||||
requires:
|
||||
- phase: 12-wireless-registration-collection
|
||||
provides: wireless_registrations hypertable and NATS stream
|
||||
provides:
|
||||
- device_interfaces table with MAC-to-device resolution index
|
||||
- wireless_links table with link state machine columns
|
||||
- DeviceInterface and WirelessLink ORM models
|
||||
- LinkState enum (discovered/active/degraded/down/stale)
|
||||
affects: [13-link-discovery-registration-ingestion]
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [link state machine with missed_polls counter, MAC-indexed interface table]
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- backend/alembic/versions/032_device_interfaces_table.py
|
||||
- backend/alembic/versions/033_wireless_links_table.py
|
||||
- backend/app/models/device_interface.py
|
||||
- backend/app/models/wireless_link.py
|
||||
modified:
|
||||
- backend/app/models/__init__.py
|
||||
|
||||
key-decisions:
|
||||
- "No backref on DeviceInterface.device relationship -- link discovery reads interfaces, does not navigate from Device to interfaces"
|
||||
|
||||
patterns-established:
|
||||
- "LinkState enum: discovered -> active -> degraded -> down -> stale state machine for wireless link health"
|
||||
- "MAC-indexed interface table pattern for cross-device MAC resolution"
|
||||
|
||||
requirements-completed: [LINK-02, LINK-03]
|
||||
|
||||
duration: 2min
|
||||
completed: 2026-03-19
|
||||
---
|
||||
|
||||
# Phase 13 Plan 02: Database Schema Summary
|
||||
|
||||
**Alembic migrations and SQLAlchemy models for device_interfaces (MAC resolution) and wireless_links (AP-CPE state tracking) tables with RLS**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 2 min
|
||||
- **Started:** 2026-03-19T11:00:46Z
|
||||
- **Completed:** 2026-03-19T11:02:22Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 5
|
||||
|
||||
## Accomplishments
|
||||
- device_interfaces table with MAC index for link discovery MAC-to-device resolution
|
||||
- wireless_links table with state machine columns (state, missed_polls) for AP-CPE tracking
|
||||
- Both tables have tenant isolation RLS matching codebase convention
|
||||
- DeviceInterface and WirelessLink models registered in app.models with LinkState enum
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Create device_interfaces table migration and ORM model** - `7147b15` (feat)
|
||||
2. **Task 2: Create wireless_links table migration, ORM model, and register both models** - `a71df2a` (feat)
|
||||
|
||||
## Files Created/Modified
|
||||
- `backend/alembic/versions/032_device_interfaces_table.py` - device_interfaces table with RLS, MAC index, unique(device_id, name)
|
||||
- `backend/alembic/versions/033_wireless_links_table.py` - wireless_links table with state machine, missed_polls, 4 indexes, RLS
|
||||
- `backend/app/models/device_interface.py` - DeviceInterface ORM model with device relationship
|
||||
- `backend/app/models/wireless_link.py` - WirelessLink ORM model with LinkState enum, ap_device/cpe_device relationships
|
||||
- `backend/app/models/__init__.py` - Added DeviceInterface, WirelessLink, LinkState to model registry
|
||||
|
||||
## Decisions Made
|
||||
- No backref on DeviceInterface.device relationship -- link discovery reads interfaces directionally, no need to navigate from Device to its interfaces via ORM
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None - plan executed exactly as written.
|
||||
|
||||
## Issues Encountered
|
||||
None
|
||||
|
||||
## User Setup Required
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
- device_interfaces and wireless_links tables ready for Plan 03's link discovery subscriber
|
||||
- LinkState enum available for state machine logic in the NATS subscriber
|
||||
- MAC index on device_interfaces enables efficient MAC-to-device lookups
|
||||
|
||||
---
|
||||
*Phase: 13-link-discovery-registration-ingestion*
|
||||
*Completed: 2026-03-19*
|
||||
@@ -1,126 +0,0 @@
|
||||
---
|
||||
phase: 14-site-dashboard-sector-views-wireless-ui
|
||||
plan: 03
|
||||
subsystem: ui
|
||||
tags: [react, tanstack-query, tailwind, site-dashboard, sectors, wireless]
|
||||
|
||||
requires:
|
||||
- phase: 14-site-dashboard-sector-views-wireless-ui
|
||||
provides: sectorsApi, wirelessApi, devicesApi with site_id filter, WirelessLinksTable with siteId prop, signalColor helper
|
||||
provides:
|
||||
- Tabbed site dashboard with Health Grid, Sectors, and Links views
|
||||
- SiteHealthGrid component with device status cards, CPU/memory bars, uptime
|
||||
- SiteSectorView with collapsible sector sections, AP cards, CPE lists, aggregate stats, sector assignment
|
||||
- SectorFormDialog for create/edit sectors
|
||||
- SiteLinksTab wrapping WirelessLinksTable with site filtering
|
||||
affects: [site-management, fleet-views]
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- useState-based tab switching consistent with device detail page pattern
|
||||
- Fleet summary data merged with device list for CPU/memory metrics on health grid
|
||||
- Collapsible sector sections with inline aggregate stats (client count, avg signal, link count)
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- frontend/src/components/sites/SiteHealthGrid.tsx
|
||||
- frontend/src/components/sites/SiteSectorView.tsx
|
||||
- frontend/src/components/sites/SectorFormDialog.tsx
|
||||
- frontend/src/components/sites/SiteLinksTab.tsx
|
||||
modified:
|
||||
- frontend/src/routes/_authenticated/tenants/$tenantId/sites/$siteId.tsx
|
||||
- frontend/src/lib/api.ts
|
||||
|
||||
key-decisions:
|
||||
- "Used fleet summary API for CPU/memory data since devicesApi.list does not return health metrics"
|
||||
- "Sector assignment dropdown uses sentinel value '__unassigned__' since Radix Select requires string values"
|
||||
|
||||
patterns-established:
|
||||
- "Site dashboard tab pattern: useState with conditional rendering (health/sectors/links)"
|
||||
- "Sector section pattern: collapsible cards with inline aggregate wireless stats"
|
||||
|
||||
requirements-completed: [DASH-02, DASH-03, DASH-04, SECT-03]
|
||||
|
||||
duration: 3min
|
||||
completed: 2026-03-19
|
||||
---
|
||||
|
||||
# Phase 14 Plan 03: Site Dashboard Integration Summary
|
||||
|
||||
**Tabbed site dashboard with device health grid, sector-organized AP/CPE view with aggregate wireless stats, and site-filtered wireless links**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 3 min
|
||||
- **Started:** 2026-03-19T11:50:42Z
|
||||
- **Completed:** 2026-03-19T11:54:14Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 6
|
||||
|
||||
## Accomplishments
|
||||
- Site detail page upgraded from placeholder to full tabbed dashboard with three views
|
||||
- Health Grid shows per-device cards with status dots, CPU/memory progress bars, and uptime
|
||||
- Sector View groups APs by sector with collapsible sections, connected CPE lists, aggregate stats, and sector assignment dropdown
|
||||
- Operators can create, edit, and delete sectors; reassign devices between sectors
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Create SiteHealthGrid, SectorFormDialog, SiteSectorView, and SiteLinksTab components** - `d89233b` (feat)
|
||||
2. **Task 2: Replace site detail page placeholder with tabbed dashboard** - `a9db9e4` (feat)
|
||||
|
||||
## Files Created/Modified
|
||||
- `frontend/src/components/sites/SiteHealthGrid.tsx` - Device health grid with status, CPU/memory bars, uptime
|
||||
- `frontend/src/components/sites/SiteSectorView.tsx` - Sector-organized view with AP cards, CPE lists, aggregate stats
|
||||
- `frontend/src/components/sites/SectorFormDialog.tsx` - Sector create/edit dialog following SiteFormDialog pattern
|
||||
- `frontend/src/components/sites/SiteLinksTab.tsx` - Wrapper for WirelessLinksTable with siteId filtering
|
||||
- `frontend/src/routes/_authenticated/tenants/$tenantId/sites/$siteId.tsx` - Tabbed dashboard replacing placeholder
|
||||
- `frontend/src/lib/api.ts` - Added sector_id/sector_name to DeviceResponse, site_id/sector_id to DeviceListParams
|
||||
|
||||
## Decisions Made
|
||||
- Used fleet summary API for CPU/memory data since devicesApi.list does not return health metrics
|
||||
- Sector assignment dropdown uses sentinel value '__unassigned__' since Radix Select requires string values
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 3 - Blocking] Added sector_id and sector_name to DeviceResponse type**
|
||||
- **Found during:** Task 1 (SiteSectorView needs sector_id to group devices)
|
||||
- **Issue:** Backend returns sector_id and sector_name on devices but frontend TypeScript type was missing them
|
||||
- **Fix:** Added sector_id and sector_name to DeviceResponse interface
|
||||
- **Files modified:** frontend/src/lib/api.ts
|
||||
- **Verification:** TypeScript type matches backend schema
|
||||
- **Committed in:** d89233b (Task 1 commit)
|
||||
|
||||
**2. [Rule 3 - Blocking] Added site_id and sector_id to DeviceListParams**
|
||||
- **Found during:** Task 1 (SiteHealthGrid needs to filter devices by site)
|
||||
- **Issue:** DeviceListParams missing site_id/sector_id even though backend accepts them
|
||||
- **Fix:** Added site_id and sector_id to DeviceListParams interface
|
||||
- **Files modified:** frontend/src/lib/api.ts
|
||||
- **Verification:** devicesApi.list now accepts site_id filter parameter
|
||||
- **Committed in:** d89233b (Task 1 commit)
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 2 auto-fixed (2 blocking)
|
||||
**Impact on plan:** Both fixes necessary for type correctness. Plan 01 added these backend fields but the frontend types were not updated to match.
|
||||
|
||||
## Issues Encountered
|
||||
None
|
||||
|
||||
## User Setup Required
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
- Phase 14 complete: all three plans delivered
|
||||
- Site dashboard fully functional with health grid, sector management, and wireless links
|
||||
- Foundation ready for future enhancements (real-time updates, alert integration)
|
||||
|
||||
---
|
||||
*Phase: 14-site-dashboard-sector-views-wireless-ui*
|
||||
*Completed: 2026-03-19*
|
||||
|
||||
## Self-Check: PASSED
|
||||
@@ -1,100 +0,0 @@
|
||||
---
|
||||
phase: 15-signal-trending-site-alerting
|
||||
plan: 02
|
||||
subsystem: api
|
||||
tags: [asyncio, signal-trending, alerting, typescript, scheduled-tasks]
|
||||
|
||||
requires:
|
||||
- phase: 14-wireless-sector-management
|
||||
provides: wireless_links, sectors, devices with site_id
|
||||
provides:
|
||||
- Hourly signal trend detection comparing 7d vs 14d averages
|
||||
- 5-minute alert rule evaluation with hysteresis for 4 rule types
|
||||
- Frontend API clients for signal history, alert rules, and alert events
|
||||
affects: [15-signal-trending-site-alerting]
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [asyncio background task with getattr fallback for config, hysteresis via consecutive_hits counter]
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- backend/app/services/trend_detector.py
|
||||
- backend/app/services/alert_evaluator_site.py
|
||||
modified:
|
||||
- backend/app/main.py
|
||||
- frontend/src/lib/api.ts
|
||||
|
||||
key-decisions:
|
||||
- "Used getattr with fallback for config settings (SIGNAL_DEGRADATION_THRESHOLD_DB etc.) so services work before Plan 01 adds them to Settings class"
|
||||
- "Trend detector derives site_id via JOIN on devices table since wireless_links has no direct site_id column"
|
||||
- "Alert events created with consecutive_hits=1 immediately; UI/API filters for >= 2 to show confirmed alerts"
|
||||
- "Severity auto-assigned: critical for device_offline rules, warning for sector signal/client rules"
|
||||
|
||||
patterns-established:
|
||||
- "Hysteresis pattern: create event at hits=1, confirm at hits>=2, auto-resolve when condition clears"
|
||||
- "Scheduled task pattern: getattr config fallback, AdminAsyncSessionLocal, raw SQL for cross-tenant system queries"
|
||||
|
||||
requirements-completed: [TRND-02, ALRT-01, ALRT-02]
|
||||
|
||||
duration: 3min
|
||||
completed: 2026-03-19
|
||||
---
|
||||
|
||||
# Phase 15 Plan 02: Signal Trending & Alert Evaluation Summary
|
||||
|
||||
**Hourly trend detection comparing 7d/14d signal averages plus 5-minute alert rule evaluation with hysteresis across 4 rule types, with TypeScript API clients for Plan 03 UI**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 3 min
|
||||
- **Started:** 2026-03-19T12:14:19Z
|
||||
- **Completed:** 2026-03-19T12:17:00Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 4
|
||||
|
||||
## Accomplishments
|
||||
- Trend detector scans active/degraded wireless links hourly, creates signal_degradation alerts when 7d avg drops 5+ dB from 14d baseline
|
||||
- Alert evaluator checks all enabled rules every 5 minutes with hysteresis (2 consecutive hits before confirming)
|
||||
- Both tasks wired into lifespan with non-fatal startup and graceful cancel on shutdown
|
||||
- Three frontend API clients (signalHistoryApi, alertRulesApi, alertEventsApi) ready for Plan 03 UI components
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Create trend detection and alert evaluation scheduled tasks** - `c3ae48e` (feat)
|
||||
2. **Task 2: Add frontend TypeScript API clients** - `b9a92f3` (feat)
|
||||
|
||||
## Files Created/Modified
|
||||
- `backend/app/services/trend_detector.py` - Hourly signal trend detection loop
|
||||
- `backend/app/services/alert_evaluator_site.py` - 5-minute alert rule evaluation with hysteresis
|
||||
- `backend/app/main.py` - Wired both tasks into lifespan startup/shutdown
|
||||
- `frontend/src/lib/api.ts` - Added signalHistoryApi, alertRulesApi, alertEventsApi clients
|
||||
|
||||
## Decisions Made
|
||||
- Used getattr with fallback for config settings so services work before Plan 01 adds settings to the Settings class
|
||||
- Derived site_id via JOIN on devices table since wireless_links has no direct site_id FK
|
||||
- Alert events created immediately with consecutive_hits=1; confirmed when hits reach 2
|
||||
- Auto-assigned severity: critical for device_offline rules, warning for sector-scoped rules
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None - plan executed exactly as written.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
None.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
- Backend scheduled tasks ready for signal degradation detection and alert evaluation
|
||||
- Frontend API clients ready for Plan 03 UI components (signal charts, alert rules tab, notification bell)
|
||||
- Depends on Plan 01 completing first (database tables, config settings, router endpoints)
|
||||
|
||||
---
|
||||
*Phase: 15-signal-trending-site-alerting*
|
||||
*Completed: 2026-03-19*
|
||||
Reference in New Issue
Block a user