← Work

Internship Radar

Full-stack internship discovery and tracking platform — aggregating listings, summarising descriptions, and turning job search noise into a manageable workflow.

FastAPIReact / TypeScriptPostgreSQLWeb scrapingWorkflow tooling
Internship Radar discovery dashboard
Discovery dashboard showing saved roles, summaries, filters, and application tracking.

Internship Radar is a full-stack web app built to make internship and placement applications less chaotic. Instead of manually checking multiple websites, the system collects listings, stores them in a structured database, enriches each role with scraped job descriptions, and presents everything in a clean dashboard.

The aim was not just to list jobs, but to help decide what is worth applying to. The interface supports filtering, saving roles, opening external listings, and manually tracking progress through applied, interview, rejected, and offer statuses.

  • Aggregates 100+ internship and placement listings.
  • Normalises messy job data into a consistent model.
  • Converts long descriptions into concise role summaries.
  • Tracks saved and applied roles through a simple workflow.

Internship hunting is noisy. Listings are spread across different platforms, descriptions are long, deadlines vary, and it is easy to lose track of what has already been saved or applied to.

For a student applying under time pressure, the bottleneck is not just finding roles — it is quickly judging relevance and keeping the process organised.

The system had to work with inconsistent real-world data. Job boards use different page structures, descriptions are often unstructured, and some sources require careful handling. The project therefore needed a modular architecture where each source could be handled independently without breaking the rest of the app.

  • Avoid fragile all-in-one scraping logic.
  • Handle missing deadlines, descriptions, and locations gracefully.
  • Keep ingestion rate-limited and non-aggressive.
  • Make the frontend useful even when the data is imperfect.

The backend is built around a normalised jobs table and source-specific collectors. Each collector extracts listings into the same shape: title, company, location, URL, source, description, role type, deadline, status, and saved state.

FastAPI exposes REST endpoints for reading jobs, filtering listings, saving roles, and updating application status. PostgreSQL stores the canonical job data, while SQLAlchemy keeps the data model explicit and maintainable.

  • Modular collectors for source-specific scraping.
  • URL-based deduplication to prevent repeated listings.
  • Scoring and summary logic separated from ingestion.
  • REST API powering the React dashboard.

The core experience is a dashboard where a student can scan opportunities quickly. The left side handles filters, the middle column shows roles, and the detail panel shows the selected job with metadata, a quick summary, and a link to the original listing.

The application workflow is deliberately honest: the app does not pretend to apply for the user. It opens the external listing, then lets the user mark the role as applied afterwards.

Aggregation pipeline

Scrapes and normalises listings from job sources into a consistent backend model.

Description summarisation

Uses rule-based text processing to turn long job descriptions into short bullet summaries.

Application tracking

Supports saved, applied, interview, rejected, and offer states without needing user accounts.

Discovery dashboard

A React/Tailwind interface for filtering, reviewing, saving, and tracking roles.

Main dashboard for browsing and filtering internship listings
Main dashboard for browsing and filtering internship listings.
Applied roles and workflow status tracking
Applied roles and workflow status tracking.

This project forced me to deal with real-world messiness rather than idealised CRUD data. The most valuable parts were designing around unreliable sources, normalising scraped data, and making the UI useful even when some fields were incomplete.

  • How to structure scraping code so each source can fail independently.
  • Why deduplication and rate limiting matter in data ingestion.
  • How to design workflows around what users actually do.
  • How to turn raw text into useful summaries without immediately reaching for AI.

The next improvements would focus on coverage, automation, and deployment.

  • Add more reliable sources and company career-page collectors.
  • Schedule daily ingestion runs.
  • Add explainable match-score breakdowns.
  • Deploy a hosted demo with seeded public data.
  • Improve summaries using cached AI-generated summaries if needed.