# LeadGen — Step-by-Step Guide (Personal Tool by AJ) > Single-owner India SMB finder: Maps → no-website hunt → scoring → AI icebreakers → Sheets. No bulk sending from this server. --- ## 1) What you need before you start - A Gmail account (owner — this will be the *only* login allowed via `APP_ALLOW_EMAIL`) - A Hugging Face account (for the Space at `https://abc1181-leads.hf.space`) - Optional but recommended: a Google Cloud project (for Places + OAuth) — free tier is enough --- ## 2) Create the Hugging Face Space The code is already pushed to `abc1181/Leads` (Docker). Just configure envs: 1. HF → Space `abc1181/Leads` → **Settings → Variables** (non-secrets) and **Secrets** (tokens) 2. Set the essentials below (Section 3). The Space auto-restarts on save. 3. Check `https://abc1181-leads.hf.space/api/health` → should be `{"ok":true,"db":"ok","persistence":"on"}`. If `persistence:off`, the Space has no `/data` bucket — it will still run on ephemeral `/tmp` (banner shows), but add a bucket at `/data` in Space Settings for durability. --- ## 3) Env vars — what to create ### 3.1 Essentials (app won't work without these) Set in HF **Variables** unless marked **Secret**: | Key | Where | Value / How | |---|---|---| | `APP_ALLOW_EMAIL` | Variables | Your Gmail exactly — only this can sign in (`middleware.ts:39`, `lib/auth.ts:14`) | | `GOOGLE_CLIENT_ID` | Variables | From Google Cloud OAuth (see 4.1) | | `GOOGLE_CLIENT_SECRET` | **Secrets** | Same OAuth client | | `NEXTAUTH_SECRET` | **Secrets** | Random 32b hex: `openssl rand -hex 32` (already set) | | `NEXTAUTH_URL` | Variables | `https://abc1181-leads.hf.space` (already set) | | `PLACES_API_KEY` | **Secrets** | Google Places API key (see 4.2) — *or leave empty and use the free OSM/Ola rail (Section 4.3)* | Also needed (already set, don't change): `DATABASE_URL=file:/data/leads.db`, `CRON_SECRET`, `ENCRYPTION_KEY` ### 3.2 Optional — add when you want more coverage | Key | Where | Free tier | Notes | |---|---|---|---| | `OLA_API_KEY` | Secrets | 100k/API/mo free | India best free — `docs/maps-providers.md#5` | | `MAPPLS_CLIENT_ID` + `MAPPLS_CLIENT_SECRET` | Secrets | Free eval, no card | India best address hit — `docs/maps-providers.md#4` | | `FOURSQUARE_API_KEY` | Secrets | 500 free calls | Global fallback | | `HERE_API_KEY` | Secrets | ~5k-250k free (needs card) | Global fallback | | `ENRICH_PROVIDER=hunter` + `ENRICH_API_KEY` | Secrets | 25-50/mo free | Else phone is spine, emails stay `unknown` | | `LLM_BASE_URL` + `LLM_API_KEY` + `LLM_MODEL=mistral-large-latest` | Secrets | Your gateway | Else fallback templates (`lib/ai/fallback.ts`) | | `SMTP_HOST/PORT/USER/PASS` **or** `RESEND_API_KEY` + `DIGEST_TO` | Secrets/Vars | 100/d free | Else digest is in-app only | | `MOCK_SOURCES=1` | Variables | — | Use for demo with 50 Delhi fixtures, no keys | > **No billing?** Leave `PLACES_API_KEY` empty — the 6-provider rail (`lib/sources/maps.ts`) runs on **OSM Overpass (free, no key)** + `OLA_API_KEY`/`MAPPLS_*` if you set them. Add Google later and it stacks — no rebuild. --- ## 4) How to get each credential ### 4.1 Google OAuth (for Sign-in + Sheets) 1. https://console.cloud.google.com → Create project → **APIs & Services → OAuth consent screen** → External → fill App name, Support email → Save 2. **Credentials → Create Credentials → OAuth client ID** → Web application → Authorized redirect URI → add: `https://abc1181-leads.hf.space/api/auth/callback/google` → Create → copy **Client ID** and **Client Secret** → paste to HF as above. ### 4.2 Google Places API (New) — $200 free, needs billing 1. Same Cloud project → **APIs & Services → Enable APIs** → search **Places API (New)** → Enable 2. **Credentials → Create Credentials → API key** → Restrict → API restrictions → **Places API (New)** only → Save → copy to `PLACES_API_KEY`. 3. Enable billing (Billing → Link account) to get the $200 credit — you won't be charged inside free. Our use ≈ $5-10 (`lib/sources/places.ts:50` caps to 60 + Details only for no-website). Quota bar turns amber at 80% and degrades to `partial`. ### 4.3 Free India maps (no billing) — Mappls + Ola - **Mappls:** https://www.mapmyindia.com/api → Sign up → Dashboard → Create project → If you have a **Static/REST key** (your case), set `MAPPLS_API_KEY`; if you have OAuth pair, set `MAPPLS_CLIENT_ID` + `MAPPLS_CLIENT_SECRET` — either works. Free eval, no card. - **Ola Maps:** https://maps.olakrutrim.com → Sign up (Krutrim Cloud) → Credentials → API Key → `OLA_API_KEY`. 100k/API/mo free from 2026-09-01. `GET https://api.olamaps.io/places/v1/nearbysearch?location=lat,lng&radius=&keyword=` header `X-API-KEY`. ### 4.4 Other free maps (optional) - **Foursquare:** foursquare.com/developers → My Apps → Create App → API Key → `FOURSQUARE_API_KEY` (500 free). - **HERE:** developer.here.com → Project → API Key → `HERE_API_KEY` (needs card, pay-as-you-grow). - **OSM Overpass:** No key. Always on at `https://overpass-api.de/api/interpreter`. Full per-provider table: `docs/maps-providers.md`. ### 4.5 Enrich (emails, optional) - Hunter: hunter.io → API key (25 free) → `ENRICH_API_KEY` with `ENRICH_PROVIDER=hunter` - Apollo: app.apollo.io → API key (50 free) → `ENRICH_PROVIDER=apollo` ### 4.6 LLM (AI drafts, optional) Any OpenAI-compatible gateway. Set `LLM_BASE_URL` (e.g. `https://api.mistral.ai/v1`), `LLM_API_KEY`, `LLM_MODEL=mistral-large-latest`. **Llama banned** on any provider (`lib/ai/llm.ts:44` — AUP). Prompts are PII-free (`lib/ai/prompts.ts:8`). ### 4.7 Email digest (optional) - Gmail: App Password → `SMTP_HOST=smtp.gmail.com`, `SMTP_PORT=587`, `SMTP_USER`, `SMTP_PASS`, `DIGEST_TO=you@gmail.com` - Resend: resend.com → API key → `RESEND_API_KEY` (100/d free) --- ## 5) Run locally (optional) ```bash cp .env.example .env.local # fill with your keys; use absolute DATABASE_URL # MUST be absolute locally (Prisma CLI vs app resolve differently): # DATABASE_URL="file:/abs/path/to/leads-app/data/leads.db" npm install --registry https://registry.npmjs.org/ npx prisma migrate dev # creates data/leads.db npm run dev # http://localhost:7860 npm test # 59 unit (lib 80% lines) # integration (mock): INTEGRATION=1 MOCK_SOURCES=1 DATABASE_URL="file:$PWD/data/test.db" npx vitest run ``` --- ## 6) How to use the app (morning loop) 1. **Searches → New search** → pick template (Health/Beauty, Food, B2B/Factory, MidMarket/Upgrade, Generic) → city + radius (geocoded & cached, `lib/geo.ts:4`) → keywords → Cap 20/50/100/200 → Create. Star it for nightly. 2. **Run search** → progress header (per-provider ms/quota) → tabs Hot/Warm/Cold (`lib/score.ts:65` threshold) → table (filter by status/source/email/band/phone, sort score/rating) → drawer (AI draft violet, Copy/Regenerate, notes, blocklist). 3. **Verify all** (concurrency 5, skips fresh <7d unless forced) → **Push to Sheets** (master `LeadGen Master`, tab per search, 21 cols, idempotent on email→phone→company|location via `lib/sheets.ts:rowKey`) → **CSV fallback** per run. 4. **Hot queue (`/hot`)** is the morning inbox — `j/k` move, `q` qualify, `c` copy icebreaker, `?` help. 5. **Dashboard** shows Hot/Warm/Cold donut, per-source yield, category intel (`Where the buyers are`), quotas ($0), recent runs. Bell shows unread Hot + quota warnings. 6. **Settings** → Quotas, Keys presence (masked), Scoring weights + Re-score, Templates, Sheets connect/disconnect (OAuth sealed `lib/crypto.ts`), Blocklist (undo), Danger (purge caches). **Nightly:** GitHub Actions `30 20 * * * UTC` (02:00 IST) pings `/api/health` 5× then `POST /api/cron/nightly` with `CRON_SECRET` (`jobs/runner.ts:38` sequential, `roles` rolled if >25min). Digest top-10 Hot to `DIGEST_TO` (self only) + in-app bell. --- ## 7) Troubleshooting - `https://abc1181-leads.hf.space/api/health` → `ok:true, db:ok, persistence:on` means good. `persistence:off` = no bucket at `/data` — still runs on `/tmp` but data resets on restart (banner shows). - Sign-in 500 → `GOOGLE_*` or `APP_ALLOW_EMAIL` wrong, or redirect URI not set to `https://abc1181-leads.hf.space/api/auth/callback/google`. - Search returns 0 / `partial` → check quota bars in Settings; with no keys, OSM/Ola still work if those keys are set. - Chrome "Deceptive site" → fixed in `c029112` by making `/`, `/privacy`, `/terms` public (no auto-Google redirect). If still cached, request review at https://transparencyreport.google.com/safe-browsing/search?url=https://abc1181-leads.hf.space --- ## 8) Branding & cost - Branding: **Made by AJ · personal tool** (sidebar/footer/landing, `components/app-shell.tsx:39`). No Vercel triangle. - Cost: $0 target (`docs/runbook.md`). Quota bars prove it. 80% banners + auto-degrade, never spend. Questions? See `PRD.md`/`TRD.md` checkboxes (210 ticked, 52 intentionally unticked for live/V1.1/V2/parked).