← System design basics for freshers and junior engineers

Lesson 5 of 5

Worked designs: URL shortener and a job portal

2 min read

URL shortener

Requirements: create a short link; redirect fast; optional custom alias and expiry; click counts. 100M redirects/day (~1,200/s average, ~5k/s peak), 1M new links/day.

API

text
POST /links { url, alias?, expiresAt? } → { code: "aZ3k9Q" }
GET  /{code} → 301/302 redirect

Code generation: a 7-character base62 code gives 62⁷ ≈ 3.5 trillion combinations. Options: base62-encode a unique id from a counter or Snowflake generator (no collisions), or hash the URL and handle collisions. Use 302 if you want to count every click (301 is cached by browsers).

Storage: links(code PK, url, owner_id, created_at, expires_at). 1M/day × ~500 B ≈ 180 GB/year: one Postgres instance with replicas is plenty at first; a key-value store also fits because lookups are always by code.

Read path: load balancer → stateless redirect service → Redis cache (most links are hot for a short time) → database on a miss. Return the redirect immediately; send a click event to a queue; a worker aggregates counts into an analytics store.

Deep dives: hot links (cache plus CDN edge redirects), abuse (rate-limit creation, scan URLs for malware), expiry (a check on read plus a periodic cleanup job).

A job portal (like HireSol)

Requirements: companies post jobs; students search and apply; companies review applicants through hiring rounds; notifications by email and in-app. 1M students, 20k companies, peak during placement season.

Services / modules: accounts and auth, profiles and resumes, jobs, search, applications and hiring rounds, notifications, analytics.

Data

text
users, student_profiles, companies
jobs(id, company_id, title, area, city, status, deadline)
applications(id, job_id, student_id, stage, status, UNIQUE(job_id, student_id))

Key flows

  • Search: jobs indexed in a search engine (or Postgres full-text search to start) with filters for city, area and type; results cached for popular queries.
  • Apply: a transaction inserts the application (the unique constraint stops double applications); an event is published; the notification worker emails the company.
  • Resume uploads: direct upload to object storage with a signed URL; a background worker extracts text and builds embeddings for AI matching.
  • Deadline spikes: autoscale the stateless app tier; queue heavy work; the database writes are small, so one primary with replicas holds up well.

Trade-offs to discuss: freshness of search results (seconds of delay are fine), consistency of application status (strong: use the primary), privacy (resume access only for companies the student applied to or opted into), and fairness in ranking.

Check yourself

  • Why might you use a 302 instead of a 301 redirect?
  • Where would you put the unique "one application per job" rule, and why there?
  • What would break first in the job portal at 10× traffic?

Sign up free to save your progress.