Tombstone
A personal data command center. Multi-user Google OAuth (narrow gmail.metadata scope: headers, never bodies) discovers every account tied to your Gmail, cross-references breach data against LeakCheck and HaveIBeenPwned, flags forgotten "zombie" accounts, and uses AI agents (Groq Llama 3.3 70B) to draft CCPA / GDPR / DPDP deletion letters. Once approved under explicit Active Consent, letters are sent from the user's own Gmail and tracked against the statutory response window. The whole thing is a mobile-responsive multi-page app, and a no-login public breach checker leads onboarding so value comes before the OAuth ask.
Note: Google OAuth is in testing mode (login requires test-user access) - the public breach checker and the /demo product tour work for anyone, no login required.
Architecture
How it works
The home page opens with a no-login breach check: enter any email, tick consent, and it's checked against LeakCheck and HaveIBeenPwned with a per-breach risk score - real value before any OAuth ask, with Gmail offered as an upgrade. Plain-language privacy promises (headers only, never bodies; disconnect erases everything) and an expandable preview of Google's exact consent screen sit right on the page, backed by a dedicated /privacy page. The product is a mobile-responsive multi-page app: a marketing site (Home, How it works, About, FAQ, Privacy) plus a server-guarded app (Dashboard, Accounts, To-do, Profile), with a no-login /demo.
Users sign in with Google OAuth (testing mode), granting the narrowest gmail.metadata scope - headers and labels, never message bodies. Refresh and access tokens are encrypted with Fernet (key from TOKEN_ENCRYPTION_KEY) and stored per-user in Postgres - never on disk, never in the cookie, which holds only a non-enumerable UUID user_id. The display name is read locally from the id_token (no extra API call), and logout revokes the token directly with Google.
/api/discover writes a row to a Postgres jobs table and returns immediately. worker.py polls with FOR UPDATE SKIP LOCKED, claims one job at a time, and retries up to 3x on failure. Jobs survive process restarts and redeploys - the core fix over the v1 design, where a daemon-thread scan simply vanished if the process restarted mid-run.
The worker reads only From, Subject, and Date headers - never bodies - through gmail_client.py, the only module allowed to import googleapiclient. A Quick scan caps recent mail (newest-first) to stay inside the access-token lifetime; a Deep scan walks the whole inbox; a Stop button cancels mid-run and keeps what was found. Root-domain merging (bigbasket.in + .com), sending-subdomain collapse (send.grammarly.com → grammarly.com), a 2+ email threshold, and personal/finance/infra exclusions produce a clean list. Re-scans are incremental via a per-scan watermark, filtered client-side because the metadata scope forbids Gmail's q/after: search.
With explicit consent, the user's own email (and only their own) is checked against LeakCheck and cross-referenced with the HaveIBeenPwned breach catalog, cached in a shared Postgres api_cache table (24h TTL, 5-min failure cooldown) so the web and worker processes share one freshness clock. Accounts with no activity in 180+ days (six months) are flagged "zombie"; breached services the user never emailed are injected into the dashboard so nothing slips through.
A single call_llm() wrapper - originally spec'd for the Claude API, swapped to Groq's Llama 3.3 70B behind that one function for a free tier - powers four pipelines: domain classification (batched 25 at a time, cached globally), a 20-minute breach action plan ranked by current risk, deletion letters whose statutes are hardcoded templates (CCPA §1798.105, GDPR Article 17, India's DPDP Section 12, or statute-free generic wording) with the LLM writing only the context paragraph and post-checked so it can never invent a citation, and step-by-step deletion walkthroughs from a vendored JustDelete.me dataset (2,542 services). Every pipeline has a non-AI fallback, so the app degrades gracefully with no API key.
Deletion letters are always written as drafts first - status='draft', consent_given_at NULL, nothing enqueued. Only an explicit "Approve" click stamps the consent timestamp, appends to an immutable audit log, and enqueues a deletion_request job - which the worker refuses to process if consent is missing. Approved letters are then sent from the user's own Gmail (the gmail.send scope is requested only at first send), with an atomic approved -> sending claim that makes duplicate sends impossible across crashes and retries. A periodic job then tracks replies (headers only) against the statutory window (CCPA +45 days, GDPR +1 month) and auto-drafts - never auto-sends - an escalation if it lapses. Data-broker opt-outs and account self-deletion round out the loop.
Technologies
Feedback
Tombstone is actively evolving. If you've tried the demo or have thoughts on the breach-check flow, a couple of minutes here genuinely steers the roadmap.