docs(devices): add randomized-MAC retention/prune to discovery spec
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -50,6 +50,7 @@ the Void's existing services "discovered → promote" pattern).
|
|||||||
| Identity | **MAC primary key**; IP a mutable column | Survives DHCP IP changes. |
|
| Identity | **MAC primary key**; IP a mutable column | Survives DHCP IP changes. |
|
||||||
| Review flow | Mirror services `discovered → promote` | New MAC → `status='new'`; owner names/edits → `status='known'`. |
|
| Review flow | Mirror services `discovered → promote` | New MAC → `status='new'`; owner names/edits → `status='known'`. |
|
||||||
| Source of truth | **DB** (`lan_devices`); `devices.json` becomes the one-time migration seed, then removed | Single source of truth. |
|
| Source of truth | **DB** (`lan_devices`); `devices.json` becomes the one-time migration seed, then removed | Single source of truth. |
|
||||||
|
| Randomized-MAC bloat | **Auto-prune unreviewed + absent rows** (randomized >24h, others >14d); keep `known`/`ignored` forever | Rotated randomized MACs never accumulate; the table stays bounded. |
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
@@ -97,10 +98,14 @@ Table `lan_devices`:
|
|||||||
- `listKnown()` (`status='known'`, grouped by `grp`), `listDiscovered()`
|
- `listKnown()` (`status='known'`, grouped by `grp`), `listDiscovered()`
|
||||||
(`status='new'`), `get(mac)`, `update(mac, {name, grp, status, note, flagged})`,
|
(`status='new'`), `get(mac)`, `update(mac, {name, grp, status, note, flagged})`,
|
||||||
`remove(mac)`. (`ignored` devices show in neither.)
|
`remove(mac)`. (`ignored` devices show in neither.)
|
||||||
|
- `prune()` — delete unreviewed + absent rows past their TTL: `status='new' AND
|
||||||
|
present=false AND ((randomized AND last_seen < now()-'24h') OR (NOT randomized
|
||||||
|
AND last_seen < now()-'14d'))`. Never touches `known`/`ignored`.
|
||||||
|
|
||||||
### Cron (`lib/cron/index.js`)
|
### Cron (`lib/cron/index.js`)
|
||||||
Add hourly (`7 * * * *`): `runScan()` → `upsertScan` → `markAbsent`. Wrapped in
|
Add hourly (`7 * * * *`): `runScan()` → `upsertScan` → `markAbsent` → `prune()`.
|
||||||
try/catch — a scan failure logs and never crashes the cron.
|
Wrapped in try/catch — a scan failure logs and never crashes the cron, and
|
||||||
|
`prune()` only runs after a *successful* scan (so a failed scan can't reap rows).
|
||||||
|
|
||||||
### API `lib/api/routes/devices.js` (mount `/api/devices`, owner-gated)
|
### API `lib/api/routes/devices.js` (mount `/api/devices`, owner-gated)
|
||||||
- `GET /` — known devices grouped for the band.
|
- `GET /` — known devices grouped for the band.
|
||||||
@@ -117,6 +122,10 @@ try/catch — a scan failure logs and never crashes the cron.
|
|||||||
- **Discovered review** — a section/panel listing `/api/devices/discovered`, each
|
- **Discovered review** — a section/panel listing `/api/devices/discovered`, each
|
||||||
with an **Add / Edit** form (name + group select + notes) that `PATCH`es to
|
with an **Add / Edit** form (name + group select + notes) that `PATCH`es to
|
||||||
promote; plus inline edit for known devices and an Ignore/Delete action.
|
promote; plus inline edit for known devices and an Ignore/Delete action.
|
||||||
|
- **Randomized devices** get a small "randomized MAC" badge (with a tooltip:
|
||||||
|
naming pins it only until the MAC rotates; disable SSID randomization for
|
||||||
|
stable tracking). A `known` device that's been `present=false` for ≥30d shows
|
||||||
|
an "absent Nd" marker for easy manual cleanup (never auto-deleted).
|
||||||
- Remove `public/devices.json` (superseded by the DB).
|
- Remove `public/devices.json` (superseded by the DB).
|
||||||
|
|
||||||
## Infra setup (one-time, on CT 311)
|
## Infra setup (one-time, on CT 311)
|
||||||
@@ -149,8 +158,9 @@ error and the feature degrades to "no new discoveries" (existing data still show
|
|||||||
## Out of scope (YAGNI)
|
## Out of scope (YAGNI)
|
||||||
- Service/port fingerprinting, SNMP/LLDP topology (that's Scanopy's job).
|
- Service/port fingerprinting, SNMP/LLDP topology (that's Scanopy's job).
|
||||||
- Multi-subnet/VLAN scanning (single `/24`).
|
- Multi-subnet/VLAN scanning (single `/24`).
|
||||||
- Auto-pruning stale `new` devices (revisit only if the queue gets noisy).
|
|
||||||
- Push notifications on new-device discovery.
|
- Push notifications on new-device discovery.
|
||||||
|
- Stable identity for randomized-MAC devices across rotations (not solvable from
|
||||||
|
L2 alone; the user-side fix is disabling MAC randomization for the SSID).
|
||||||
|
|
||||||
## References
|
## References
|
||||||
- Scanopy — github.com/scanopy/scanopy ; scanopy.net (self-hosted discovery/topology, AGPL-3.0).
|
- Scanopy — github.com/scanopy/scanopy ; scanopy.net (self-hosted discovery/topology, AGPL-3.0).
|
||||||
|
|||||||
Reference in New Issue
Block a user