Live App → linkpilot Live Url
Backend API → Linkpilot API
LinkPilot is a production-deployed SaaS application for creating, managing, and analyzing smart short links — similar to Bitly or Rebrandly, but with richer features including campaign management, bio pages, QR codes, and subscription billing.
This frontend showcases modern full-stack React engineering — from authentication architecture and real-time data fetching, to role-based access control and responsive dashboard UI — all deployed at production scale on Vercel.
Why I built this: Most link shorteners are black boxes. I wanted to build one where users own their data, get real analytics, and can create branded experiences around their links — all under one subscription.
- Multi-provider auth — Google OAuth, GitHub OAuth, and email/password via
better-auth - Email verification flow — mandatory on signup with resend capability
- Password reset — secure token-based reset with 1-hour expiry
- Role-based access —
userandadminroles with protected route segments - Session persistence — cross-domain cookie handling with
SameSite=None; Secure
- Real-time stats — clicks, unique visitors, top referrers, device breakdown
- Interactive charts — time-series click graphs with daily/weekly/monthly views
- Geographic insights — country-level click distribution
- UTM tracking — source, medium, and campaign attribution
- Bulk operations — create, edit, archive, and delete multiple links
- QR code generation — downloadable QR codes with style customization
- Link health status — visual indicators for broken or redirecting destinations
- Password protection — secure individual links behind a password gate
- Expiry scheduling — links automatically deactivate on a set date
- Campaign grouping — organize related links and track aggregate performance
- Bio page editor — build a bio link landing page (like Linktree)
- Custom domain support — attach your own domain to shortened links
- Stripe Checkout integration — seamless plan upgrades (Starter / Pro / Lifetime)
- Subscription status — live billing info with renewal dates and usage
- Usage limits — plan-enforced link quotas with clear upgrade prompts
- Self-serve management — cancel, upgrade, or view invoices from the dashboard
- API Key management — generate and revoke keys for programmatic access
- Admin panel — user management, system analytics, and platform health
| Category | Technology | Why |
|---|---|---|
| Framework | Next.js 15 (App Router) | Server components, streaming, file-based routing |
| Language | TypeScript 5 | End-to-end type safety |
| Styling | Tailwind CSS 4 | Utility-first, zero unused CSS |
| UI Components | shadcn/ui + Radix UI | Accessible, composable primitives |
| Auth Client | better-auth/react | Matches backend auth, consistent sessions |
| HTTP Client | Axios | Typed requests with interceptors |
| Forms | React Hook Form + Zod | Performant forms with schema validation |
| Notifications | Sonner | Non-blocking toast notifications |
| Icons | Lucide React + React Icons | Consistent icon system |
| Deploy | Vercel | Edge network, preview URLs, zero config |
src/
├── app/ # Next.js App Router pages
│ ├── (auth)/ # Auth pages (login, register, reset)
│ │ ├── auth/login/
│ │ ├── auth/register/
│ │ └── auth/reset-password/
│ ├── (dashboard)/ # Protected user dashboard
│ │ ├── dashboard/ # Overview and stats
│ │ ├── links/ # Link management
│ │ ├── analytics/ # Analytics views
│ │ ├── campaigns/ # Campaign management
│ │ ├── pages/ # Bio page builder
│ │ ├── domains/ # Custom domains
│ │ ├── api-keys/ # Developer API keys
│ │ └── settings/ # Account and billing
│ └── admin/ # Admin-only panel
│
├── components/
│ ├── auth/ # Login forms, social buttons, auth card
│ ├── dashboard/ # Charts, stat cards, link tables
│ ├── ui/ # shadcn/ui base components
│ └── shared/ # Layout, navbar, sidebar, modals
│
├── lib/
│ ├── auth-client.ts # better-auth client setup
│ ├── axios.ts # Axios instance with base URL
│ └── utils.ts # cn(), formatters, helpers
│
├── services/ # Typed API service layer
│ ├── link.service.ts
│ ├── analytics.service.ts
│ ├── campaign.service.ts
│ └── user.service.ts
│
└── types/ # Shared TypeScript interfaces
- Node.js 18+
- Running instance of LinkPilot API
git clone https://github.com/SuvraDebPaul/Smart-Link-Management-System-Backend
cd smart-link-management-system
npm installcp .env.example .env.local# Local development — points to local backend
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_API_BASE_URL=http://localhost:5000/api
NEXT_PUBLIC_BACKEND_URL=http://localhost:5000
NEXT_PUBLIC_BETTER_AUTH_URL=http://localhost:5000
NEXT_PUBLIC_ENABLE_GOOGLE_AUTH=true
NEXT_PUBLIC_ENABLE_GITHUB_AUTH=truenpm run dev # Start dev server on localhost:3000
npm run build # Production build
npm run lint # ESLint checkDeployed on Vercel with automatic preview deployments on every push. Production environment uses separate env vars pointing to the live backend API.
Vercel environment variables (production):
NEXT_PUBLIC_APP_URL = https://linkpilot-blue.vercel.app
NEXT_PUBLIC_API_BASE_URL = https://linkpilot-url.vercel.app/api
NEXT_PUBLIC_BETTER_AUTH_URL = https://linkpilot-url.vercel.app
NEXT_PUBLIC_ENABLE_GOOGLE_AUTH = true
NEXT_PUBLIC_ENABLE_GITHUB_AUTH = true
Used Next.js 15 App Router to leverage React Server Components for data-heavy dashboard content, reducing the client-side JavaScript bundle and improving Core Web Vitals scores.
All API calls go through a typed service layer (/services/*.ts) rather than being scattered across components. This centralizes error handling, makes mocking trivial, and keeps components focused on rendering logic.
Chose better-auth because it's framework-agnostic — the same auth instance powers the Express backend and this Next.js frontend, keeping session behaviour consistent across the stack without duplicating logic.
Zod schemas are used both for form validation in the UI and for validating API responses. This creates a single source of truth for data shapes — type errors surface at build time, not in production.
The frontend (linkpilot-blue.vercel.app) and backend (smart-link-api.vercel.app) run on different Vercel deployments. Session cookies are configured with SameSite=None; Secure to allow cross-domain transmission while retaining HttpOnly protection.
- Session cookies are
HttpOnly— inaccessible to JavaScript - All form inputs validated with Zod before submission
- OAuth protected with CSRF-safe state parameter (handled by
better-auth) - Environment variables gated by
NEXT_PUBLIC_prefix — only safe values exposed to client - Auth endpoints rate-limited server-side (10 req/min per IP)
Suvra Deb Paul
- 📧 [email protected]
- 🐙 GitHub
- 🌐 Portfolio