What inspired us

Interview prep usually means juggling tabs, generic advice, and guesswork about what a company really cares about. We wanted one place where you paste a job description and get a single, citation-backed report: company intel, tech deep-dives, and practice questions—all grounded in live web research instead of generic tips. We also wanted to keep past reports in one place instead of losing them when you close the tab. That’s why we built Interview Buddy: turn any job posting into structured, research-backed interview prep you can save and revisit.

What we learned

  • Streaming UX: Using Server-Sent Events (SSE) so the UI shows progress step-by-step (metadata → company research → tech research → synthesis) instead of a long wait and one big dump. The frontend consumes the stream with fetch + ReadableStream and updates React state as events arrive.

  • You.com APIs: Integrating Search (v1 and legacy fallback on 403) and the Express Agent for synthesis, with clear error handling and timeouts so the pipeline degrades gracefully. Full-stack on one dyno: Serving the React app and FastAPI from a single Heroku app: Node buildpack builds the frontend to dist/, Python runs the API, and FastAPI serves static files and a catch-all for SPA routing so one URL gives you both UI and API.

  • Backend-backed history: We added a small history API (list, save, get, delete) with an in-memory store so saved analyses live on the server. The frontend calls these endpoints when the API is available and falls back to localStorage when it isn’t, so the app works both in production and when the backend is down or not deployed.

  • Structuring the backend: Splitting models (Pydantic request/response and domain types) into an app/models/ package and moving business logic (parsers, API client, pipeline, prompts, SSE, history store) into app/services/ made the codebase easier to navigate and test.

How we built it

  • Backend (Python/FastAPI): A pipeline in app/services/ runs in order: job_parser (regex + known tech list) extracts company, role, and technologies; you_client calls You.com Search (one query per company and per technology) and the Express Agent for synthesis; prompts and sse helpers shape the prompt and stream. We stream each phase as SSE events. history_store backs the /api/history endpoints (list, save, get, delete) with an in-memory store; the same models (in app/models/) are used for requests, responses, and the analysis result.

  • Frontend (React, TypeScript, Vite): AnalysisContext triggers POST /api/prepare with the job text, reads the SSE stream, and drives state (steps, progress, result). The Prepare page shows the streamed report and auto-saves to history when complete. useSavedAnalyses fetches from GET /api/history when the backend is available and falls back to localStorage otherwise; the History page lists saved analyses and can open or delete them via the API. UI is Tailwind + shadcn/ui.

  • Deployment: Procfile runs uvicorn from backend/; root requirements.txt points at backend/requirements.txt; .buildpacks uses Node then Python; heroku-postbuild runs npm run build so dist/ exists. FastAPI serves /api/* and, when dist/ exists, serves static assets and index.html for SPA routes.

  • CI (GitHub Actions): We added a workflow that runs on push and pull requests: a backend job installs Python deps and runs pytest (unit and integration tests, including the history API), and a frontend job runs npm ci and npm run build so we know the app builds and tests pass before merge.

Challenges we faced

  • API compatibility: You.com Search v1 returned 403 for some keys; we added a legacy search endpoint fallback and configurable URLs so the app works across different API access levels. Streaming and parsing: The synthesis step returns a large JSON blob; we had to parse it incrementally and still stream progress and handle malformed JSON without breaking the SSE connection or leaving the UI stuck.

  • Heroku as “Python-only”: By default Heroku detected only Python. We introduced multi-buildpack (Node first, then Python), NPM_CONFIG_PRODUCTION=false, and heroku-postbuild so the frontend builds and the same app serves both the React SPA and the FastAPI backend from one URL.

  • History on the server vs in the browser: We wanted saved analyses to persist on the backend when deployed, but still work when the API isn’t available (e.g. local dev or backend down). We added a small history API and made the frontend try the API first and fall back to localStorage, so one code path works in both cases.

Built With

  • fastapi
  • heroku
  • httpx
  • pydantic
  • python
  • radix-ui
  • react-18
  • react-router
  • server-sent-events-(sse)
  • shadcn/ui
  • tailwind-css
  • typescript
  • uvicorn
  • vite
  • you.com-chat-api
  • you.com-search-api
Share this project:

Updates