Ristek Link Frontend - Documentation
π Background
Overviewβ
The Ristek.Link Frontend is the web application for the RISTEK URL shortening service. It provides a public-facing interface for creating custom short URLs (single and bulk via Excel), generating customizable QR codes, viewing click analytics with charts, and managing user accounts with email/password or Google OAuth authentication. The application also handles short link resolution by rewriting incoming short URLs to the backend redirect API.
Stakeholdersβ
- Users: RISTEK members, general public (anonymous shortening)
- Upstream Dependencies: Ristek.Link Backend API, Google OAuth API, AWS S3 (bulk Excel downloads), Mixpanel (product analytics)
- Downstream Consumers: None (this is the end-user client application)
Scope & Boundariesβ
- In Scope: URL shortening UI (single and bulk), QR code generation with color/logo customization, click analytics dashboard (visitor, unique visitor, retention charts), user authentication (email/password + Google OAuth), password reset flow, "My URLs" management drawer, short link redirect resolution, maintenance mode, Terms of Service page.
- Out of Scope: Backend API logic, custom subdomain management (superuser-only backend feature), DNS configuration, mobile applications.
βοΈ Architecture & Design
System Diagramβ
Architecture Decisions (ADRs)β
- Language/Framework: JavaScript / Next.js 12.1.6 (Pages Router) / React 18.1.0
- State Management: React Context API (AuthContext, StateManagementContext, DrawerContext, BackdropContext)
- Styling: Tailwind CSS 3.0.24 + Chakra UI 2.0.2 + Emotion + styled-components (enabled via Next.js compiler)
- HTTP Client: Axios for all API calls
- Authentication: JWT stored in httpOnly cookie (UserAuthToken), verified server-side via Next.js API routes
- Charts: Chart.js 4.5.0 + react-chartjs-2
- QR Generation: @cheprasov/qrcode (SVG) + html-to-image (PNG export)
- Icons: Font Awesome (React) + custom SVG icons
- Product Analytics: Mixpanel (browser + server)
- Error Monitoring: Sentry (@sentry/nextjs)
- Ads Integration: @ristek-kit/ads (RISTEK ad platform)
- Deployment: Vercel via GitHub Actions
- Short Link Resolution: Next.js rewrites (/:shortLink* β /api/:shortLink*) handled by a catch-all API route
π»Technical Specifications
API Documentationβ
The frontend uses Next.js API routes (pages/api/) as a BFF (Backend-for-Frontend) proxy layer. Client-side code calls internal /api/* endpoints, which then forward requests to the Ristek.Link Backend with proper authentication headers. Backend base URL resolution (config/apiTarget.js):
| Environment | URL |
|---|---|
| production | API_URL env var |
| Other | DEV_API_URL env var |
Internal API Routes (pages/api/)β
| Endpoint | Method | Backend Proxy Target | Description |
|---|---|---|---|
/api/auth | GET | β | Validate JWT from UserAuthToken cookie, return token or status |
/api/auth | POST | POST /auth/login | Email/password login, sets httpOnly cookie |
/api/google | POST | POST /auth/google | Google OAuth login, sets httpOnly cookie |
/api/logout | POST | β | Clears UserAuthToken cookie |
/api/register | POST | POST /auth/register | User registration |
/api/resetPassword | POST | POST /auth/reset-password | Reset password with token |
/api/shorten | POST | POST /shorten | Create short URL |
/api/shorten | PUT | PUT /shorten | Edit existing short URL (auth required) |
/api/urls | GET | GET /shorten | List user's URLs (auth required) |
/api/analytic | GET | GET /analytics | Get analytics for a short URL (auth required) |
/api/generateQR | PATCH | PATCH /shorten/generate-qr | Generate custom QR code |
/api/bulkShortener | POST | POST /shorten/bulk | Bulk URL shortening from Excel |
/api/[...shortLink] | GET | POST /shorten/redirect | Resolve short link β redirect to target URL |
| Direct backend call (not proxied): |
POST /auth/forgot-passwordβ
Called directly from pages/login/forgot.js.
Pages & Routesβ
| Route | File | Auth Required | Description |
|---|---|---|---|
/ | pages/index.js | No | Landing page with URL shortener, QR generator, analytics (state-driven) |
/login | pages/login/index.js | No | Login (email/password + Google OAuth) |
/login/forgot | pages/login/forgot.js | No | Forgot password (sends reset email) |
/login/reset | pages/login/reset.js | No | Reset password (with JWT token from email) |
/register | pages/register/index.js | No | User registration |
/bulk-shortener | pages/bulk-shortener/index.js | No | Bulk URL shortening with Excel upload |
/terms-of-service | pages/terms-of-service.js | No | Terms of Service (13 content sections) |
/maintenance | pages/maintenance.js | No | Maintenance mode page (shown when MAINTENANCE_MODE=true) |
/404 | pages/404.js | No | Custom 404 page |
/:shortLink* | Rewrite β /api/[...shortLink] | No | Short link resolution and redirect |
State Management (React Context)β
| Context | File | State | Purpose |
|---|---|---|---|
| AuthContext | context/AuthContext/AuthContext.js | user, loggingIn, authStatus | Authentication state, login/logout/authenticate functions |
| StateManagementContext | context/StateManagementContext/StateManagementContext.js | state, dataLink, analyticState, rangeState, file, bulkShortenerState, processing | Landing page view state (shortener/QR/analytics), active link data, chart range |
| DrawerContext | context/DrawerContext/DrawerContext.js | drawerOpened, urls, loadingUrls, featureDrawerOpened | "My URLs" side drawer state, URL list, refresh function |
| BackdropContext | context/BackdropContext/BackdropContext.js | backdropActive | Overlay backdrop visibility |
| Auth status enum: | |||
| AUTHENTICATED (1) β valid JWT in cookie | |||
| NOT_AUTHENTICATED (2) β no token, no prior session | |||
| SESSION_EXPIRED (3) β had token but it's gone (shows toast) | |||
| TOKEN_UNVERIFIED (4) β token exists but failed verification (shows toast) |
Authentication Flowβ
- Email/Password Login: form submit β
POST /api/authβ API route proxies to backendPOST /auth/loginβ setsUserAuthTokenas an httpOnly, sameSite strict cookie βAuthContext.login()stores the user in state and localStorage. - Google OAuth Login:
@react-oauth/googleprovides token βPOST /api/googleβ API route proxies to backendPOST /auth/googleβ uses the same cookie flow. - Session Validation: on page load,
AuthContext.authenticate()callsGET /api/authβ API route readsUserAuthTokencookie β verifies JWT withjsonwebtokenusingJWT_SECRETβ returns token or status code (TOKEN_UNVERIFIED,TOKEN_DOES_NOT_EXIST). - Logout:
POST /api/logoutβ clears cookie β clears localStorage while preservinghasOpenandlastBulk. - Short Link Device Tracking:
DeviceIdcookie (UUID) is set on first short-link redirect for unique click analytics.
Short Link Resolutionβ
Short URLs (e.g. ristek.link/my-link) are resolved via:
- Rewrite:
/:shortLink*β/api/:shortLink* - Resolver:
pages/api/[...shortLink].jscalls backendPOST /shorten/redirectwith the short code andDeviceIdcookie. - Success:
302redirect to the target URL. - Failure: redirect to the Ristek Link homepage.
Project Structureβ
ristek.link-frontend/
βββ .github/
β βββ workflows/
β βββ deploy.yml # Production: push to main β Vercel prod
β βββ preview.yml # Staging: push to staging β Vercel preview
βββ components/
β βββ common/
β β βββ Backdrop/Backdrop.js # Overlay backdrop component
β β βββ Banner/ # Announcement banners
β β β βββ Banner.js # Banner UI
β β β βββ BannerContainer.js # Banner state management
β β βββ Button/index.js # Reusable button component
β β βββ FeatureDrawer/ # Mobile drawer for QR/Analytics
β β β βββ FeatureDrawer.js # Drawer container
β β β βββ components/ # Drawer sub-components
β β βββ Icon/ # CopyIcon, PngDownloadIcon, WarningIcon, etc.
β β βββ Input/Input.js # Reusable input component
β β βββ URLDrawer/ # "My URLs" side drawer
β β βββ URLDrawer.js # Drawer container with URL list
β β βββ URLCard.js # Single URL card (copy, edit, QR, analytics)
β β βββ OpenDrawerlogo.js # Drawer toggle button
β β βββ Logos.js # Drawer logo assets
β β βββ components/ # URLDrawerComponents/ sub-components
β βββ layout/
β β βββ Layout.js # Page wrapper (Navbar, Footer, Backdrop, FeatureDrawer)
β β βββ Footer/
β β β βββ Footer.js # Site footer
β β β βββ SocialContainer.js # Social media links
β β βββ Navbar/
β β βββ Navbar.js # Top nav with auth state, login/logout
β β βββ components/ # Navbar sub-components
β βββ pages/
β β βββ Analytic/ # Click analytics view
β β β βββ Analytic.js # Main analytics component with Chart.js
β β β βββ components/ # Chart, stats sub-components
β β βββ AuthPage/ # Login/register form components
β β β βββ FormHeader.js # Auth form header
β β β βββ FormFields.js # Auth form fields
β β β βββ components/ # Google button, form sub-components
β β βββ BulkShortener/ # Bulk URL shortening
β β β βββ BulkShortener.js # Multi-step bulk flow with Excel upload
β β β βββ component/ # Upload, progress, result sub-components
β β βββ GenerateQR/ # QR code generation
β β β βββ GenerateQR.js # QR generation with color picker
β β β βββ Preview.js # QR preview
β β β βββ QROption.js # QR customization options
β β β βββ ... # Download, option sub-components
β β βββ Landing/ # Main landing page
β β β βββ Landing.js # State-driven view (shortener/QR/analytics)
β β β βββ Container.js # Page container
β β β βββ ShortenerInput.js # Landing shortener input
β β β βββ ... # Success modal, input sub-components
β β βββ TermsOfService/ # Terms of Service
β β β βββ TermsOfService.js # ToS wrapper
β β β βββ (13 section components) # Individual ToS sections
β β βββ URLShotener/ # URL shortener feature
β β βββ URLShortener.js # Shortener container
β β βββ ShortenerInput.js # Form logic, validation, API call
β β βββ Logo.js # Shortener branding
β βββ utils/
β βββ useCustomToast.js # Chakra useToast wrapper
β βββ chart.js # Chart.js registration (scales, elements)
β βββ downloadFromS3.js # Download Excel results from S3
βββ config/
β βββ apiTarget.js # Backend API URL resolver (prod/dev)
β βββ awsConfig.js # AWS S3 config (bucket, keys)
βββ context/
β βββ AuthContext/AuthContext.js # Auth state, login/logout/authenticate
β βββ StateManagementContext/StateManagementContext.js # Landing page view state
β βββ DrawerContext/DrawerContext.js # URL drawer state
β βββ BackdropContext/BackdropContext.js # Backdrop overlay state
βββ hooks/
β βββ useWindowSize.js # Window dimension hook
β βββ useMixpanelClient.js # Mixpanel client-side tracking
β βββ useMixpanelServer.js # Mixpanel server-side tracking
βββ pages/
β βββ _app.js # App root (providers: Auth, Google OAuth, Chakra, Contexts, Ads, Layout)
β βββ _error.js # Error page with Sentry
β βββ 404.js # Custom 404
β βββ index.js # Landing page
β βββ maintenance.js # Maintenance mode page
β βββ terms-of-service.js # Terms of Service page
β βββ bulk-shortener/index.js # Bulk shortener page
β βββ login/
β β βββ index.js # Login page
β β βββ forgot.js # Forgot password
β β βββ reset.js # Reset password
β βββ register/index.js # Registration page
β βββ api/ # Next.js API routes (BFF proxy)
β βββ auth.js # Auth validation + login proxy
β βββ google.js # Google OAuth proxy
β βββ logout.js # Cookie clear
β βββ register.js # Registration proxy
β βββ resetPassword.js # Password reset proxy
β βββ shorten.js # Create/edit short URL proxy
β βββ urls.js # List user URLs proxy
β βββ analytic.js # Analytics proxy
β βββ generateQR.js # QR generation proxy
β βββ bulkShortener.js # Bulk shorten proxy
β βββ [...shortLink].js # Catch-all short link redirect
βββ public/
β βββ images/ # SVG assets (logos, icons, illustrations)
β βββ vercel.svg
βββ styles/
β βββ globals.css # Global styles (Poppins font, base resets)
β βββ theme.js # Chakra UI custom theme
βββ next.config.js # Next.js config (Sentry, env vars, rewrites, headers)
βββ tailwind.config.js # Tailwind config (custom colors, animations, JIT)
βββ postcss.config.js # PostCSS (Tailwind + autoprefixer)
βββ sentry.client.config.js # Sentry client initialization
βββ sentry.server.config.js # Sentry server initialization
βββ sentry.properties # Sentry org/project config
βββ .eslintrc.json # ESLint (next/core-web-vitals)
βββ .env.example # Environment variable template
βββ package.json # Dependencies and scripts
Componentsβ
| Layer | Paths | Responsibility |
|---|---|---|
| Landing Page | components/pages/Landing/Landing.js | The main view at /, driven by StateManagementContext.state. Switches between three sub-views: URL Shortener (default), QR Code Generator, and Analytics. Includes a success modal after shortening and integrates with the URL drawer for authenticated users. |
| URL Shortener | components/pages/URLShotener/ | Two-input form (long URL + custom alias). Validates URL format, checks for duplicate aliases, and calls POST /api/shorten. Supports both anonymous and authenticated shortening. Displays the resulting short link with copy-to-clipboard functionality. |
| Bulk Shortener | components/pages/BulkShortener/BulkShortener.js | Multi-step flow: (1) Excel file upload with template download, (2) processing indicator, (3) results summary (success/fail counts) with downloadable result Excel from S3. Max 100 links per batch. |
| QR Code Generator | components/pages/GenerateQR/ | Customizable QR code generation for existing short URLs. Features a color picker (react-colorful), optional RISTEK logo toggle, SVG preview, and PNG/SVG download via html-to-image and downloadjs. |
| Analytics Dashboard | components/pages/Analytic/ | Bar chart visualization using Chart.js showing visitor and unique visitor data. Supports three time ranges (week, month, six months) with pagination. Displays aggregate stats (total, average, max, min, percentage change). |
| URL Drawer | components/common/URLDrawer/ | Slide-in side panel showing authenticated user's URLs. Each URL card displays click counts, creation date, and provides actions: copy link, edit URL/alias, generate QR, view analytics. Includes search filtering. |
| Feature Drawer | components/common/FeatureDrawer/ | Mobile-optimized bottom drawer for accessing QR generation and analytics features on smaller screens. |
| Layout | components/layout/Layout.js | Page wrapper providing Navbar, Footer, Backdrop overlay, and the Feature/URL drawers. Applied globally via _app.js. |
| Navbar | components/layout/Navbar/Navbar.js | Top navigation with RISTEK logo, navigation links (Bulk Shortener, Terms of Service), and auth-aware UI (Login/Register buttons or user dropdown with logout). |
| App Root | pages/_app.js | Provider hierarchy: AuthContextProvider β GoogleOAuthProvider β ChakraProvider β StateManagementContextProvider β BackdropContextProvider β DrawerContextProvider β AdsProvider β Layout. Shows maintenance page when MAINTENANCE_MODE=true. |
βοΈ Operational Playbook
Infrastructureβ
- Cloud Provider: Vercel
- Production Deployment: Push to main branch β GitHub Actions (deploy.yml) β Vercel production deploy
- Staging Deployment: Push to staging branch β GitHub Actions (preview.yml) β Vercel preview deploy
- Link: https://ristek.link
Environment Variablesβ
(example)
| Key | Description | Default (Dev) | Sensitive? |
|---|---|---|---|
| API_URL | Backend API URL (production) | β | No |
| DEV_API_URL | Backend API URL (development) | β | No |
| NODE_ENV_TARGET | Environment selector (production / other) | β | No |
| JWT_SECRET | JWT verification secret (must match backend) | β | Yes |
| GOOGLE_CLIENT_ID | Google OAuth Client ID | β | Yes |
| SENTRY_DSN | Sentry DSN for error tracking | β | Yes |
| SENTRY_AUTH_TOKEN | Sentry auth token for source maps | β | Yes |
| NEXT_PUBLIC_AWS_BUCKET_NAME | S3 bucket for bulk Excel downloads | β | No |
| NEXT_PUBLIC_AWS_ACCESS_KEY_ID | AWS access key ID (client-side) | β | Yes |
| NEXT_PUBLIC_AWS_ACCESS_KEY_VALUE | AWS secret key (client-side) | β | Yes |
| NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN | Mixpanel project token for product analytics | β | No |
| MAINTENANCE_MODE | Enable maintenance page ("true" / "false") | "false" | No |
| WEBDEV_VERCEL_TOKEN | Vercel deploy token (GitHub Actions secret) | β | Yes |
| ORG_ID | Vercel organization ID (GitHub Actions secret) | β | Yes |
| PROJECT_ID | Vercel project ID (GitHub Actions secret) | β | Yes |
πQuestions
π List of frequently asked questions or question that need to be answered that is related to this initiative ..