Previously the Mem/Disk bars only showed a percentage. Plumbed the
underlying byte totals through the whole stack -- collectors, DB
(with a migration for the already-deployed CT122 instance), API, and
the web tile -- so each card also shows e.g. "19.6/32.0 GB".
Verified end-to-end with a throwaway local instance (seeded snapshot,
logged in, screenshotted the rendered tile).
Note: the SSH-collected hosts (omv, ripper) assume the remote
monitor-readonly.sh script emits raw bytes for MEMLINE/DISK_, matching
Proxmox's convention -- unverified since that script only lives on
those two hosts, not in this repo.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Deployed the new-device feature, checked the live API response
instead of assuming the earlier unit test covered it, and found 65/71
devices marked isNew: true. The notification path was correctly
bootstrap-safe (verified separately), but the UI's isNew check just
tested "first_ever_seen within 24h" with no bootstrap awareness --
and bootstrap timestamps are, correctly, "now", so the whole existing
population qualified on day one.
Added seen_macs.is_bootstrap, set on the seeding call and excluded
from isNew. Migration backfills is_bootstrap=1 for any seen_macs rows
that already existed before this column did (the already-deployed
CT122 instance) -- verified locally against both a fresh DB and a
simulated pre-migration table.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New seen_macs table: permanent, insert-only, MAC-keyed record of the
first time each device was ever seen -- deliberately decoupled from
devices.first_seen (IP-keyed, would false-positive on every DHCP
lease change). Bootstrap-safe: first call seeds the baseline from
whatever's currently on the network without alerting on all 71+
existing devices at once. Verified locally: bootstrap call reports
nothing new, repeat calls with the same MACs report nothing new, one
genuinely new MAC gets reported exactly once.
Pushes a Home Assistant persistent_notification when a new MAC
appears (gated behind HOME_ASSISTANT_TOKEN + homeAssistant.url in
hosts.yaml -- missing config just means no push, detection still
runs). Also surfaced directly in the dashboard as a blue "new" badge
for anything first seen in the last 24h, independent of HA config.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Folded into the existing on-demand Deep check button: queries
Fingerbank's interrogate API with the device's MAC plus the SSDP
SERVER header when deep-check-device.sh finds one, showing the
confidence band alongside the result. Runs directly from the API
container (no host-level access needed, just an outbound HTTPS call),
unlike the SSDP/mDNS steps.
Confirmed via direct testing: without DHCP fingerprint data (which we
structurally don't have, not being the DHCP server), MAC-only queries
often can't get past manufacturer-level confidence -- same info the
free OUI lookup already provides. Documented honestly in
docs/device-discovery.md rather than overselling it. Still worth
having as opt-in enrichment for devices that do expose richer signals.
Gated behind optional FINGERBANK_API_KEY -- missing key, API errors,
or no match all degrade gracefully without affecting the rest of
deep-check's local findings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Conflated CREATE TABLE/INDEX's IF NOT EXISTS support with ALTER
TABLE ADD COLUMN, which SQLite has never supported -- syntax error,
not a version issue (confirmed on 3.49.2). Check pragma table_info
for the column first instead. Verified against both a fresh DB and
one simulating the existing pre-migration production schema, and
confirmed idempotent on a second open.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- OUI: mac-oui-lookup package resolves vendor from the MAC prefix
(computed on read, no storage needed). Already correctly identifies
the LXC host prefix as "Proxmox Server Solutions GmbH" and several
"unknown" devices as "Amazon Technologies Inc." -- likely the Echo
Dots / Ring gear.
- mDNS: discover-devices.sh now runs avahi-resolve per discovered IP
(parallel, bounded 2s timeout per host so one non-mDNS device can't
stall the run), stored in a new devices.mdns_hostname column.
- Manual labels: new device_labels table keyed by MAC (survives DHCP
IP changes), PUT/DELETE /api/devices/:mac/label, inline-editable
Name cell in the dashboard. Deliberately separate from vendor/mDNS
info -- those are shown as an italic *hint* for unlabeled devices,
not treated as "known" until the admin actually confirms one.
- Fixed the Name column's sort comparator to match what's rendered
(name, else vendor/mDNS hint) instead of just the raw name field --
caught while reasoning through what the existing sort test would
actually need to assert once hints appear in the column.
Part of #15 (OUI/mDNS/manual labels done; on-demand deep-check next).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
24h of snapshots were already being retained but never read. Adds a
windowed query (last ~40 samples/host, one query total via
ROW_NUMBER() OVER PARTITION BY, not N+1) embedded in the existing
/api/hosts response, rendered as small hand-rolled SVG sparklines
(cpu/mem/disk overlaid) -- no charting library needed at this scale.
Closes#10.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Runs as a host-level systemd timer on CT122 (scripts/discover-devices.sh)
rather than inside the api container, since real ARP entries live in the
host's network namespace, not Docker's bridge network. See
docs/device-discovery.md for the full writeup, including why literal
passive-only ARP reading was dropped (near-empty result in practice).
API reads the resulting JSON file each poll cycle, cross-references
config/hosts.yaml's knownDevices list by IP, and serves /api/devices.
Dashboard gets a new "Network Devices" table.
Closes#9.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Vertical slice for Phase 1 (v1-dashboard milestone): Proxmox collector,
SQLite storage, local auth, and a dashboard UI showing host/container
status cards. Config-driven collector registry so future data sources
(SSH-based hosts, Zabbix, network discovery) plug in without rewiring.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>