A real-time public-interest observatory for India's alcohol policy, illicit-liquor incidents, and correlated social harms.
SoberMap is an early-stage civic-tech product that fuses four alcohol-related signals India normally tracks in isolation into a single live dashboard:
- Policy — who allows it, who bans it, what the legal drinking age is.
- Consumption — household survey proxies drawn from NFHS-5.
- Illicit supply — hooch tragedies, methanol poisonings, IMFL seizures.
- Social harm — domestic violence rates and alcohol-linked crime.
The result is a map-first observatory with a real GeoJSON choropleth of India, a live signal feed wired to Postgres realtime, per-state deep-dives with SEO-ready routes, and an AI pipeline that watches Indian news wires and inserts structured incident rows as they happen.
SoberMap is a public-interest research and awareness prototype. It is not an enforcement tool, not a personal-risk predictor, and not a substitute for professional help.
SoberMap is built and maintained by:
Mohammad Zeeshan - Engineer Eötvös Loránd University (ELTE), Budapest
Mission: make public data about alcohol, policy, and social harm in India legible, current, and usable — by journalists, civil society, researchers, and the public — without turning people into data points.
| Module | What it does |
|---|---|
| Legality Choropleth | Real GeoJSON India map (d3-geo + topojson) with zoom, pan, per-state status colors, and live realtime pulses when new incidents arrive. |
| Signal Feed | Postgres realtime stream — new incidents prepend with a visual flash and NEW badge as they are inserted. |
| Consumption x DV Panel | Side-by-side state ranking with the Pearson correlation between consumption proxies and reported domestic-violence rates per 100k. |
| Per-State Reports | /state/$code with hero KPIs, six-year trend chart (events vs casualties), full incident timeline, prioritized helplines, and unique SEO / OpenGraph metadata per state. |
| AI News Ingest | POST /hooks/ingest-news parses Indian RSS feeds, de-dupes against existing rows, and uses an OpenAI-compatible model via tool-calling to extract {state, district, type, date, casualties} as structured inserts. |
| Helplines Directory | Verified Indian DV, de-addiction and mental-health numbers (181, 1091, NIMHANS 14416, AASRA, iCall, and more) with 24x7 flag and coverage area. |
Full transparency about what is real versus seeded, because trust matters more than impressive-looking numbers.
| Table | Rows | Source |
|---|---|---|
states |
31 | Manually curated. consumption_index, dv_rate_per_100k, drinking_age, policy_notes are representative figures derived from NFHS-5 and NCRB published ranges — directional, not row-level audited. |
incidents |
20 seed + live | Seed rows are real, attributable public events from news archives (Botad 2022, Chhapra 2022, Tarn Taran 2020, and others). New rows are inserted automatically by the AI ingest hook. |
helplines |
12 | Real, verified Indian numbers. |
Realtime, the choropleth pulses, the signal feed, and the AI extraction pipeline are all real and wired end-to-end. What is small today is the dataset volume, not the plumbing. Schedule the ingest hook and rows accumulate automatically.
- TanStack Start v1 — full-stack React 19 framework with SSR and file-based routing on Vite 7.
- TanStack Router — type-safe routing (
/state/$codeis fully typed). - Tailwind CSS v4 — design tokens in
oklch, defined insrc/styles.css. - Postgres + Realtime — public-read RLS, websocket subscription on
incidents. - d3-geo + topojson-client — real India GeoJSON projection with zoom / pan.
- Recharts — trend charts on per-state pages.
- OpenAI-compatible Chat Completions — provider-agnostic structured extraction via tool-calling (works with OpenAI, Azure OpenAI, OpenRouter, Groq, Together, Fireworks, or any self-hosted gateway).
- TypeScript strict mode, ESLint, Prettier.
- Vercel — production hosting for both the SSR app and the server routes.
# 1. Install
npm install
# 2. Configure environment
cp .env.example .env
# fill in the keys listed below
# 3. Dev server on http://localhost:5173
npm run dev
# 4. Production build
npm run build
npm run startAll variables live in .env locally and in the Vercel project settings in production.
# Public (browser-safe) — bundled into the client
VITE_SUPABASE_URL=https://<project-ref>.supabase.co
VITE_SUPABASE_PUBLISHABLE_KEY=<anon-key>
VITE_SUPABASE_PROJECT_ID=<project-ref>
# Server-only — never expose to the browser
SUPABASE_URL=https://<project-ref>.supabase.co
SUPABASE_PUBLISHABLE_KEY=<anon-key>
SUPABASE_SERVICE_ROLE_KEY=<service-role-key>
# AI ingest pipeline
AI_API_KEY=<provider-key>
AI_GATEWAY_URL=https://api.openai.com/v1/chat/completions
AI_MODEL=gpt-4o-mini
# Shared secret for scheduled ingest calls
CRON_SECRET=<long-random-string>The VITE_-prefixed values are bundled into the client at build time. Every other value is server-only and must stay out of the browser.
Three tables, all RLS-enabled with public-read policies.
states—code,name,status(banned/partial/legal),drinking_age,consumption_index,dv_rate_per_100k,illegal_supply_risk,policy_notes.incidents—state_code(FK),type(hooch_tragedy/illegal_seizure/domestic_violence/alcohol_crime),occurred_on,district,casualties,source_url,title,description.helplines—name,phone,category,coverage,available_24_7,url.
Realtime is enabled on incidents (ALTER PUBLICATION supabase_realtime ADD TABLE public.incidents), so the dashboard reacts within milliseconds of an insert.
Migrations live under supabase/migrations/.
POST /hooks/ingest-news is the heart of the live data layer.
Per invocation:
- Fetch the configured Indian-news RSS feeds.
- Pre-filter headlines on alcohol / hooch / liquor / seizure keywords.
- De-dupe against existing
incidents.source_urlrows. - Send a JSON-serialized batch to the configured OpenAI-compatible model with a strict tool schema demanding
{state_code, type, occurred_on, district, casualties, title, description, source_url}. - Drop any row whose
state_codeis not a valid Indian state. - Insert via the service-role client; Postgres realtime fans out to every connected dashboard.
Trigger manually:
curl -X POST https://<your-deploy>.vercel.app/hooks/ingest-news \
-H "Authorization: Bearer <service-role-key>"Trigger on a schedule (Vercel Cron, GitHub Actions, Postgres pg_cron, or any other scheduler):
curl -X POST https://<your-deploy>.vercel.app/hooks/ingest-news \
-H "x-ingest-context: cron" \
-H "x-cron-secret: $CRON_SECRET"src/
components/
IndiaChoropleth.tsx # d3-geo + topojson, zoom / pan, realtime pulses
StatusBadge.tsx
hooks/
use-data.ts # useStates, useIncidents (realtime), useHelplines
integrations/supabase/ # auto-generated client + types + auth middleware
routes/
__root.tsx # head() / shell / 404
index.tsx # dashboard (map + signal feed + DV panel)
state.$code.tsx # per-state report (KPIs, trends, timeline)
hooks/ingest-news.ts # POST hook: RSS + AI extraction
styles.css # design tokens (oklch) + animations
router.tsx
SoberMap is configured end-to-end for Vercel: the SSR app, the /hooks/ingest-news server route, and the Postgres client all work out of the box.
-
Push the repo to GitHub.
-
In the Vercel dashboard, import the repository.
-
Build command:
npm run build. Output directory: leave empty (Vercel uses.vercel/outputautomatically). -
Add every variable from
.env.exampleto the Vercel project settings (Production + Preview). -
Deploy.
-
Optional — schedule the ingest hook. Easiest path is Vercel Cron in
vercel.json:Vercel Cron requests include
x-vercel-cron: 1— add an equivalent header or use thex-cron-secretflow shown above.
Supabase (Postgres, Auth, Realtime, Storage) is a managed service and is not part of the Vercel deploy. You only point the deploy at it via the environment variables above.
- NFHS-5 — National Family Health Survey, Government of India.
- NCRB — Crime in India statistical reports.
- State excise department public releases.
- Curated public news archives (The Hindu, Times of India, NDTV, Indian Express) for hooch tragedies and seizures.
Where reliable data is missing, we say so. Indicators are aggregate. Correlation is not causation.
SoberMap is not:
- a real-time crime feed,
- a personal-risk predictor,
- a claim that alcohol causes domestic violence,
- a substitute for professional or emergency help.
If you or someone you know needs help, the helplines directory lists free, confidential support numbers across India.
SoberMap is early-stage and opinionated, but contributions that improve data quality, extend state coverage, or harden the ingest pipeline are very welcome.
- Fork the repository.
- Create a topic branch (
git checkout -b fix/helpline-validation). - Make your change with a short, descriptive commit message.
- Open a pull request describing the intent and any data sources cited.
MIT — see LICENSE. Data inputs follow their respective source licenses (NFHS, NCRB, state excise departments, and news archives).
SoberMap — because policy data should be public, current, and correlated. Built with care by Mohammad Zeeshan.
{ "crons": [ { "path": "/hooks/ingest-news", "schedule": "0 * * * *" } ] }