diff --git a/docs/architecture/subsystems/storage.md b/docs/architecture/subsystems/storage.md new file mode 100644 index 0000000..5aa40ab --- /dev/null +++ b/docs/architecture/subsystems/storage.md @@ -0,0 +1,51 @@ +# storage + +## Purpose + +The persistence layer. Defines every SQLite table, opens the WAL-mode database, exposes hand-written SQLAlchemy Core queries for the rest of the codebase, and provides the AES-256-CTR file encryption used to seal recordings as `.vge`. It is a library package, not a supervised subsystem process. + +## Key files + +- `vigilar/storage/schema.py` — SQLAlchemy Core `MetaData` and 19 `Table` definitions +- `vigilar/storage/db.py` — engine creation, WAL pragmas, `init_db`, `get_db_path` +- `vigilar/storage/queries.py` — all `insert_*`/`get_*`/`update_*`/`delete_*` helpers +- `vigilar/storage/encryption.py` — AES-256-CTR `encrypt_file` / `decrypt_stream` for `.vge` recordings + +## MQTT topics + +**Subscribes:** none +**Publishes:** none + +## Database tables + +- `cameras` — configured camera registry +- `sensors` — configured sensor registry +- `sensor_states` — current key/value state per sensor +- `events` — canonical event log written by the events processor +- `recordings` — video clip metadata (path, duration, trigger, event_id, starred) +- `system_events` — operator-facing component log (info/alert/critical) +- `arm_state_log` — arm-state FSM transitions +- `alert_log` — one row per alert delivery attempt and outcome +- `push_subscriptions` — VAPID Web Push subscription endpoints +- `pets` — known pets (name, species, breed, training count) +- `pet_sightings` — per-frame pet observations with confidence and crop path +- `wildlife_sightings` — wildlife observations with species, threat level, weather context +- `package_events` — package delivery state machine rows (detected/reminded/collected) +- `pet_training_images` — images staged for pet-ID model retraining +- `pet_rules` — per-pet rule definitions with cooldown and priority +- `face_profiles` — known faces, household flag, visit count +- `face_embeddings` — serialized face vectors linked to a profile +- `visits` — per-visit records for recognized faces +- `timelapse_schedules` — per-camera timelapse generation schedules + +## Depends on + +- Filesystem: SQLite database under `system.data_dir`, AES key at `/etc/vigilar/secrets/storage.key` + +## Consumed by + +- Every other subsystem. Camera encrypts recordings through it, events/alerts/sensors/ups/pets/highlights/presence/web all import `vigilar.storage.queries`. + +## Notes + +Encryption is AES-256 in **CTR mode** (no GCM), so `.vge` files are confidential but **not tamper-evident** — there is no authentication tag and a bit-flip in the ciphertext produces a corresponding bit-flip in the plaintext without detection. The 16-byte IV is prepended to each file and the plaintext is unlinked after encryption. The codebase uses SQLAlchemy Core exclusively — there are no mapped ORM classes. The database is opened in WAL mode so the web process can read while the events processor writes.