Files
oO/docs/architecture/privacy.md
alvis d454a0a8bf docs: ADR-0014 — unified Profile model + agent registry
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>
2026-05-05 10:19:07 +00:00

3.0 KiB

Privacy architecture

Privacy is a Phase 0 feature, not a Phase 5 compliance project. This doc is the minimum.

Principles

  1. 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.
  2. User-visible controls. Every connection shows exactly which scopes we hold and what we've computed. One tap disconnects and revokes.
  3. 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.
  4. No surprise sharing. Cross-user / collaborative features are opt-in, per category, per integration.
  5. 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).
  • 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.