-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
harshcode1 edited this page Jun 20, 2026
·
1 revision
BetterMind is a single Next.js 14 application using the App Router. The same deployment serves the UI (React Server/Client Components) and the backend (/api/* Route Handlers), talking to MongoDB and a few optional external services.
┌─────────────────────────────────────────────────────────────────────┐
│ Next.js 14 (App Router) │
│ │
│ ┌─────────────────────────┐ ┌──────────────────────────────┐ │
│ │ Client Components │ fetch │ Route Handlers │ │
│ │ │ ──────► │ │ │
│ │ AuthContext │ JSON │ /api/auth/* (login, 2FA) │ │
│ │ (user + guest + gate) │ ◄────── │ /api/mood, /api/assessment │ │
│ │ │ │ /api/chat (OpenAI) │ │
│ │ Pages: │ │ /api/doctors, /appointments │ │
│ │ dashboard, mood, │ │ /api/doctor/* /api/admin/* │ │
│ │ assessment, chat, │ │ │ │
│ │ doctors, appointments, │ │ verifyAuth() on every │ │
│ │ resources, settings │ │ protected handler │ │
│ └─────────────────────────┘ └───────────────┬───────────────┘ │
└──────────────────────────────────────────────────────┼─────────────────┘
│
┌────────────────────┬────────────────────┬─────┴──────────────┐
│ │ │ │
┌─────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ ┌────────▼────────┐
│ MongoDB │ │ OpenAI │ │ Google APIs │ │ otplib (TOTP) │
│ (driver) │ │ gpt-4o-mini │ │ Calendar │ │ + AES crypto │
└────────────┘ └─────────────┘ └─────────────┘ └─────────────────┘
required optional optional local
- A client page calls
fetch('/api/...'). The browser automatically attaches the httpOnlytokencookie. - The Route Handler reads the cookie and calls
verifyAuth(token)fromlib/authServer.js. -
verifyAuthchecks an in-memory cache (5-minute TTL keyed by token). On a miss itjwt.verifys the token and confirms the user still exists in MongoDB, then caches the result. - The handler enforces role (
patient/doctor/admin) and returns JSON. - The client renders.
AuthContextalready knows the current user from/api/auth/checkon mount.
-
Client Components drive the interactive pages (
'use client') because they rely onAuthContext, animations, and live data fetching. -
Route Handlers are marked
export const dynamic = 'force-dynamic'because they depend on per-request cookies and must never be statically cached. - Pages that read
useSearchParams()(e.g.login,login/2fa,appointments/new) are wrapped in<Suspense>to satisfy the App Router's streaming requirements.
| Collection | Purpose | Notable fields |
|---|---|---|
users |
All accounts |
name, email, password (bcrypt), role, verified, twoFactorAuth
|
doctors |
Doctor profiles |
userId, specialty, credentials, licenseNumber, workingHours, reviews[], averageRating, googleTokens, rejected, rejectionReason
|
moods |
Daily mood logs |
userId, mood (1–10), activities[], notes, createdAt
|
assessments |
PHQ-9 / GAD-7 results |
userId, phq9Score, gad7Score, phq9Answers[], gad7Answers[], severities, date
|
appointments |
Bookings |
patientId, doctorId, dateTime, status, googleEventId, notes
|
-
Custom JWT over a turnkey auth framework. Gives full control of the 2FA challenge (issue the JWT only after TOTP verification) and consistent role gating.
next-authwas removed during the audit because it was installed but unused — mixing two auth systems is a liability. -
Auth-result caching.
verifyAuthcaches verification per token for 5 minutes to avoid a DB round-trip on every single API call. -
Graceful degradation by default. The AI chat falls back to keyword→specialist matching without
OPENAI_API_KEY; Calendar sync no-ops without OAuth tokens; the MongoDB URI check is deferred to request time so the app can boot in environments where it's intentionally absent. - Guest Mode is a client concern only. No fake server session is created. Demo data is generated client-side and writes are intercepted, so the database is never touched by a guest. See Guest-Mode.
- Reusable rate-limiter factory instead of bespoke logic per route — see Authentication-and-Security.