A shortener is two routes and a table, and it quietly covers routing, database design, redirects, validation and abuse prevention. Excellent scope for a first server-side project.

1. The data

One table: the short code, the destination URL, when it was created, and a click count. The short code is the primary lookup and must be indexed and unique.

2. The two routes

shortener-build.txt
Build a URL shortener. Stack: <stack>.

Two routes:
- POST /shorten — takes a URL, returns a short code.
- GET /<code> — looks up and redirects.

Requirements:
- Generate codes from a character set with no ambiguous characters
  (no 0/O, 1/l/I). Say what length you chose and how many URLs that
  allows before collisions matter.
- Handle a collision on insert rather than assuming it won't happen.
- Validate the destination: must be http or https, must parse, must
  not point at my own shortener or at localhost / private IPs.
- 301 or 302? Pick one and explain the consequence for my click count.
- Unknown code returns a real 404 page, not a crash.

That private-IP check matters more than it looks — without it, your shortener can be used to probe internal networks from your server.

3. Stop it becoming a spam tool

An open, anonymous shortener will be found and used for phishing within days, and your domain gets blocklisted. At minimum: rate limit by IP, and either require a login or check destinations against a safe-browsing list.

4. Add the useful bit

Click counts, and a page showing them. Then, if you want: custom codes, expiry dates, a QR code. Each is small, and each teaches something.

Log the referrer and the timestamp, not the visitor's IP. You get the analytics you actually wanted and none of the data-protection questions.