# Secure Local Database

ZoneGaze Matrix owns a shared secure local database for application and plugin data that should not live in renderer `localStorage`.

## Current Implementation

- Contracts live in `flow/contracts/src/secure-local-database.ts`.
- The web/plugin adapter lives in `flow/web/src/storage/secure-local-database-store.ts`.
- The macOS desktop implementation lives in `platforms/desktop/src/secure-local-database.ts`.
- Plugins reach the database through `getSecureLocalDatabaseClient()`, which returns `null` when the host cannot provide secure storage.

The desktop database stores data under Electron `userData` in `secure-local-database/`. The database key is wrapped by Electron `safeStorage`, which uses the OS secure store on macOS. Record values are encrypted with AES-256-GCM before they are written to disk. Namespace and key strings are stored inside the encrypted payload; the plaintext file keeps only hashed lookup ids and encryption metadata.

## Data Model

Each record is addressed by:

- `namespace`: lowercase plugin or product namespace such as `zonegaze.chat`.
- `key`: lowercase record key such as `conversation-1`.
- `value`: finite JSON-compatible data up to 1 MiB.

The API supports:

- `status`
- `get`
- `list`
- `put`
- `delete`
- `clearNamespace`

## Rules For Plugins

- Use this database for sensitive or durable plugin data that should be available inside Matrix on the local device.
- Keep plugin-specific schemas inside the owning plugin. The database is a storage boundary, not a domain model.
- Do not write secrets to `localStorage`.
- Do not store binary blobs directly. Store metadata here and put large files in a plugin-owned local directory.
- Treat a missing database client as a real platform limitation. Browser-only and Android hosts need their own secure storage adapters before claiming encrypted persistence.

## Android Direction

The contract is platform-neutral. Android should implement the same bridge shape with a Keystore-wrapped encryption key and app-private storage. Until that adapter exists, Android callers should receive `null` from the web adapter and keep data in their existing platform storage.
