Md Samad
▶ Live Demo
Privacy / Security Multi-User SaaS AI Agents 5-Person Team

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.

103
Tests Passing
2,542
Deletion Directory
7
Postgres Tables
System Design

Architecture

Logged-out - public breach check + /demo no login · LeakCheck + HIBP · per-breach risk Browser - Google OAuth login gmail.metadata scope · cookie = user_id (UUID) Flask Web App - app.py multi-page · marketing + guarded app · CSRF · rate limiting crypto.py + Google OAuth Fernet-encrypted tokens · key_version Postgres users · accounts · jobs · deletion_requests Worker - worker.py SKIP LOCKED · 3x retry · idempotent send claim Gmail API (metadata-only) Quick/Deep/Stop · root-merge · ≥2-email · watermark LeakCheck + HIBP api_cache · 24h TTL · zombie flag (180d+) AI Tier - Groq Llama 3.3 70B (services/ai_service.py) Classification batched 25 domains -> cache Breach Triage 20-min action plan Deletion Letters CCPA §1798.105 GDPR Art.17 · DPDP Sec.12 Walkthroughs JustDelete.me · 2,542 svc deletion_requests + broker opt-outs draft -> approve (Active Consent) -> queued atomic approved->sending -> sent from own Gmail Response tracking + escalation headers-only reply scan · bounce filter due CCPA+45 / GDPR+1mo · escalation = draft
End-to-End

How it works

1
Check-First Onboarding + Multi-Page App

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.

2
Multi-User Google OAuth + Encrypted Tokens

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.

3
Durable Job Queue - No Daemon Threads

/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.

4
Gmail Account Discovery (Metadata-Only)

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.comgrammarly.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.

5
Breach Cross-Reference

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.

6
AI Tier - Classification, Triage, Letters, Walkthroughs

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.

7
Active Consent + Real Sends (Phase 4, built)

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.

Stack

Technologies

Backend
Python 3.12 Flask psycopg2 / Postgres Alembic
Auth & Crypto
Google OAuth 2.0 (PKCE) cryptography (Fernet) CSRF tokens
Job Queue
Postgres jobs table FOR UPDATE SKIP LOCKED worker.py
AI / LLM
Groq Llama 3.3 70B JSON-mode prompting
Frontend
Tailwind CSS v4 Jinja templates Vanilla JS Lucide icons
Data Sources
Gmail API LeakCheck HaveIBeenPwned JustDelete.me
Testing
pytest pytest-postgresql freezegun responses
Deployment
Render Supabase / Neon Docker (local)