The dashboard's host widgets took 18-60 s. Every "latest reading" query (hosts overview, host-agent fleet, host page, vitals, SNMP, MCP get_host) searched plugin_metrics for the newest row per metric. Postgres has no skip scan, so each one read every raw sample in the 7-day window. - plugin_metric_latest: one row per (source, resource, metric). record_metrics upserts it in the same transaction, moving forward only and in sorted key order. Migration 0030 seeds it by stepping the existing index. - Retention drops a latest row once its sample leaves the raw window, so a resource that stopped reporting disappears when its history does, as before. Renames carry it along. - A quiet host keeps its last values, marked stale. A time-bounded query would have shown it as missing. - Vitals sparklines span the 6 h they claim, averaged in SQL to ~120 points, instead of fetching 6 h raw and drawing the last 120 samples. - Dashboard and share-view cells: "Loading…" until the first answer; a 20 s deadline per fetch; "Couldn't load (why)" with Retry now and an automatic retry for cells that don't poll; "as of HH:MM" in the header, and "couldn't refresh · as of" when a refresh fails over shown data. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7.1 KiB
7.1 KiB
Code Map
Quick reference for where key functions, models, and entry points live in the codebase.
Application Bootstrap
| What | File | Function / Class |
|---|---|---|
| App factory | steward/app.py |
create_app() |
| CLI entry point | steward/cli.py |
main() |
| Bootstrap config loading | steward/config.py |
load_bootstrap() |
| Secret key resolution | steward/config.py |
_resolve_secret_key() |
| DB engine init | steward/database.py |
init_db() |
| Core migrations | steward/core/migration_runner.py |
run_core_migrations() |
| Plugin migrations | steward/core/migration_runner.py |
run_plugin_migrations() |
| Core task registration | steward/app.py |
_register_core_tasks() |
| Scheduler loop | steward/core/scheduler.py |
start_scheduler() |
Settings System
| What | File | Function |
|---|---|---|
| All defaults | steward/core/settings.py |
DEFAULTS dict |
| Read a setting | steward/core/settings.py |
get_setting(session, key) |
| Write a setting | steward/core/settings.py |
set_setting(session, key, value) |
| Read all settings | steward/core/settings.py |
get_all_settings(session) |
| Sync load at startup | steward/core/settings.py |
load_settings_sync(db_url) |
| Extract SMTP dict | steward/core/settings.py |
to_smtp_cfg(settings) |
| Extract webhook dict | steward/core/settings.py |
to_webhook_cfg(settings) |
| Extract Ansible dict | steward/core/settings.py |
to_ansible_cfg(settings) |
| Extract plugins dict | steward/core/settings.py |
to_plugins_cfg(settings) |
Plugin System
| What | File | Function |
|---|---|---|
| Plugin loading | steward/core/plugin_manager.py |
load_plugins(app) |
| ScheduledTask dataclass | steward/core/scheduler.py |
ScheduledTask |
| Task runner | steward/core/scheduler.py |
start_scheduler(tasks) |
Alert Pipeline
| What | File | Function |
|---|---|---|
| Write metric + evaluate alerts | steward/core/alerts.py |
record_metric(session, source_module, resource_name, metric_name, value) |
| Init alert pipeline | steward/core/alerts.py |
init_alerts(app) |
| Rule evaluation | steward/core/alerts.py |
_evaluate_rule() (internal) |
| Notification dispatch | steward/core/alerts.py |
_dispatch_notification() (internal) |
| Email + webhook send | steward/core/notifications.py |
dispatch_notifications() |
Monitors
| What | File | Function |
|---|---|---|
| Ping a host | steward/monitors/ping.py |
ping_check(host, session) |
| DNS check a host | steward/monitors/dns.py |
dns_check(host, session) |
| Data cleanup | steward/core/cleanup.py |
run_cleanup(app) |
Auth
| What | File | Function / Class |
|---|---|---|
| Role-based access decorator | steward/auth/middleware.py |
@require_role(UserRole.X) |
| Login / session handling | steward/auth/middleware.py |
login_user(), logout_user() |
| User count (for first-run) | steward/auth/middleware.py |
get_user_count(app) |
Data Models
| Model | File | Table |
|---|---|---|
Host |
steward/models/hosts.py |
hosts |
PingResult |
steward/models/monitors.py |
ping_results |
DnsResult |
steward/models/monitors.py |
dns_results |
AlertRule |
steward/models/alerts.py |
alert_rules |
AlertState |
steward/models/alerts.py |
alert_states |
AlertEvent |
steward/models/alerts.py |
alert_events |
PluginMetric |
steward/models/metrics.py |
plugin_metrics |
PluginMetricLatest |
steward/models/metrics.py |
plugin_metric_latest |
AnsibleRun |
steward/models/ansible.py |
ansible_runs |
User |
steward/models/users.py |
users |
AppSetting |
steward/models/settings.py |
app_settings |
TraefikMetric |
plugins/traefik/models.py |
traefik_metrics |
SQLAlchemy Base |
steward/models/base.py |
(shared declarative base) |
HTTP Routes
| URL pattern | Blueprint | File |
|---|---|---|
/ (dashboard) |
dashboard_bp |
steward/dashboard/routes.py |
/auth/login, /auth/logout |
auth_bp |
steward/auth/routes.py |
/hosts/ |
hosts_bp |
steward/hosts/routes.py |
/ping/, /ping/rows, /ping/settings |
ping_bp |
steward/ping/routes.py |
/dns/, /dns/rows |
dns_bp |
steward/dns/routes.py |
/alerts/ |
alerts_bp |
steward/alerts/routes.py |
/ansible/ |
ansible_bp |
steward/ansible/routes.py |
/settings/ |
settings_bp |
steward/settings/routes.py |
/plugins/traefik/, /plugins/traefik/widget |
traefik_bp |
plugins/traefik/routes.py |
/health |
(inline) | steward/app.py |
Templates
| Template | Purpose |
|---|---|
steward/templates/base.html |
Layout, navigation, full CSS design system |
steward/templates/dashboard/index.html |
Dashboard with stat strip and widget grid |
steward/templates/ping/rows.html |
HTMX fragment: ping pill rows (shared by dashboard and /ping/) |
steward/templates/ping/index.html |
Full /ping/ page |
steward/templates/dns/rows.html |
HTMX fragment: DNS status rows |
steward/templates/dns/index.html |
Full /dns/ page |
plugins/traefik/templates/traefik/widget.html |
HTMX fragment: Traefik dashboard widget |
plugins/traefik/templates/traefik/index.html |
Full Traefik detail page |
Migrations
| Location | Covers |
|---|---|
steward/migrations/versions/ |
Core schema (hosts, users, monitors, alerts, app_settings) |
plugins/traefik/migrations/versions/ |
traefik_metrics table |
alembic.ini |
Alembic config; version_locations lists all migration directories |
MCP server and API tokens
| What | File | Function / Class |
|---|---|---|
Mount /mcp (ASGI dispatch, bearer auth, DB gate) |
steward/mcp/server.py |
mount_mcp(app) |
| Server, role registry, refusals | steward/mcp/server.py |
StewardMCPServer, register_tool(), refusal() |
| Plugin tools and overview findings | steward/mcp/server.py |
register_plugin(name, module) |
| Caller and app inside a tool | steward/mcp/_context.py |
current_caller(), mcp_app() |
| Core tool modules | steward/mcp/tools/ |
register_all(); one module per area |
| Response conventions | steward/mcp/tools/_shape.py |
iso, age_s, bounded, lookback, summarize, pick |
| Audit a write as " via MCP" | steward/mcp/tools/_audit.py |
audit_mcp() |
| "What is wrong now" | steward/mcp/tools/overview.py |
get_overview() |
| Playbooks, runs, schedules, alert actions | steward/mcp/tools/automation.py |
run_playbook(), wait_for_run(), … |
| Monitor validation (forms and tools) | steward/monitors/service.py |
monitor_fields(), build_config() |
| Alert rule / window validation | steward/alerts/service.py |
rule_fields(), window_fields(), acknowledge() |
| Docker and host-agent tools | plugins/docker/mcp_tools.py, plugins/host_agent/mcp_tools.py |
register_tools(), mcp_overview() |
| Token model | steward/models/api_tokens.py |
ApiToken |
| Mint, resolve, revoke tokens | steward/core/api_tokens.py |
create_token(), resolve_token(), revoke_token() |
| Token management page and connect card | steward/ai_access/routes.py, steward/templates/ai_access/ |
ai_access_bp |