# Deployment Guide — CourtMitra MissionOS > **Target:** Vercel (frontend) + Hugging Face Spaces (backend + worker) + Google OAuth (Clerk) + Neon (Postgres) --- ## Honest Time Estimate | Milestone | Time | |---|---| | Clerk setup (Google OAuth) + env vars | **10 min** | | Neon Postgres + run migrations | **10 min** | | Frontend on Vercel | **5 min** | | API + Worker on Hugging Face Spaces | **20–30 min** | | Wire frontend → backend + smoke test | **10 min** | | **Running frontend + API + Worker + DB + Google Auth** | **~1 hour** (if everything goes smoothly) | --- ## Prerequisites - GitHub repo pushed and public (or HF Pro for private Spaces) - Accounts (all have generous free tiers): - [Vercel](https://vercel.com) - [Clerk](https://clerk.com) - [Hugging Face](https://huggingface.co) - [Neon](https://neon.tech) - [Inngest](https://inngest.com) (optional — for background workflows) - OpenRouter API key (or OpenCode / OpenAI key) for LLM calls --- ## Step 1: Clerk + Google OAuth (10 min) 1. Go to [dashboard.clerk.com](https://dashboard.clerk.com) → Create Application. 2. In the **Social Connections** section, enable **Google**. - For development, use Clerk's shared OAuth credentials (just toggle it on). - For production, add your own Google Client ID/Secret. 3. Copy your **Publishable Key** and **Secret Key** from Clerk Dashboard → API Keys. 4. Set these in Vercel (Step 3) and locally: ``` NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_... NEXT_PUBLIC_CLERK_SIGN_IN_URL=/en/sign-in NEXT_PUBLIC_CLERK_SIGN_UP_URL=/en/sign-up ``` 5. That's it — the frontend has Clerk wired with `SignInButton`, `UserButton`, and `` components. 6. **Backend Clerk verification:** The API verifies Clerk JWTs from the `Authorization: Bearer ` header. On first API call, it auto-creates a user in the DB and links their Google identity. --- ## Step 2: Neon Postgres (10 min) 1. Go to [neon.tech](https://neon.tech) → New Project → copy the **connection string**. 2. Save it as `DATABASE_URL` and `DIRECT_DATABASE_URL`. 3. **Run migrations** against the Neon DB: ```bash # At repo root export DATABASE_URL="postgres://..." export DIRECT_DATABASE_URL="postgres://..." pnpm db:migrate pnpm db:seed ``` --- ## Step 3: Frontend → Vercel (5 min) 1. Push this repo to GitHub. 2. In Vercel → **Add New Project** → import the repo. 3. Set these **Environment Variables** in the Vercel dashboard: ``` NEXT_PUBLIC_API_BASE_URL=https://your-hf-space.hf.space/api NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_... NEXT_PUBLIC_CLERK_SIGN_IN_URL=/en/sign-in NEXT_PUBLIC_CLERK_SIGN_UP_URL=/en/sign-up ``` 4. Deploy. Vercel will auto-detect Next.js in `apps/web`. > **Tip:** `next.config.mjs` already has `output: "standalone"`, so Vercel optimizes automatically. --- ## Step 4: Backend → Hugging Face Spaces (25 min) ### 4a. Create the Space 1. Go to [huggingface.co/spaces](https://huggingface.co/spaces) → **Create new Space**. 2. **Space name:** `courtmitra-api` 3. **SDK:** `Docker` 4. **Visibility:** Public (free tier) 5. **Hardware:** Free CPU ### 4b. Deploy the Dockerfile The repo root has `Dockerfile.hf` which builds the monorepo and runs the NestJS API + Inngest Worker in ONE container. Push it to HF (or link your GitHub repo in HF Space settings): ```bash git add Dockerfile.hf git commit -m "Add HF Spaces Dockerfile (API + Worker combined)" git push origin main ``` Then in your HF Space → **Settings** → **Repository** → link your GitHub repo. ### 4c. Set Environment Variables In your HF Space → **Settings** → **Variables & Secrets**: ``` PORT=7860 API_PORT=7860 DATABASE_URL=postgres://... (Neon) DIRECT_DATABASE_URL=postgres://... (Neon) AI_PROVIDER=openrouter OPENROUTER_API_KEY=sk-or-v1-... AI_MODEL=google/gemini-2.0-flash-exp:free AI_VISION_MODEL=google/gemini-2.0-flash-exp:free APP_BASE_URL=https://your-hf-space.hf.space API_BASE_URL=https://your-hf-space.hf.space WEBHOOK_BASE_URL=https://your-hf-space.hf.space LOCAL_STORAGE_DIR=/app/.storage JWT_SECRET=hackathon-jwt-secret-change-me PII_HASH_SALT=hackathon-salt TOKEN_ENCRYPTION_KEY=hackathon-enc-key-min-32-chars!! CLERK_SECRET_KEY=sk_test_... CLERK_JWT_KEY=... (optional — for networkless JWT verification) ``` Optional (for email actions): ``` RESEND_API_KEY=re_... RESEND_FROM=noreply@yourdomain.com ``` Optional (for Inngest background workflows): ``` INNGEST_EVENT_KEY=... (from Inngest Cloud) INNGEST_SIGNING_KEY=... (from Inngest Cloud) INNGEST_BASE_URL=https://api.inngest.com ``` Optional (for local dev without Clerk): ``` DEMO_MODE=true ``` ### 4d. Verify the API Once the Space builds, visit: - `https://your-space.hf.space/api/admin/health` → should return `{"status":"ok"}` - `https://your-space.hf.space/api/inngest` → should return the Inngest registration JSON --- ## Step 5: Wire Frontend → Backend Update your Vercel environment variable: ``` NEXT_PUBLIC_API_BASE_URL=https://your-hf-space.hf.space/api ``` Redeploy the frontend (or Vercel will auto-redeploy on save). --- ## Architecture (Combined Container) ``` ┌─────────────────────────────────────────────────┐ │ Hugging Face Spaces — Port 7860 │ │ ┌─────────────────────────────────────────┐ │ │ │ Fastify HTTP Server (NestJS) │ │ │ │ ┌─────────────┐ ┌────────────────┐ │ │ │ │ │ API Routes │ │ /api/inngest │ │ │ │ │ │ /api/* │ │ (Worker Fns) │ │ │ │ │ │ │ │ │ │ │ │ │ │ - missions │ │ - intake │ │ │ │ │ │ - actions │ │ - evidence │ │ │ │ │ │ - users │ │ - route-plan │ │ │ │ │ │ - evidence │ │ - execute │ │ │ │ │ └─────────────┘ └────────────────┘ │ │ │ └─────────────────────────────────────────┘ │ │ ↓ │ │ Neon Postgres (Cloud) │ └─────────────────────────────────────────────────┘ ``` --- ## Quick Smoke Test After both are deployed: 1. Open your Vercel URL → click **Sign In** → choose **Google**. 2. After signing in, you should see your avatar in the top-right corner. 3. Click **Get Started** (hero CTA) → describe a problem. 4. The API call should reach HF Spaces, create a user in the DB, and create a mission. 5. Visit `/{locale}/profile` → you should see your profile and the mission you just created. 6. Check `https://your-hf-space.hf.space/api/admin/health` to confirm backend is alive. --- ## New Features | Feature | Status | |---|---| | Google OAuth via Clerk | ✅ Frontend + Backend verified | | User auto-creation on first API call | ✅ Creates `users` + `userIdentities` rows | | Profile page (`/{locale}/profile`) | ✅ Shows avatar, name, email, editable phone + language | | My Missions list on profile | ✅ Lists user's own missions | | Mission ownership | ✅ Users only see their own missions | | Combined API + Worker container | ✅ One HF Space serves both | | Demo mode | ✅ `DEMO_MODE=true` bypasses auth for local dev | --- ## Known Limitations for Hackathon Demo | Feature | Status in 1-hour deploy | |---|---| | Frontend + Google OAuth on Vercel | ✅ Works | | API + Worker + DB on HF + Neon | ✅ Works | | Mission CRUD (user-scoped) | ✅ Works | | Evidence upload | ✅ Works (if storage configured) | | Background AI workflows | ⚠️ Needs Inngest Cloud keys for production webhooks | | Email sending via Resend | ⚠️ Needs Resend key + verified domain | | WhatsApp / Telegram channels | ❌ Needs Meta Business verification (days) | | Portal automation / eCourts | ❌ Phase 2 only | --- ## Troubleshooting **HF Space build fails:** - Check **Factory Logs** in HF. If `pnpm` is missing, the Dockerfile installs it via `corepack`. - If out of disk: HF free tier has ~50GB disk. The Dockerfile removes frontend packages (`next`, `react`) from the API deploy to save space. **API returns 401 Unauthorized:** - Make sure `CLERK_SECRET_KEY` is set in HF Space env vars. - Make sure the frontend passes `Authorization: Bearer ` header. Check browser DevTools Network tab. **API returns 500:** - Verify `DATABASE_URL` is set and migrations ran. - Verify `OPENROUTER_API_KEY` is set (some endpoints call LLMs). **CORS errors from frontend:** - The API has `app.enableCors({ origin: true })` which reflects the request origin. If blocked, add your Vercel domain to `origin: ["https://your-vercel.app"]` in `apps/api/src/main.ts`. **Clerk sign-in fails:** - Make sure `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` are set in Vercel. - In Clerk Dashboard → **Social Connections** → **Google**, ensure it's enabled. - Add your Vercel domain to Clerk Dashboard → **URLs** → **Allowed Origins**. **Inngest events not firing:** - Make sure `INNGEST_EVENT_KEY` and `INNGEST_SIGNING_KEY` are correct. - Check the Inngest Cloud dashboard for failed runs. - HF free-tier Spaces sleep after inactivity. Use a paid Space or keep-alive ping for reliable background processing. --- ## Local Dev ```bash # 1. Start local Postgres + Inngest pnpm infra:up # 2. Copy env and fill in keys cp infra/.env.example .env # 3. Run everything pnpm dev ``` - Web: http://localhost:3000 - API: http://localhost:3001/api - Inngest Dev Server: http://localhost:8288 **Note:** For local dev without Clerk, set `DEMO_MODE=true` in `.env`. The API will skip JWT verification and use a demo user. --- *Good luck at the hackathon! 🚀*