This repository contains the Next.js frontend for NeuroWealth. It's a demo-ready frontend with mock authentication, UI components, and client-side adapters that let the app run without a backend.
Assumptions: This frontend targets the Stellar testnet by default (NEXT_PUBLIC_STELLAR_NETWORK=testnet). For production, configure NEXT_PUBLIC_STELLAR_NETWORK=mainnet and provide a real API backend via NEUROWEALTH_API_BASE_URL.
This project uses Yarn 1 (Classic) as the package manager. The exact version is pinned in the
packageManager field of package.json (yarn@1.22.22).
Do not use npm install or pnpm install — they will produce a different lockfile format and
break the Corepack pin. Always run yarn install to install dependencies.
The lockfile (yarn.lock) is committed to the repository. After adding or upgrading packages,
commit the updated yarn.lock alongside the package.json change.
Next.js uses the SWC compiler for both development (Fast Refresh) and production builds. No Babel configuration is present; SWC is the default when using Next.js 13+. The SWC binary is resolved automatically by Next.js — no extra install step is needed.
Requirements: Node.js 20+, Yarn (Corepack supported)
Install and run:
# Enable the pinned yarn version via Corepack (run once per machine)
corepack enable
corepack prepare
yarn install
yarn devRun tests:
yarn testInspect bundle size locally:
yarn analyzeThis runs a production build with the Next.js bundle analyzer enabled via ANALYZE=true.
The report is written under .next/analyze/, which is already ignored by git.
Use this command when checking for bundle regressions before merging. We do not run it in CI because analyzer builds are slower than the normal test/lint/build pipeline.
- Next.js 14 app under
src/app - Client-side mock auth (
src/lib/mock-auth.ts) that persists an in-browser session inlocalStorageand mirrors it to a non-httpOnly cookie somiddleware.tscan perform edge-side redirects. - Edge middleware (
middleware.ts) that protects routes under/dashboard,/profile, and/settingsand redirects unauthenticated users to/login?from=.... - Tests using the Node test runner (match:
src/**/*.test.ts).
src/
├── app/ # Next.js App Router — routes and layouts
│ ├── (auth)/ # Auth-gated route group (login, onboarding)
│ ├── (errors)/ # Standalone error pages (401 unauthorized, 403 forbidden)
│ ├── api/ # Route handlers
│ ├── dashboard/ # Protected dashboard shell and sub-routes
│ │ ├── dev-errors/ # Dev-only error trigger routes (hidden in production)
│ │ ├── portfolio/
│ │ ├── activity/
│ │ ├── strategy/
│ │ └── settings/
│ ├── not-found.tsx # Global 404 page
│ └── error.tsx # Global 500 / uncaught error boundary
├── components/ # Shared UI components (ui/, dashboard/, auth/, layout/)
├── features/ # Feature-scoped logic co-located with its UI
├── hooks/ # Reusable React hooks
├── lib/ # Pure utilities, constants, and adapters
│ ├── mock-auth.ts # Client-side mock auth session
│ ├── auth-constants.ts # Canonical storage/cookie key names
│ └── …
└── types/ # Shared TypeScript types and interfaces
TypeScript strict mode is enabled (tsconfig.json → "strict": true).
Lint runs via yarn lint (ESLint + eslint-config-next).
See docs/env.md for the full variable reference, including the public/server-only split,
Edge middleware constraints, and runtime validation notes. Typed accessors and validation
live in src/lib/env.ts — each field is documented with its corresponding env var name.
The frontend supports two runtime modes controlled by server-only env vars (see
src/lib/env.ts and NEUROWEALTH_API.md):
| Mode | Condition | Behaviour |
|---|---|---|
| Demo / mock | NEUROWEALTH_API_BASE_URL unset |
All /api/* route handlers return in-process mock data (source: "demo"). No backend required — default for local dev and PR previews. |
| Real API | NEUROWEALTH_API_BASE_URL set |
Route handlers proxy to the backend via createServerApiClient() with Authorization: Bearer <NEUROWEALTH_API_AUTH_TOKEN>. |
| Browser calls | Next.js route | Backend path (when configured) |
|---|---|---|
| Portfolio data | GET /api/portfolio |
GET {NEUROWEALTH_PORTFOLIO_PATH} (default /portfolio/overview) |
| Transactions | POST /api/transactions |
POST {NEUROWEALTH_TRANSACTIONS_PATH} (default /transactions) |
| Strategy | GET/PUT /api/strategy |
GET/PUT {NEUROWEALTH_STRATEGY_PATH} (default /strategy/preference) |
Browser → Next.js requests authenticate via the httpOnly session cookie (nw_session).
Next.js → backend requests require the Bearer token — never expose it to the client bundle.
| Hop | Required headers |
|---|---|
Browser → /api/* |
Accept: application/json; Content-Type: application/json on writes; session cookie |
| Server → backend | Accept: application/json; Authorization: Bearer <NEUROWEALTH_API_AUTH_TOKEN> |
All /api/* responses use the unified envelope defined in src/lib/api-response.ts:
{ "success": true, "data": { } }
{ "success": false, "error": { "code": "ERROR_CODE", "message": "…", "details": { } } }The typed client in src/lib/api-client.ts unwraps success payloads and throws ApiRequestError
on failure. Built-in client error codes include REQUEST_TIMEOUT (408), NETWORK_ERROR (503),
INVALID_JSON, and INVALID_ENVELOPE. Backend codes are forwarded verbatim.
Use useAsyncData((signal) => apiRequest("/api/…", { signal })) so in-flight requests abort on
unmount. See NEUROWEALTH_API.md and docs/api-integration.md
for full endpoint schemas and integration checklists.
The React provider tree is composed in src/components/ClientProviders.tsx in the following order (outer to inner):
ClientProviders
├── SandboxProvider # Dev-only error trigger context
├── ThemeProvider # Dark/light theme with localStorage persistence
├── I18nProvider # Internationalization & locale state
├── AuthProvider # User session: localStorage ↔ cookie sync
├── WalletProvider # Stellar wallet connection (network-aware)
├── ToastProvider # Toast notifications & alerts
└── CookieConsentProvider # Privacy & cookie banner state
└── ErrorTrackingMount # Global error tracking (unhandledrejection, window errors)
└── children
└── CookieBanner, PrivacyModal
Provider order matters: Each provider depends on layers below it. For example, ThemeProvider is initialized before AuthProvider so theme preferences load before the user checks authentication.
-
Authentication:
- User signs in via
/login→AuthContext.signIn()→mock-auth.tscreates session - Session stored in
localStorage(key:SESSION_STORAGE_KEY) - Session mirrored to httpOnly cookie (key:
SESSION_COOKIE_NAME) for middleware - Middleware (
middleware.ts) reads cookie to redirect unauth users - Sign-in on other tabs triggers
storageevent → all tabs sync
- User signs in via
-
Stellar wallet integration:
WalletProviderresolves network based onNEXT_PUBLIC_STELLAR_NETWORKenv (testnet/mainnet)- Horizon URL configurable via
NEXT_PUBLIC_STELLAR_HORIZON_URL(falls back to public nodes) useWallet()hook provides wallet state and account info
-
API requests:
- Browser → Next.js
/api/*routes: authenticated via httpOnly cookie (no extra header needed) - Next.js → Real backend: use
createServerApiClient()in route handlers to inject Bearer token (fromNEUROWEALTH_API_AUTH_TOKENenv) - All responses must conform to the standard envelope (see NEUROWEALTH_API.md)
- Demo mode (no backend): all
/api/*routes return mock data
- Browser → Next.js
-
Internationalization:
- Active locale stored in
localStorage(key fromauth-constants.ts) dictionariesmap locale codes to message objects- All formatters (
formatCurrency,formatDate, etc.) usegetActiveIntlLocale()for locale-aware output
- Active locale stored in
-
Theme:
- Light/dark mode persisted to
localStorage - CSS variables injected into
:rootfor tailwind theming ThemeProviderinitializes before auth so theme loads without flash
- Light/dark mode persisted to
The mock auth flow stores the session in localStorage using SESSION_STORAGE_KEY and mirrors it into a cookie named SESSION_COOKIE_NAME. This allows the browser UI and Next.js middleware to agree on authentication state in demo setups. See src/lib/auth-constants.ts for the canonical values.
- Follow existing patterns for components and hooks.
- Tests live next to logic under
src/and run viayarn test. - For bundle-size checks, run
yarn analyzelocally and review the generated report before changing code that affects route or vendor bundles. - Use
data-qaonly for smoke-flow anchors, with kebab-case names that describe the flow and action, for examplelanding-primary-cta-button,wallet-connect-button, andtransaction-submit-button.
To report a vulnerability or for our handling and response expectations, see SECURITY.md. Please do not file public issues for security reports.
Internal/demo project — see repository owner for license details