Drop a company domain, get a grounded, meeting-ready deal dossier. A Next.js app whose API route crawls the company's homepage plus /about and /pricing, then asks Gemini (with Google Search grounding) for live signals and a structured dossier, streamed back to the browser. Past dossiers are saved in the browser via localStorage.
- Copy the env file and add your Gemini key:
Set
cp .env.example .env.local
GENAI_API_KEYto your key from https://aistudio.google.com/apikey SetMONGODB_URIto a MongoDB connection string (e.g. an Atlas free cluster). Only needed for shareable links; everything else works without it. Setenvotodevlocally; set it toprodon your deployment so share links point to your domain (dossier.ayam.codes) instead of the raw host. SetNEXT_PUBLIC_API_KEYto the key that gates the API routes. The browser sends it on every request and the server rejects requests without it. - Install and run:
npm install npm run dev
- Open http://localhost:3000
- Push this folder to a GitHub repo.
- On vercel.com, "Add New Project" and import the repo.
- Under Settings > Environment Variables, add
GENAI_API_KEY,MONGODB_URI,envo(set toprod), andNEXT_PUBLIC_API_KEY. - Deploy. The API route runs as a serverless function; the frontend is static.
- Models: tries
gemini-3.5-flash, falls back togemini-2.5-flash, with retry/backoff on transient 503/429. - The API route streams text; the key stays server-side and never reaches the browser.
- Retry/fallback covers errors before streaming starts; a mid-stream outage shows a truncated dossier rather than auto-retrying.
- The model emits a compact JSON block alongside the prose; the frontend turns it into an interactive signals timeline, priority/pain chips, and value cards. If that block is missing or truncated, graphics are skipped and the prose still renders.
- Share stores a snapshot of the dossier in MongoDB and returns a
/?id=...link. Opening it reads the stored snapshot, so it costs no model call and never changes. - All API routes require an
x-api-keyheader matchingNEXT_PUBLIC_API_KEY. Since the app calls them from the browser, the key ships in the client bundle: it deters casual and scripted hits but is not a strong secret. For stronger protection, add same-origin enforcement plus rate limiting.