feat(sfm): add SFM proxy router and event data page

- backend/routers/sfm.py: HTTP proxy to SFM backend (localhost:8200),
  mirrors the SLMM proxy pattern. SFM_BASE_URL env var for docker-compose.
  Catch-all /{path} forwards to SFM root (no /api/ prefix). 60s timeout.

- templates/sfm.html: full SFM dashboard with 5 tabs:
  Events (DB listing, filters by serial/date/false-trigger, flag/unflag FT),
  Units (known serials + stats, filter events by unit),
  Monitor Log (continuous monitoring intervals),
  ACH Sessions (call-home history),
  Live Device (TCP connect, device info cards, start/stop monitoring,
  push project config, download events from device, operation log).

- backend/main.py: import sfm router, include router, add GET /sfm route
- templates/base.html: add SFM Live Data nav link under Seismographs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-13 17:14:36 -04:00
parent 0f582a8a17
commit 2ba20c7809
4 changed files with 1261 additions and 1 deletions
+8 -1
View File
@@ -18,7 +18,7 @@ logging.basicConfig(
logger = logging.getLogger(__name__)
from backend.database import engine, Base, get_db
from backend.routers import roster, units, photos, roster_edit, roster_rename, dashboard, dashboard_tabs, activity, slmm, slm_ui, slm_dashboard, seismo_dashboard, projects, project_locations, scheduler, modem_dashboard
from backend.routers import roster, units, photos, roster_edit, roster_rename, dashboard, dashboard_tabs, activity, slmm, slm_ui, slm_dashboard, seismo_dashboard, sfm, projects, project_locations, scheduler, modem_dashboard
from backend.services.snapshot import emit_status_snapshot
from backend.models import IgnoredUnit
from backend.utils.timezone import get_user_timezone
@@ -97,6 +97,7 @@ app.include_router(slmm.router)
app.include_router(slm_ui.router)
app.include_router(slm_dashboard.router)
app.include_router(seismo_dashboard.router)
app.include_router(sfm.router)
app.include_router(modem_dashboard.router)
from backend.routers import settings
@@ -233,6 +234,12 @@ async def seismographs_page(request: Request):
return templates.TemplateResponse("seismographs.html", {"request": request})
@app.get("/sfm", response_class=HTMLResponse)
async def sfm_page(request: Request):
"""SFM live event data and device control dashboard"""
return templates.TemplateResponse("sfm.html", {"request": request})
@app.get("/modems", response_class=HTMLResponse)
async def modems_page(request: Request):
"""Field modems management dashboard"""