Back to Projects
Shorteny URL Shortener

Shorteny — URL Shortener

Web Development
Type
Personal Project
Stack
Go + Next.js
Status
Live in Production

Project Overview

Shorteny is a URL shortener with a Next.js frontend and a Go (Gin) API. Visitors can shorten links anonymously without signing up; logged-in users get a dashboard with their links, click counts, QR codes, and account-scoped management. The backend uses PostgreSQL for storage and Redis for caching, rate limiting, and the cache-warmer that keeps the most-used short codes hot. Live at shorteny.site.

17
Frontend pages
15
API endpoints
3
Auth route groups
2
Database tables

What I Built

End-to-end ownership. Both the Go API and the Next.js frontend are mine — schema, handlers, middleware, and every page in the app.

Two flows in one product. Anonymous shortening through the public landing page, plus a full authenticated experience with a dashboard, history, profile, QR modal, and password-reset email loop.

Production-grade backend. Rate-limited Gin router, Redis cache warmer, Postgres-backed GORM models with soft-delete, structured logging, graceful shutdown, and SQL migrations.

Containerized + deployed. Frontend on Vercel, Go API packaged with the repo Dockerfile and run behind nginx — Postgres and Redis run as separate services.

Application Gallery

Landing — anonymous shortening with no signup
Landing — anonymous shortening with no signup
Sign in — JWT-backed auth
Sign in — JWT-backed auth
Create account — registration flow
Create account — registration flow
Pricing — single free tier
Pricing — single free tier

Frontend (Next.js 14)

App Router pages. 17 routes across the public site, auth flows, the user dashboard, and a resources cluster (blog, guide, documentation, api-docs).

Two service layers. src/services/api.ts handles auth, src/app/services/api.ts handles URL and QR calls. Base URL injected through NEXT_PUBLIC_API_URL.

UI. Tailwind for layout, Framer Motion for transitions, react-icons for the icon set.

Auth state. JWT persisted in localStorage; protected pages redirect on missing or expired tokens. Dashboard re-pulls URL stats on a timer while the tab is active.

Backend (Go + Gin)

Routing. Gin router split into /api public, /v1/auth, and JWT-guarded /v1/api groups. CORS, structured logger, and rate limiter middleware on every route.

Models. GORM models for User and URL over Postgres, with UUID primary keys, soft-delete on URLs, and ownership helpers (IsOwnedBy, CanBeEditedBy).

Rate limiting. Redis-backed token-bucket limiter keyed by client IP, with auto-block on excess requests and a TTL countdown returned to the caller.

Cache warmer. Background service that periodically loads the top URLs into Redis to keep redirects hot.

Auth. JWT access + refresh tokens generated per user UUID. Forgot-password flow sends reset links via SMTP using a dedicated email service.

Migrations. Versioned SQL migrations under migrations/: users, urls, anonymous-url support.

Lifecycle. Graceful shutdown via signal context, health-check endpoint, and 404 fallback wired into the router.

API Endpoints

Public
POST /api/urls (anonymous shorten), GET /urls/:shortCode (redirect), GET /qr/:shortCode, GET /qr/:shortCode/base64, GET /health
Auth
POST /v1/auth/register, /login, /forgot-password, /reset-password
User (JWT)
GET /v1/api/user/me, POST /v1/api/user/logout
URLs (JWT)
POST /v1/api/urls, GET /v1/api/urls (paginated), GET/DELETE /v1/api/urls/:id

Technologies Used

frontend

Next.js 14React 18TypeScriptTailwindCSSFramer Motionreact-icons

backend

GoGinGORMPostgreSQLRedisJWTSMTP

infra

DockernginxVercelRender

Key Features Shipped

Anonymous URL shortening — no signup required on the landing page
Authenticated dashboard with paginated URL list and live click counts
JWT auth: register, login, logout, password reset via SMTP email loop
QR code generation per short code (PNG and base64 endpoints)
Custom short-code support with collision check + random fallback
History page with client-side search and status filter
Auto-refreshing dashboard while the tab is active
Redis-backed token-bucket rate limiter keyed by client IP
Cache warmer service keeps top URLs hot in Redis
Soft-delete on URLs and account-scoped ownership checks

Try it live

Anonymous shortening on the landing page — no signup needed. Sign in to access the dashboard, click counts, and QR codes.

Visit shorteny.site