A blockchain investigation, AML/CFT and fraud analysis dashboard built with Next.js 14 (App Router), TypeScript, Tailwind CSS, Redux Toolkit and React Flow.
The app lets analysts log in, explore multichain wallet transaction graphs, and run AML/fraud risk analysis on individual wallet addresses, complete with drawers for risk indicators, portfolio breakdowns, reports, and a printable PDF export.
Note: This project was developed as part of an internship. It is a frontend built on top of Defy's existing backend APIs, and it talks to a test environment (
test.getdefy.co/testdashboard.getdefy.co).
- Email/password login backed by the Defy auth API, using JWT tokens.
- Token expiry is validated client-side before protected pages render.
- Session persistence in
localStorage, restored on load through auseAuthhook. - Forgot-password flow with reset-token confirmation.
- Investigation list with pagination, and a graph view rendered with
@xyflow/react. - Multichain support: wallets and transfers from multiple networks (Ethereum, BSC, Polygon, …) in a single unified graph.
- Custom wallet nodes and floating transfer edges, with edge colors driven by wallet risk status (red = risky, blue = safe, gray = neutral).
- Token picker with an "All Tokens" mode plus per-token filtering, and an independent network filter with network badges.
- Wallet search to add new addresses to a graph directly from the canvas.
- Drag-and-drop node layouts that can be saved back to the API (network codes normalized to a canonical format before saving).
- Transaction drawer for a selected wallet, with infinite scroll over its transfers.
- AML wallet list with live search over addresses, plus wallet deletion.
- Wallet detail view with tabbed sections, network picker, and an overview powered by the AML APIs (
aml,aml_fast,wallet_detail,networks,tags). - Sankey visualization of transaction flows.
- Risk Analysis drawer for drilling into individual risk indicators.
- Portfolio drawer with links out to the relevant block explorer per network.
- Report drawer, share-link copying, and a dedicated print view for exporting the analysis as PDF.
- Navigation state is synced to the URL (
?tab=…), so views are shareable and survive refreshes. - Server-side API route handlers under
app/api/**proxy requests to the Defy backend and forward the caller'sAuthorizationheader.
| Area | Choice |
|---|---|
| Framework | Next.js 14 (App Router) |
| Language | TypeScript 5 |
| Styling | Tailwind CSS 3 + shadcn/ui-style components (cva, clsx, tailwind-merge) |
| State | Redux Toolkit + React Redux |
| Graph | @xyflow/react (React Flow) |
app/
api/ # Route handlers proxying the Defy backend
analyze/dashboard/ # aml, aml_fast, networks, tags, token_list, wallet_detail
investigate/ # list, get, save, search_address, token_list, transactions
liveaml/ # list, search, delete
coefficients/
dashboard/ # Main shell: sidebar + tab-driven views
login/ forgot-password/ # Auth pages
components/
aml/ # AmlView, AmlDetailView, Sankey, Risk/Portfolio/Report drawers
investigations/ # InvestigationGraph, WalletNode, TransferEdge, TokenPicker, TxDrawer
ui/ # Button, Input, Label primitives
hooks/useAuth.ts # Session restore + auth guard
lib/
api/ # Typed clients: auth, analyze, investigations, liveaml, coefficients
investigations/ # Graph types + API→graph adapter
jwt.ts authStorage.ts # Token decoding and localStorage persistence
store/ # Redux store, auth slice, investigation slice
Requires Node.js 18+.
npm installnpm run devThen open http://localhost:3000 and sign in with a Defy test account.
| Command | Description |
|---|---|
npm run dev |
Start the development server |
npm run build |
Production build |
npm start |
Serve the production build |
npm run lint |
Run ESLint via next lint |
Upstream URLs are currently hardcoded to the test environment:
- Auth:
https://test.getdefy.co/v2/auth - Data APIs:
https://testdashboard.getdefy.co/api/proxy/...
To point at another environment, update the BASE_URL / UPSTREAM constants in lib/api/*.ts and app/api/**/route.ts (or move them into environment variables).