Skip to content

Repository files navigation

bank-web

English summary. Frontend of a banking application, built as a university project for two courses: Web Applications, and Information Systems in Banking. Next.js 16 (App Router, Server Components, Turbopack), React 19, TypeScript in strict mode with typed routes, Tailwind 4 and shadcn/ui, running on Bun.

It follows a BFF pattern: the browser never calls the API directly. Reads go through Server Components and writes through Server Actions, so access tokens stay on the server and never reach client-side JavaScript.

Covers registration and login with two-factor confirmation, dashboard, accounts, transfers, cards, loans, deposits, the KYC flow, user settings, and a separate admin area for approving KYC submissions, loans and deposits. It talks to bank-api.

The rest of this document is in Polish.

Zrzuty ekranu

Pulpit klienta Nowy przelew
Pulpit Nowy przelew
Włączanie 2FA (TOTP) Panel admina — użytkownicy
2FA Panel admina

Zrzuty pochodzą z lokalnego uruchomienia na danych z bun run db:seed:demo (efemeryczny Postgres z docker-compose.test.yml). Sekret TOTP widoczny na zrzucie należy do jednorazowego konta demo w bazie trzymanej w tmpfs.

Frontend aplikacji bankowej — projekt zaliczeniowy (Aplikacje Webowe + Systemy Informatyczne w Bankowości).

Stack

  • Runtime / PM: Bun 1.3+
  • Framework: Next.js 16 (App Router, Turbopack, Server Components)
  • React: 19
  • Style: Tailwind CSS 4 (CSS-first) + shadcn/ui (@base-ui/react jako primitives)
  • Form: react-hook-form + zod + @hookform/resolvers
  • Toast: sonner
  • TypeScript: strict + typedRoutes

Architektura (BFF pattern)

Frontend nigdy nie woła bank-api bezpośrednio z przeglądarki. Wszystkie wywołania API lecą przez:

  • Server Components — pobieranie danych (read)
  • Server Actions — mutacje (write, np. login, transfer)

Tokeny JWT (access + refresh) z bank-api są przechowywane wyłącznie w httpOnly cookies w domenie bank-web. Klient (przeglądarka) nigdy ich nie widzi.

┌───────────┐ httpOnly  ┌───────────────────────────┐ Bearer  ┌──────────┐
│ Browser   │ cookie    │  bank-web (Next 16)        │ JWT     │ bank-api │
│ (no JWT)  │◄─────────►│  Server Actions + RSC      │◄───────►│ (NestJS) │
└───────────┘           │  + proxy.ts (gate)         │         └──────────┘
                        └───────────────────────────┘

Wymagania

  • Bun ≥ 1.3
  • Działający bank-api (http://localhost:3001/api/v1)

Setup

bun install

cp .env.example .env.local
# uzupełnij BANK_API_URL i SESSION_SECRET (openssl rand -base64 64)

bun run dev    # http://localhost:3000

Skrypty

Komenda Opis
bun run dev Dev server (Turbopack)
bun run build Production build (standalone output)
bun run start Production server (po build)
bun run lint ESLint

Struktura aplikacji

app/
├── (auth)/                          # group route — brandowany shell
│   ├── layout.tsx
│   ├── login/page.tsx
│   ├── login/2fa/page.tsx           # krok TOTP po haśle
│   └── register/page.tsx
│
├── (dashboard)/                     # chronione strony klienta (server-side auth check)
│   ├── layout.tsx                   # /auth/me + nav + KYC banner + logout
│   ├── _components/                 # nav, account-card, transaction-row, kyc-banner
│   ├── dashboard/page.tsx           # suma sald + szybkie akcje + ostatnie transakcje
│   ├── accounts/                    # list, [id], new
│   ├── cards/                       # list, [id], new, new/success (reveal raz)
│   ├── transfers/                   # list, [id], new
│   ├── loans/                       # list, [id] (harmonogram), applications/new, applications/[id]
│   ├── deposits/                    # list, [id], products, products/[id]/open
│   └── kyc/                         # submit + status
│
├── admin/                           # panel admina (RoleGuard w layoucie)
│   ├── layout.tsx                   # sprawdza role === ADMIN
│   ├── _components/admin-nav.tsx
│   ├── page.tsx                     # dashboard ze stats
│   ├── kyc/                         # review queue (approve/reject z reason)
│   ├── loans/                       # pending list, [id] decision forms (approve/reject/disburse)
│   ├── deposits/products/           # CRUD produktów lokat
│   └── users/                       # lista z search, [id] z akcjami (suspend/activate/promote)
│
├── layout.tsx                       # root (Toaster, font, lang=pl)
└── page.tsx                         # / → redirect login lub dashboard

components/ui/                       # shadcn/ui — button, input, form, card, sonner, etc.
                                     # + link-button.tsx (Link + buttonVariants, bo nowy shadcn nie ma asChild)

lib/
├── api/
│   ├── client.ts                    # server-only fetch wrapper z auto-refresh 401
│   ├── types.ts                     # wszystkie typy API
│   ├── accounts.ts, cards.ts, transfers.ts, loans.ts, deposits.ts, kyc.ts, admin.ts
│   │                                # server-only queries
│   └── *-actions.ts                 # server actions (login, transfer, issue card, etc.)
├── auth/
│   ├── session.ts                   # httpOnly cookies (access/refresh/2fa-pending)
│   └── schemas.ts                   # zod schemas dla wszystkich formularzy
├── env.ts                           # zod-walidacja env (server vs client split)
├── format.ts                        # formatMoney, formatDate, labels (PL)
└── utils.ts                         # cn() z shadcn

proxy.ts                             # Next 16 Proxy (dawny middleware) — gate sesji
next.config.ts                       # standalone output + security headers + typedRoutes

Routes (skrót)

Klient (po zalogowaniu)

  • /dashboard — pulpit
  • /accounts, /accounts/[id], /accounts/new
  • /cards, /cards/[id], /cards/new, /cards/new/success
  • /transfers, /transfers/[id], /transfers/new
  • /loans, /loans/[id], /loans/applications/new, /loans/applications/[id]
  • /deposits, /deposits/[id], /deposits/products, /deposits/products/[id]/open
  • /kyc

Admin (role === ADMIN, w przeciwnym razie redirect /dashboard)

  • /admin — dashboard ze stats
  • /admin/kyc — kolejka wniosków
  • /admin/loans, /admin/loans/[id] — decyzja + wypłata
  • /admin/deposits/products, /admin/deposits/products/new
  • /admin/users, /admin/users/[id]

Bezpieczeństwo

  • httpOnly cookies dla tokenów (nigdy localStorage)
  • BFF pattern — klient nie widzi sekretów ani API URL
  • Security headers: X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy
  • proxy.ts: optimistic gate na chronione ścieżki (/dashboard, /accounts, /transfers, /cards, /admin, ...)
  • Layouty (dashboard) i admin/ robią pełną weryfikację przez API (defense-in-depth)
  • Walidacja env przez zod (fail-fast przy starcie)
  • Auto-refresh 401 w lib/api/client.ts (rotacja tokenów transparentna dla UI)
  • Idempotency keys generowane na kliencie przez crypto.randomUUID() przy każdej krytycznej operacji
  • Confirm dialogs przy nieodwracalnych akcjach (zamknięcie konta/karty, zerwanie lokaty, suspend usera)
  • CSP header — do dodania przed produkcją (po podpięciu konkretnych domen)

Notatki o Next 16

  • Middleware przemianowane na Proxy (proxy.ts, eksport proxy)
  • cookies(), headers(), params są async (await cookies())
  • Domyślnie Turbopack (bun run dev)
  • React 19 z React Server Components
  • typedRoutes włączone — redirect(...) i Link href weryfikowane w czasie kompilacji
  • Po dodaniu nowych ścieżek wymagany rebuild (bun run build) żeby zregenerować typy routes
  • Najnowsze shadcn używa @base-ui/react zamiast Radix — nie ma propu asChild w Button. Do linków stylizowanych jak buttony używamy <LinkButton> (components/ui/link-button.tsx).

About

Bank Web — Next.js 16 + Tailwind 4 + shadcn v4. Frontend aplikacji bankowej (BFF pattern). Projekt zaliczeniowy AW + SIB.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages