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,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