Links is a full-stack link-in-bio style product: users get a public profile page with customizable design, ordered links, social icons, optional analytics, and a dashboard to manage everything. This repository is structured as a portfolio-grade monorepo (web + API + cloud deployment).
Live demo: https://links.fatihakyol.com/
The app separates a Next.js marketing and dashboard experience from a Node/Express API backed by MongoDB. Authentication uses sessions (cookie + server-side store), not JWT-on-client-only patterns. The UI combines Mantine, SCSS modules, and accessible drag-and-drop for link ordering. Production ships as two Docker images on Google Cloud Run, wired together via Cloud Build so the web build receives the deployed API URL automatically.
| Area | Highlights |
|---|---|
| Marketing | Landing page, responsive layout, SEO-friendly metadata on key routes |
| Auth | Register / login / logout / password change; session-backed flows |
| Dashboard | Links (create, edit, archive, reorder), design (backgrounds, typography, buttons), socials, page settings, analytics views |
| Public profile | Dynamic routes per username; rendered profile matching saved design |
| Media | File upload endpoint for assets (e.g. avatars), integrated with the web client |
| Ops | cloudbuild.yaml: build/push API → deploy API → inject URL → build/push web → deploy web |
- Next.js 16 (App Router), React 19, TypeScript
- Mantine v9 (UI, forms, notifications), Tabler Icons
- Sass (CSS modules), clsx
- Axios service layer with shared patterns for API calls
- Zustand + Immer for client state (e.g. page/editor state)
- Zod validation + mantine-form-zod-resolver
- @dnd-kit for sortable lists
- Express 5, TypeScript (ESM), tsx for development
- MongoDB via Mongoose
- Passport (local strategy), express-session with connect-mongo
- bcrypt for passwords, Multer for uploads
- Zod for request/schema validation
- CORS and production-oriented session cookie settings (e.g. SameSite behind proxies)
- Docker (
server/Dockerfile, client image via Cloud Build steps) - Google Cloud Build + Artifact Registry + Cloud Run (API + Web)
- Secrets for
MONGODB_URIandSESSION_SECRETvia Google Secret Manager (seecloudbuild.yaml)
Useful bullets for a portfolio or CV:
- Full-stack TypeScript: shared validation mindset (Zod) across client and server boundaries
- REST API design: modular routes (
auth,page,links,design,socials,analytics,upload) - Secure auth: session cookies, password hashing, authenticated middleware
- Rich UI/UX: dashboard layout, previews, responsive marketing pages, accessible DnD
- State management: normalized page model in the client store, optimistic-friendly patterns
- SSR/SSG awareness: App Router pages, dynamic public profile routes, metadata where appropriate
- Cloud-native delivery: multi-service deploy, env wiring, containerized workloads on Cloud Run
- DevEx: typed codebase, reproducible Docker builds
Requirements: Node.js, npm, and a running MongoDB instance.
-
API env — copy the example file and fill in values (never commit real secrets):
cp server/.env.example server/.env
-
Install & run API (from
server/):npm install npm run dev
-
Install & run web (from
client/):
Copy env template (adjust ports if your API differs):cp .env.example .env.local
Defaults match
client/src/config.ts; overrideNEXT_PUBLIC_API_URL/NEXT_PUBLIC_ASSET_URLif needed.npm install npm run dev
-
Open the URL printed by Next.js (often
http://localhost:3000) and confirm the API base URL matches your server.
- The demo is hosted on Cloud Run; the link above is the web service. The API is a separate Cloud Run service;
cloudbuild.yamlcan inject custom domains into the Next.js build (_NEXT_PUBLIC_API_URL,_NEXT_PUBLIC_ASSET_URL,_NEXT_PUBLIC_BASE_DOMAIN). - Session cookies + split domains (e.g.
links.fatihakyol.com+linksapi.fatihakyol.com): the API setsSESSION_COOKIE_SAME_SITE(defaultlaxin pipeline), optionalSESSION_COOKIE_DOMAIN(e.g..fatihakyol.com) so the session applies across subdomains, andCORS_ORIGINSmust list the exact frontend origin (https://links.fatihakyol.com). Seecloudbuild.yamlsubstitutionsfor the values used in this project. - After changing substitutions, redeploy the API so env vars update, then rebuild/deploy the web image so
NEXT_PUBLIC_*matches.
.
├── client/ # Next.js application
├── server/ # Express API
└── cloudbuild.yaml # GCP pipeline (API + Web)
Released under the MIT License: permissive open source—you may use, modify, and redistribute the code (commercial use included) if you keep the copyright and license notice. Software is provided as-is, without warranty.
Replace Links authors in LICENSE with your name if you prefer.
Never commit secrets (.env, keys, production secrets).