ADR-024: AI-Assisted Import as Opt-In Third-Party Egress
Status: Accepted Date: 2026-10-13
Context
Photo import uses AI providers (src/infrastructure/ai/): OpenAI, Anthropic, Google Gemini, or a user-configured OpenAI-compatible endpoint. Recipe photos go to the chosen provider with the user’s own API key. This is the one place besides sync where user content leaves the device, so it must not weaken the privacy goal.
Decision
- AI import is opt-in and off by default.
- Before the first request to a provider, the PWA shows a consent step naming the provider and the data sent. Consent is stored locally per provider and can be withdrawn in settings.
- API keys travel in request headers only, never in URLs.
- Keys stay on the device and are never synced. A key is saved in local storage so an installed PWA keeps working across restarts. Users can lock a key with a passkey: it is encrypted with a secret from the WebAuthn PRF extension and decrypted into memory only after Face ID, fingerprint, or device PIN, until the app reloads.
- forked operates no AI proxy; requests go straight from the device to the chosen provider.
- Once a key is configured, the PWA may check the connection automatically (on entry, when settings open with a stale result, and when the device comes back online). The check calls only the provider’s model metadata endpoint: it sends the key but no user content and consumes no tokens.
Consequences
- The privacy goal stays honest: off-device processing happens only with explicit consent, and no forked-operated infrastructure sees recipe content or keys.
- Provider availability, pricing, and data handling are outside forked’s control.
- Keys in browser storage remain exposed to XSS, also while a passkey-locked key is unlocked. The strict CSP (ADR-026) is part of the mitigation. The passkey lock protects keys at rest (shared or lost device, storage dumps).
- The consent step adds one interaction before the first AI import.