A GenAI-powered check-in, personal emergency script, and real-time caregiver-linked support system for people navigating substance use recovery in India. Built for the PromptWars (hack2skill) "Build with AI" challenge - this repo covers both the warm-up Step 1 and the main challenge build (same persona, extended into a two-role product).
Primary persona: the person in recovery, with a caregiver as a linked, real second role - not a generic multi-persona app. Every crisis-moment interaction is designed around the person in recovery; the caregiver side exists specifically to support them in real time, not as a standalone feature.
- Sign up, choosing "In recovery" - one-click Google sign-in or email/password (with a forgot-password flow). Google sign-in is the lower-friction default; email/password is the fallback for anyone who doesn't have or want a Google account. Gets a real 6-character pairing code to share with a caregiver.
- Check-in - 3 real screening questions adapted from the WHO ASSIST
instrument, plus an open field for their own words about their trigger
and their reason to stay clear (
lib/data/assist-lite.ts). - Script generation (
/api/generate-script) - Gemini (gemini-2.5-flash) drafts a short, personal, WRAP-style emergency script from that context. A real national helpline number is appended programmatically (never generated by the model, to guarantee accuracy) and persisted to Firestore under the user's own uid. - Daily check-in: "I stayed clear today" / "I used today" drives a
non-punitive streak (
lib/streak.ts) - a lapse resets the current streak but never the longest streak or history, reflecting that relapse is a normal stage-of-change transition, not a failure (see project research docs, §1a). - "I need help right now" (
/api/crisis-response) - the saved script is sent back to Gemini with a "this is happening right now" framing for a calming, personalized read-back, and writes a real-time alert to any linked caregiver via Firestore. Shown alongside a guided box-breathing grounding exercise, not an alarm sound - a loud alert raises panic in someone already in distress rather than lowering it. - Opt-in distress-phrase detection (
lib/voice.ts) - the person can turn on continuous listening for phrases like "I need help" or "I want to use" (off by default - always-on mic is a real privacy tradeoff, not silently enabled). A match triggers the same crisis flow automatically, after a 3-second cancelable countdown so a single stray phrase doesn't fire an unwanted caregiver alert. Click-to-speak dictation for the check-in trigger note is a separate, unrelated feature and unaffected. - Rewards catalog - streak milestones map to badges and illustrative
reward categories (
lib/data/rewards.ts). This is explicitly NOT a live commerce/payment integration - real partner deals for coupons/cashback are a business-development step outside a hackathon timebox, and the UI says so rather than pretending otherwise.
- Sign up, choosing "A caregiver." Enters the recovering person's
pairing code to link (
links/{recoveringUid}_{caregiverUid}in Firestore, enforced by security rules - see below). - Live dashboard: linked person's current/longest streak and daily
buddy-check-in status, via a Firestore
onSnapshotlistener - no polling, no refresh needed. - Real-time crisis/lapse alerts: the moment the linked person hits "I need help right now" or logs a lapse, a banner appears live on the caregiver's screen.
This is a real, non-mocked, cue → routine → reward loop end to end: the crisis trigger is the cue, the Gemini-generated grounding action is the routine, streak milestones are the reward - and the caregiver is wired into the same loop, not bolted on separately.
npm install
cp .env.example .env # fill in GEMINI_API_KEY and the Firebase config (see below)
npm run devFirebase config values (NEXT_PUBLIC_FIREBASE_*) come from Firebase
Console → Project settings → General → Your apps → Web app. These are
not secret and are safe to expose client-side. GEMINI_API_KEY is the
one real secret and stays server-side only (never sent to the client).
For Google sign-in to work, enable it under Authentication → Sign-in
method → Google in the Firebase Console (Email/Password must also be
enabled for the fallback path). Also publish firestore.rules via
Firestore Database → Rules in the console, or firebase deploy --only firestore:rules with the CLI - a fresh project defaults to denying all
access until this is done.
See TESTING.md for the full breakdown. Summary:
npm run test- unit tests (streak logic, ASSIST scoring), no network.npm run test:integration- real Gemini API calls, no mocking.npm run test:rules- Firestore security rules against the real local emulator (firebase emulators:start --only firestorefirst).- E2E - headless Playwright critical path (signup → crisis trigger → caregiver sees the live alert).
- Two dedicated portals, no shared role picker.
/useris the entry point for the person in recovery (signup, login, Google sign-in, forgot password, all in one page);/caregiveris the same for caregivers. Each is self-contained specifically so the recovering person's path stays as fast as possible, and so this route tree could be split into two fully separate deployments later without touching the other side. The old shared/signup,/login,/checkin,/scriptroutes still work as redirects to their new locations, for backward compatibility. - Logged-in users landing back on
/useror/caregiversee the form again rather than an automatic redirect to their dashboard - a known minor UX gap, not a functional bug (the Header still reflects their actual session). - Simplified ASSIST scoring, not the official multi-branch WHO
algorithm (documented in
lib/data/assist-lite.ts). - Typed check-in, not voice-first. The problem statement's "zero-typing intervention" ideal is proven out at the AI/decision-logic layer end to end; the Gemini Live API voice layer is a documented next step, not built here due to the timebox.
- Rewards catalog is illustrative, not a live redemption/commerce system (see above).
- One helpline surfaced (1800-11-0031) in generated scripts; Tele-MANAS
is in
lib/data/helplines.ts, ready to surface as a second option. - Pairing codes use a 6-character alphanumeric space (no 0/O/1/I ambiguity) with no explicit collision check - acceptable risk at hackathon scale, would need a uniqueness guarantee at real scale.
npm audit reports advisories inside two places, neither exploitable via
this app's actual runtime/user-facing surface:
- Next.js 16.2.11's own bundled build-time dependencies (postcss, sharp,
the eslint/minimatch chain). Next has not shipped a patched release yet;
npm audit fix --forcewould downgrade to a very old Next version, which is not a real fix. @google/genai's optional MCP-server sub-dependency chain (@modelcontextprotocol/sdk→@hono/node-server), unused by this app - we only callai.models.generateContent, never the SDK's optional local MCP server.
Tracking upstream for patched releases rather than downgrading either.
Next.js 16 (App Router, TypeScript, Tailwind) · @google/genai
(server-side only) · Firebase Auth (email/password) + Firestore (client
SDK, secured by firestore.rules) · Netlify (hosting).