Propose a shared substrate for per-user prefs, contexts, per-key consents, and per-agent state so adding an agent stays a manifest change. Updates CLAUDE.md, README, and architecture docs to reflect the multi-agent pipeline (ADR-0013) and the registry direction. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3.0 KiB
Privacy architecture
Privacy is a Phase 0 feature, not a Phase 5 compliance project. This doc is the minimum.
Principles
- Data minimization. Store only what we need for the tip. Raw task titles stay at Todoist; we store references + computed features. If a feature doesn't lift a metric, its input data doesn't get stored.
- User-visible controls. Every connection shows exactly which scopes we hold and what we've computed. One tap disconnects and revokes.
- Deletion is real. Deleting an account revokes provider tokens, purges credentials immediately, and soft-deletes user data for a 30-day recovery window, then hard-deletes.
- No surprise sharing. Cross-user / collaborative features are opt-in, per category, per integration.
- Encryption in transit and at rest. TLS everywhere; column-level encryption for credentials; disk-level for backups.
Flows
Connect
User taps "Connect Todoist" → consent screen lists: scopes requested, what we store, what we compute, retention, revocation instructions → OAuth → stored credential is immediately testable and shows in /connect.
Disconnect
User taps disconnect → Credential.revoked_at set → provider-side revocation attempted (Todoist: token revocation endpoint) → credential erased on success → credential.revoked event → downstream modules drop associated cursors, caches, derived features for that (user, provider) pair.
Delete account
User taps "Delete account" in settings → hard confirm → User.deleted_at set, all sessions revoked, user.deletion_requested event fanned out → every module processes its portion (credentials revoked + purged; profile scrubbed; tip history anonymized to aggregate stats only or purged, per retention policy; events purged on schedule) → within 24 hours account is non-recoverable operationally; within 30 days all rows are hard-deleted.
Export (Phase 2)
GET /me/export returns a JSON bundle of everything we hold for the user: profile, consents, credentials-metadata (not secrets), events, tip history.
Scope boundaries
Each integration and each agent declares the consent keys it requires (data:todoist, agent:focus-area, ...) in its manifest. The user_consents table is the source of truth (per-key rows, revocation is a revoked_at write — never a delete, so audits stay clean). A revoked consent short-circuits derived-feature computation at the feature store and removes the dependent agent from the orchestrator's eligible set on the next tip. See ADR-0014.
Audit
- Privileged actions (admin-initiated deletions, credential decryption outside the normal refresh path) go to an append-only audit log from Phase 0.
- Per-user access log available via
GET /me/access-log(Phase 2).
Legal surface (Phase 0 minimum)
- Terms of Service + Privacy Policy documents shipped alongside the sign-in page.
- Consent capture on first sign-in, with a versioned ToS/PP hash stored per user.
- Data-subject request inbox (email) wired up before onboarding the first external user.