The Next.js frontend for GoBank β a production-grade banking platform with multi-currency accounts, atomic peer-to-peer transfers, and institutional-grade authentication.
Built with a Revolut/Wise-inspired design language on a dark obsidian + gold palette.
GoBank Web is a full-featured banking dashboard that connects to the GoBank API (Go + gRPC-Gateway). It handles authentication, account management, fund transfers, and real-time activity feeds β all rendered with a Next.js App Router architecture that prioritises server-side data fetching and minimal client-side JavaScript.
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript (strict) |
| Styling | Tailwind CSS v4 |
| Auth | iron-session (AES-256 + HMAC cookie) |
| Validation | Zod v4 |
| HTTP client | Native fetch (server + client) |
| Toast | react-hot-toast |
| Icons | lucide-react |
| Testing | Vitest |
| Linting | ESLint (eslint-config-next) |
| Package manager | pnpm |
- Authentication β Login / Register / Logout with silent access-token rotation
- Email verification β One-click link verification flow with loading state
- Dashboard β Balance overview, account card carousel, live activity feed
- Accounts β Create (USD / EUR / EGP), view, delete; intercepted modal for smooth UX
- Transfers β 4-step wizard (source β recipient β amount β confirm) with real-time account lookup
- Settings β Update profile (name/email) and change password
- Middleware auth guard β Cookie-presence check at the Edge before every protected route
- Server-side token renewal β Access tokens silently refreshed on the server; no client exposure
- Node.js β₯ 20.9.0
- pnpm β₯ 10
- A running instance of the GoBank API (default:
http://localhost:8080)
pnpm installCopy the example below into a .env.local file in the project root:
# URL of the GoBank API (no trailing slash)
NEXT_PUBLIC_API_URL=http://localhost:8080
# iron-session encryption secret β must be β₯ 32 characters
# Generate with: openssl rand -hex 32
SESSION_SECRET=your-super-secret-32-char-minimum-key
# Public base URL for this Next.js app (used in sitemaps / OG metadata)
NEXT_PUBLIC_APP_URL=http://localhost:3000
SESSION_SECRETmust be at least 32 characters. iron-session uses AES-256 which requires a 256-bit key. If this is missing the app will fail to start.
pnpm devOpen http://localhost:3000.
| Command | Description |
|---|---|
pnpm dev |
Start development server with hot reload |
pnpm build |
Production build |
pnpm start |
Serve production build |
pnpm lint |
Run ESLint |
pnpm test |
Run Vitest (unit tests, single run) |
pnpm test:watch |
Run Vitest in watch mode |
| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_API_URL |
β | GoBank API base URL (e.g. http://localhost:8080) |
SESSION_SECRET |
β | iron-session key β min 32 chars, never commit this |
NEXT_PUBLIC_APP_URL |
β | App public URL, defaults to http://localhost:3000 |
src/
βββ app/ # Next.js App Router pages
β βββ (auth)/ # Login, register, verify-email (unauthenticated)
β βββ (dashboard)/ # Protected pages
β β βββ @modal/ # Parallel route for account creation modal
β β βββ (panel)/ # Accounts, transfers, settings (panel layout)
β β βββ dashboard/ # Main dashboard page
β βββ api/accounts/lookup/ # Route handler for client-side account lookup
β βββ layout.tsx # Root layout (fonts, providers)
β
βββ components/
β βββ accounts/ # Account list card, delete button, create form/modal
β βββ dashboard/ # Hero, activity feed, account carousel, smart brief
β βββ forms/ # Login + register forms
β βββ layout/ # Providers (Toaster)
β βββ Sidebar/ # AppSidebar, NavLink, LogoutButton
β βββ settings/ # Profile form, password form, section cards
β βββ transfers/ # TransferWizard (4-step)
β βββ ui/ # Badge, Button, Input, PanelHeader, AmbientGlow
β
βββ constants/ # Nav items and other shared constants
βββ lib/
β βββ actions/ # Server Actions (auth, accounts, transfers, settings)
β βββ accounts/ # Cached accounts snapshot (React cache)
β βββ api/ # API client (goApi, goPublicApi), types
β βββ auth.ts # requireAuth() guard
β βββ dashboard/ # Dashboard snapshot, view-models, formatters
β βββ session/ # iron-session config, get/save/destroy helpers
β βββ validation/ # Zod schemas (auth, settings)
β
βββ __tests__/ # Vitest unit tests
βββ validation.test.ts
βββ proxy.test.ts
βββ dashboard-activity.test.ts
The app heavily favours React Server Components. Client Components ("use client") are used only where strictly necessary:
- Interactive forms (use
useActionState) - Navigation state (sidebar toggle, active route)
- Toasts and dialog interactions
- The transfer wizard (multi-step state machine)
- Login β GoBank API returns
access_token+refresh_token - Both are sealed into an
HttpOnlycookie via iron-session (never exposed to browser JS) - On each request,
getAuthSession()checks token expiry server-side - If the access token is within 60s of expiry, it silently calls
/v1/auth/renew_access - The middleware only checks cookie presence (fast Edge check); full verification happens in RSCs via
requireAuth()
- Account data is fetched once per server render via
getAccountsSnapshot()(Reactcache()β deduplicates across RSCs in a single render tree) - Dashboard activity is fetched in parallel with accounts via
Promise.all - Mutations go through Server Actions β
revalidatePath()to bust the Next.js cache
pnpm testTests cover Zod validation schemas, middleware routing logic, and dashboard view-model transformations. They run in a Node environment with mocked next/headers and next/navigation.
Set NEXT_PUBLIC_API_URL to your deployed GoBank API endpoint:
NEXT_PUBLIC_API_URL=https://api.yourdomain.comMake sure the GoBank API's CORS config allows your frontend origin (see corsMiddleware in main.go).
MIT β see LICENSE for details.