courtmitra / HANDOFF.md
Hetansh Waghela
handoff doc
ad76a88
|
Raw
History Blame Contribute Delete
19.4 kB

CourtMitra MissionOS β€” Handoff Document

1. What This Is

CourtMitra is a citizen-side grievance/legal-action autopilot for India. A user describes a problem once (WhatsApp / Telegram / browser); the system turns it into a mission, builds the evidence file, grounds it in Indian law/procedure, picks an official route, drafts + sends approved actions, follows up, and records the outcome.

Architecture

apps/
  web/         β†’ Next.js App Router (port 3000)
  api/         β†’ NestJS + Fastify (port 3001)
  worker/      β†’ Inngest functions (port 3002)
packages/
  domain/      β†’ Pure business logic (no framework imports)
  ports/       β†’ Interfaces only (hexagonal boundary)
  adapters/    β†’ Concrete implementations (LLM, email, channels, etc.)
  db/          β†’ Drizzle schema, migrations, seeds
  contracts/   β†’ Zod schemas (single source of truth)
  prompts/     β†’ Versioned prompt templates
  ui/          β†’ Shared React components
infra/
  docker-compose.yml  β†’ Postgres, Inngest dev server, API, Worker, Web
  Dockerfile.*        β†’ Multi-stage builds

How It Works

  1. Intake: User sends a message via WhatsApp/Telegram/browser β†’ system extracts structured facts via LLM
  2. Evidence: User uploads screenshots/PDFs/audio β†’ vision-LLM or ASR extracts data
  3. Facts: User confirms extracted facts
  4. Legal grounding: pgvector + FTS retrieves relevant Indian law citations
  5. Route plan: LLM generates a step-by-step plan grounded in law
  6. Action preview + consent: System drafts an action, user approves with hash-bound consent
  7. Execution: Resend sends email, portal fills forms, etc.
  8. Follow-up: System tracks replies, schedules reminders
  9. Resolution: Outcome recorded, anonymized ledger entry

2. Environment Variables β€” Complete Reference

Copy infra/.env.example to infra/.env and fill in the values below.

Required (system won't start without these)

Variable Where to Get Notes
DATABASE_URL Auto-set by Docker compose postgres://courtmitra:courtmitra@localhost:5432/courtmitra for local dev
DIRECT_DATABASE_URL Same as DATABASE_URL Used by Drizzle for direct connections
AI_PROVIDER Choose one openrouter (default) or opencode
OPENROUTER_API_KEY https://openrouter.ai/keys Free tier available. Used for LLM calls.
OPENAI_API_KEY https://platform.openai.com/api-keys Required for Whisper ASR (voice notes). Free tier: $5 credit.

Required for Email Sending

Variable Where to Get Notes
RESEND_API_KEY https://resend.com/api-keys Free tier: 100 emails/day, 3000/month
RESEND_FROM Set in Resend dashboard e.g. noreply@yourdomain.com
RESEND_REPLY_DOMAIN Your domain e.g. reply.yourdomain.com β€” used for reply-token threading

Required for Vector Search

Variable Where to Get Notes
QDRANT_URL https://cloud.qdrant.io Free tier: 1GB storage, 1 cluster
QDRANT_API_KEY Qdrant Cloud dashboard Created when you set up the cluster
QDRANT_COLLECTION Just set courtmitra_legal (default)

Optional β€” WhatsApp

Variable Where to Get Notes
WHATSAPP_VERIFY_TOKEN You create this Any random string for webhook verification
WHATSAPP_APP_SECRET Meta Developer Portal For HMAC signature verification
WHATSAPP_ACCESS_TOKEN Meta Developer Portal Permanent token from App Dashboard
WHATSAPP_PHONE_NUMBER_ID Meta Developer Portal Found in WhatsApp > API Setup
WHATSAPP_BUSINESS_ACCOUNT_ID Meta Developer Portal Found in WhatsApp > API Setup

Optional β€” Telegram

Variable Where to Get Notes
TELEGRAM_BOT_TOKEN @BotFather on Telegram /newbot command

Optional β€” Portal Automation

Variable Where to Get Notes
BROWSERBASE_API_KEY https://www.browserbase.com Free tier: 5 hours/month
BROWSERBASE_PROJECT_ID Browserbase dashboard Created when you sign up
ENABLE_PORTAL_AUTOMATION Set to 1 Without this, portal assist degrades to manual packet

Optional β€” eCourts CNR Lookup

Variable Where to Get Notes
SUREPASS_API_KEY https://surepass.io Paid API for Indian court case data

Optional β€” Observability

Variable Where to Get Notes
LANGFUSE_PUBLIC_KEY https://langfuse.com Free tier available
LANGFUSE_SECRET_KEY Langfuse dashboard

Defaults (usually fine as-is)

Variable Default Notes
APP_BASE_URL http://localhost:3000 Web app URL
API_BASE_URL http://localhost:3001 API URL
WEBHOOK_BASE_URL http://localhost:3001 For Resend/WhatsApp webhook callbacks
LOCAL_STORAGE_DIR .storage File storage path (relative to repo root)
INNGEST_BASE_URL http://localhost:8288 Inngest dev server
INNGEST_DEV 1 Enable Inngest dev mode
PII_HASH_SALT dev-salt-change-me For PII hashing
JWT_SECRET dev-jwt-secret-change-me For session tokens
AI_MODEL google/gemini-2.0-flash-exp:free LLM model (free on OpenRouter)
AI_VISION_MODEL google/gemini-2.0-flash-exp:free Vision model for evidence parsing

3. Step-by-Step Setup

Prerequisites

  • Node.js >= 20
  • pnpm 10.20.0+ (corepack enable && corepack prepare pnpm@10 --activate)
  • Docker + Docker Compose
  • Git

Step 1: Clone and Install

git clone <repo-url> hackathon
cd hackathon
pnpm install

Step 2: Start Infrastructure

# Start Postgres + Inngest dev server
pnpm infra:up

# Wait for Postgres to be healthy (check with:)
docker ps
# Should show courtmitra_pg as "healthy"

Step 3: Set Up Environment

cp infra/.env.example infra/.env
# Edit infra/.env with your API keys (see table above)

Minimum viable .env for local dev:

DATABASE_URL=postgres://courtmitra:courtmitra@localhost:5432/courtmitra
DIRECT_DATABASE_URL=postgres://courtmitra:courtmitra@localhost:5432/courtmitra
AI_PROVIDER=openrouter
OPENROUTER_API_KEY=<your-key>
OPENAI_API_KEY=<your-key>
RESEND_API_KEY=<your-key>
RESEND_FROM=noreply@yourdomain.com
RESEND_REPLY_DOMAIN=reply.yourdomain.com
QDRANT_URL=<your-qdrant-cloud-url>
QDRANT_API_KEY=<your-qdrant-key>
QDRANT_COLLECTION=courtmitra_legal
LOCAL_STORAGE_DIR=.storage
INNGEST_BASE_URL=http://localhost:8288
INNGEST_DEV=1
PII_HASH_SALT=dev-salt-change-me
JWT_SECRET=dev-jwt-secret-change-me
AI_MODEL=google/gemini-2.0-flash-exp:free
AI_VISION_MODEL=google/gemini-2.0-flash-exp:free

Step 4: Run Database Migrations

pnpm db:migrate

This creates all 30+ tables including: users, missions, actions, evidence, legal_chunks, followups, social_posts, case_lookups, portal_assist_sessions, etc.

Step 5: Seed Legal Data + Qdrant

# Seed legal sources, chunks, and route rules into Postgres
pnpm db:seed

# Seed Qdrant with embeddings (requires OPENROUTER_API_KEY for embeddings)
npx tsx scripts/seed-qdrant.ts

Step 6: Start the Application

# Start all three services (API, Worker, Web)
pnpm dev

This starts:

Step 7: Verify Everything Works

# Run all checks
pnpm typecheck && pnpm lint && pnpm test && pnpm test:contracts

# Check API health
curl http://localhost:3001/api/admin/health

# Check capabilities (shows what's available/blocked)
curl http://localhost:3001/api/capabilities

4. How to Test the Product End-to-End

Test 1: Create a Mission from Browser

  1. Open http://localhost:3000
  2. Click "Create Mission"
  3. Select issue domain (consumer/payment/cyber_fraud)
  4. Enter title and description
  5. Click create β†’ mission appears on the board

Test 2: Send a Telegram Message (Easiest Channel Test)

  1. Set TELEGRAM_BOT_TOKEN in .env
  2. Restart the API
  3. Send a message to your bot on Telegram
  4. Check http://localhost:3000 β€” mission should appear
  5. Check Inngest dev server at http://localhost:8288 β€” events should flow

Test 3: Full Loop (Email Send)

  1. Create a mission from browser
  2. Confirm facts (click "Confirm Facts" in the mission room)
  3. Wait for route plan generation (check Inngest)
  4. Preview an action β†’ approve with consent
  5. Execute β†’ email sent via Resend
  6. Check proof_state = sent_by_email
  7. Reply to the email β†’ reply ingested β†’ mission advances

Test 4: WhatsApp (Requires Meta App)

  1. Set WhatsApp env vars
  2. Configure webhook URL in Meta Developer Portal: https://your-domain/webhooks/whatsapp
  3. Set verify token to match WHATSAPP_VERIFY_TOKEN
  4. Send a voice note or text message
  5. Mission created, evidence parsed, facts extracted

Test 5: Voice Notes (Requires OPENAI_API_KEY)

  1. Send a voice note via WhatsApp or Telegram
  2. System downloads audio β†’ transcribes via Whisper β†’ includes transcript in intake
  3. Check evidence_parsed_outputs for parserName = "whisper-asr"

5. What's Built (Phase 1 + Phase 2 Modules 1-8)

Phase 1 β€” Complete Automation Loop βœ…

Component Status
Mission CRUD from browser βœ…
WhatsApp webhook + media download βœ…
Telegram webhook + voice βœ…
Intake (LLM extracts structured facts) βœ…
Vision-LLM evidence parsing βœ…
Whisper ASR transcription βœ…
Fact confirmation UI βœ…
Legal grounding (pgvector + FTS + RRF) βœ…
Route plan generation with citations βœ…
Claim verification (literal substring) βœ…
Action preview + consent hash βœ…
Defamation gate βœ…
PII redaction (Aadhaar/PAN/UPI/IFSC/phone/email) βœ…
Email send via Resend βœ…
Reply-token threading βœ…
Reply classification βœ…
Follow-up scheduling βœ…
Resolution capture βœ…
Public case page (private link) βœ…
DPDP data export + erase βœ…
Capability registry βœ…

Phase 2 β€” Modules 1-8 βœ…

Module What's Built
1. Complaint Swarm Entity resolution, swarm clustering, dossier generation, opt-in with consent
2. ASR / Voice Notes Whisper API transcription, WhatsApp audio download, Telegram voice, PII redaction
3. Indic Translation LLM-based language detection + translation, preferredLanguage on users, localized_texts table
4. Hybrid RAG Qdrant Cloud adapter (dense vectors + Postgres FTS + RRF), seed script
5. Portal Automation Playwright adapter, portal_assist_sessions, consent gate, receipt capture, degradation
6. Company Resolver Organizations, resolver threads, domain verification, masked case view
7. Social Publishing Social accounts/posts tables, copy-ready fallback, social card image generator
8. eCourts / CNR Surepass API adapter, case_lookups table, hearing reminder scheduling

Phase 2 β€” Modules 9-11 ❌ (Not Built)

Module What's Needed
9. Intermediary Compliance Takedown requests table, Grievance Officer contact, IT Rules 2021 timelines
10. AI Public Account @CourtMitraWatch β€” requires modules 7+9, legal review
11. Advanced Ledger Materialized views, route-success rates, repeat-offender clusters

6. Known Issues / Limitations

Architecture

  • No auth system β€” browser missions use a hardcoded "Demo User". No login, no session management.
  • Single-user demo β€” all browser missions attach to the same demo user.
  • Local file storage β€” evidence files stored on local filesystem (.storage/). Production needs R2/Supabase Storage.

Data

  • 42 curated legal chunks across 3 domains. No automated PDF ingestion (Docling skipped).
  • 3 route rules (consumer, payment, cyber_fraud). No employment/RTI/landlord domains.
  • All social posts are copy-ready β€” no Meta App Review completed, no X API payment.

Code Quality

  • 26 lint warnings β€” mostly any types in existing code, unused imports.
  • No integration tests β€” only unit tests with mocked DB.
  • Some as never casts in Inngest event sends (type safety gap).

Docker Images

  • infra-api: ~404MB
  • infra-worker: ~384MB
  • infra-postgres: ~640MB (pgvector base)

7. Key Commands Reference

# Development
pnpm dev                    # Start all services (web + api + worker)
pnpm build                  # Build all packages
pnpm typecheck              # TypeScript type checking
pnpm lint                   # ESLint
pnpm test                   # Run all tests
pnpm test:contracts         # Run contract tests only

# Database
pnpm db:migrate             # Run Drizzle migrations
pnpm db:seed                # Seed legal data + route rules
npx tsx scripts/seed-qdrant.ts  # Seed Qdrant with embeddings

# Docker
pnpm infra:up               # Start Postgres + Inngest
pnpm infra:down             # Stop all containers
docker compose -f infra/docker-compose.yml up -d    # Same as above
docker compose -f infra/docker-compose.yml down     # Same as above

# Verification (run before committing)
pnpm typecheck && pnpm lint && pnpm test && pnpm test:contracts

8. File Structure (Key Files)

CLAUDE.md                          # Project invariants β€” READ THIS FIRST
PHASE_1_automation_loop.md         # Phase 1 spec + DoD
PHASE_2_scale_and_intelligence.md  # Phase 2 spec (11 modules)

packages/
  db/src/schema.ts                 # All 30+ table definitions
  db/src/migrations/               # 0000 through 0009
  db/src/seeds/                    # legal-data.ts, route-rules-data.ts, run.ts
  contracts/src/                   # All Zod schemas (enums, mission, action, swarm, asr, etc.)
  ports/src/index.ts               # All port interfaces
  adapters/src/                    # All adapter implementations
    legal/pgvector-fts.ts          # Original Postgres RAG adapter
    legal/qdrant-hybrid.ts         # Qdrant Cloud hybrid adapter
    audio/whisper-api.ts           # Whisper ASR adapter
    translation/llm-adapter.ts     # LLM translation adapter
    portal/playwright-adapter.ts   # Playwright portal adapter
    social/copy-ready-fallback.ts  # Social publishing fallback
    social/card-generator.ts       # Social card image generator
    case-lookup/surepass-adapter.ts # eCourts CNR adapter
    channel/whatsapp.ts            # WhatsApp Cloud API
    channel/telegram.ts            # Telegram Bot API
    submission/resend-email.ts     # Resend email adapter
    redaction/regex.ts             # PII regex redaction
    redaction/regex-llm.ts         # LLM-assisted redaction
    storage/local-fs.ts            # Local filesystem storage
    index.ts                       # Adapter exports + capability registry

apps/
  api/src/
    app.module.ts                  # Root NestJS module (all modules wired)
    workflow/inngest.module.ts     # Inngest client + WorkflowService
    actions/                       # Action preview, consent, execute
    missions/                      # Mission CRUD + reply ingestion
    evidence/                      # Evidence files + fact confirmation
    webhooks/                      # WhatsApp, Telegram, email webhook handlers
    conversations/                 # Message ingestion service
    route-plans/                   # Route plan generation trigger
    resolution/                    # Resolution capture
    ledger/                        # Anonymized ledger
    dpdp/                          # Data export + erase
    swarm/                         # Complaint swarm
    portal-assist/                 # Portal automation
    resolver/                      # Company resolver
    case-lookup/                   # eCourts CNR lookup
    capabilities/                  # GET /api/capabilities
  worker/src/
    inngest.ts                     # All registered Inngest functions
    deps.ts                        # Singleton dependencies
    functions/
      intake.ts                    # Run intake (extract facts)
      evidence.ts                  # Parse evidence (vision-LLM or ASR)
      route-plan.ts                # Generate route plan with citations
      action-execute.ts            # Execute actions via ActionExecutor
      followup-schedule.ts         # Schedule follow-up reminders
      followup-handler.ts          # Handle due follow-ups
      reply-classify.ts            # Classify inbound replies
      resolution-verify.ts         # Verify resolution
      swarm.ts                     # Entity resolution + clustering
      portal-assist.ts             # Portal automation flow
      case-lookup.ts               # eCourts CNR lookup
    lib/
      action-executor.ts           # The ONLY place side-effects happen
  web/src/
    app/page.tsx                   # Mission board (list + create)
    app/missions/[id]/page.tsx     # Mission room (full detail)
    app/p/[slug]/page.tsx          # Public case page (private link)
    app/ledger/page.tsx            # Anonymized ledger dashboard
    lib/api.ts                     # Typed API client

9. Troubleshooting

"DATABASE_URL is not set"

Make sure infra/.env exists and has DATABASE_URL set. The API and worker read from this file.

"Qdrant connection failed"

Check QDRANT_URL and QDRANT_API_KEY. For local Qdrant: docker run -p 6333:6333 qdrant/qdrant.

"OpenAI API key not set" (Whisper)

Set OPENAI_API_KEY for voice note transcription. Without it, audio evidence will be skipped.

"Resend API key not set" (Email)

Set RESEND_API_KEY and RESEND_FROM for email sending. Without it, email actions will fail with proof_state: failed.

"Inngest function not found"

Make sure the Inngest dev server is running (pnpm infra:up) and the worker is running (pnpm dev). Check http://localhost:8288 for the Inngest dashboard.

Tests failing

pnpm typecheck  # Check for type errors first
pnpm test       # Run tests

Docker build failing

# Rebuild from scratch
docker compose -f infra/docker-compose.yml down -v
docker compose -f infra/docker-compose.yml build --no-cache
docker compose -f infra/docker-compose.yml up -d

10. Architecture Invariants (from CLAUDE.md)

These are non-negotiable. Violating them breaks the system's trustworthiness:

  1. Hexagonal β€” packages/domain has ZERO framework imports
  2. Everything external is an Action β€” side-effects only happen in action-executor.ts
  3. No fake submissions β€” proof_state must reflect reality
  4. No legal claim without cited source β€” literal substring check
  5. No public output without redaction + consent β€” Presidio redaction before share
  6. Contracts-first β€” all Zod schemas in packages/contracts
  7. Idempotent writes β€” every write endpoint accepts Idempotency-Key
  8. Every schema change is a Drizzle migration β€” no ad-hoc DB edits