- Stack: Node.js, Express, Prisma, PostgreSQL, JWT, custom AES‑256‑GCM encryption.
- Entry point:
apps/backend/src/server.ts- Connects to the database via
config/database.ts. - Creates the Express app with
createAppfromsrc/app.ts. - Starts the HTTP server on the port from
config/env.ts.
- Connects to the database via
src/app.ts- Initializes
express()and global middleware:helmet()for basic security headers.cors()withorigintaken fromprocess.env.FRONTEND_URL(or*as a fallback) andcredentials: true.express.json()for JSON body parsing.- Custom logging middleware that measures request duration and logs
[METHOD] path - status - duration ms.
- Exposes a
/healthendpoint for simple health checks. - Mounts the main router from
src/routes/index.ts.
- Initializes
src/routes/index.ts- Composes feature routers:
/auth→ authentication routes./api/gonka→ routes that proxy/coordinate with the Gonka API./chats→ chat session and messaging routes./messages→ message‑level operations./developer→ developer API key and related routes.
- Composes feature routers:
- Layering:
- Routes: define URL structure and HTTP methods, wire up middlewares and controllers.
- Controllers (
src/controllers/*): handle HTTP input/output (validation, status codes, response shapes). - Services (
src/services/*): implement business logic, orchestrate database access and Gonka API calls.
src/config/database.ts- Exposes a single
PrismaClientinstance configured with:datasources.db.urlfromprocess.env.DATABASE_URL.- Logging of queries, errors and warnings.
- Provides helper functions to connect and disconnect on application start/shutdown.
- Exposes a single
prisma/schema.prisma- Defines the relational data model used by the backend (users, chats, messages, API keys, etc.).
- Migrations are stored under
apps/backend/prisma/migrations/*and applied viaprisma migrate.
- Wallet‑based authentication:
- The backend exposes auth endpoints (under
/auth) to:- Generate a nonce for a wallet address.
- Verify a signed message from the wallet.
- On successful verification, a JWT is issued and usually stored in a cookie on the frontend.
- The backend exposes auth endpoints (under
src/utils/jwt.ts- Uses
JWT_SECRETfrom environment variables (with a development fallback) to:signToken(payload)— create JWT tokens with a default lifetime (e.g. 7 days).verifyToken(token)— verify and decode tokens.
- Uses
src/middlewares/auth.middleware.ts(not detailed here)- Reads the JWT from the request (header/cookie).
- Verifies the token and attaches the authenticated user context to the request object.
- Protects routes that require authentication.
src/utils/encryption.ts- Uses AES‑256‑GCM for encrypting sensitive values.
ENCRYPTION_KEYis loaded fromprocess.env.ENCRYPTION_KEYand must be exactly 64 hex characters (32‑byte key).- Provides:
encrypt(text)→ returns base64‑encoded ciphertext and nonce.decrypt(ciphertextB64, nonceB64)→ restores original plaintext.computeContentHash(content)andverifyContentIntegrity(content, storedHash)for integrity checks using SHA‑256.
- Sensitive data such as secrets or API keys can be stored encrypted at rest in the database, and decrypted only at the moment of use in services.
src/services/gonka.service.ts- Lazily imports the
gonka-openaiSDK at runtime. - Resolves dynamic endpoints based on
GONKA_SOURCE_URLand caches them. - Instantiates a
GonkaOpenAIclient using:GONKA_SOURCE_URL(as API base).GONKA_PRIVATE_KEY(for authentication).
- Exposes:
gonkaChat(message, model?)— sends a chat completion request to a selected LLM.gonkaGetEndpoints()— returns resolved endpoints information.
- Lazily imports the
- Stack: Next.js App Router, React, TypeScript, Tailwind, Zustand, React Query, Wagmi/RainbowKit, Axios.
- Lives in
apps/web.
app/layout.tsx- Defines the HTML skeleton and global layout:
- Imports global styles and polyfills.
- Wraps the application in dynamic
Providers(client‑side only). - Renders persistent UI elements:
Navbar(sidebar navigation).Header(top bar).Transitionwrapper for page transitions/animations.
- Renders the
Toastercomponent for notifications (sonner).
- Defines the HTML skeleton and global layout:
app/providers.tsx- Sets up global client‑side providers:
- React Query client.
- Wagmi + RainbowKit for wallet connections.
- Custom Gonka provider and any shared context required by the app.
- Sets up global client‑side providers:
- Located in
apps/web/app/*:/— main landing/dashboard./chatand/chat/[id]— chat selection and active chat view./account— account summary, current balance, basic info./analytics— usage statistics and charts./developer-api— developer API keys management and documentation snippets./deposit— deposit/top‑up flows and transaction history./withdraw— withdrawal flows and transaction summary./bridge— UI for future bridge/swap functionality./settings— user and application settings.
Each page composes feature‑specific components from components/*.
components/*is organized by domain:components/chat/*— chat UI (messages, input, chat list, model selection, quick preview).components/account/*— account info and usage stats.components/analytics/*— charts and summary blocks for analytics.components/deposit/*andcomponents/withdraw/*— deposit/withdrawal cards, forms and history blocks.components/developer/*— API key creation and management UI.components/settings/*— settings sections and skeletons.components/ui/*— shared primitives such asbutton,modal,switcher,section-title,skeleton, etc.
- Shared UI primitives that may also be reused outside the app live in
packages/ui(e.g. reusablebutton,card,codecomponents).
- Zustand store (
apps/web/store/useChatStore.ts)- Holds chat‑related state:
chatsandcurrentChat.messageslist for the active chat.- loading/error flags and an
isActiveflag.
- Provides actions to:
- Load, create, select and delete chats (via
lib/chatAPI helpers). - Append user and assistant messages.
- Clear messages and toggle active status.
- Load, create, select and delete chats (via
- Holds chat‑related state:
- Hooks (
apps/web/hooks/*)- Encapsulate domain‑specific logic for:
- Authentication (
useAuth). - Chats (
useChats). - Developer API (
useDeveloperApi). - Gonka balance and price (
useGonkaBalance,useGonkaPrice). - Model selection (
useModelSelection). - Profile info (
useProfile).
- Authentication (
- Encapsulate domain‑specific logic for:
- Data fetching
- Centralized in
apps/web/lib/*:auth.ts— auth‑related calls, cookie name, helpers.gonkaClient.ts— low‑level Axios client for sending chat messages.chat.ts,developer-api.ts,gonkaClient.ts— higher‑level helpers for corresponding back‑end routes.
- Uses
NEXT_PUBLIC_API_BASE_URL(with a default ofhttp://localhost:5000) to reach the backend. - React Query is used (via providers) for caching and background refetching in hooks/components.
- Centralized in
- Wallet connection is initiated from the UI using Wagmi/RainbowKit components.
- After connecting, the app:
- Requests a nonce from the backend.
- Asks the wallet to sign a message containing the nonce.
- Sends the signed message back to the backend for verification.
- On success, the backend returns a JWT, typically stored in a
gonka_tokencookie. apps/web/lib/gonkaClient.tsand other API helpers:- Read the
gonka_tokencookie on the client. - Attach it as a
Bearertoken in theAuthorizationheader when calling backend endpoints.
- Read the
- User opens the web app
- Next.js serves the UI, sets up providers and wallet connection.
- Authentication
- The user connects a wallet and signs a backend‑provided nonce.
- The backend verifies the signature, mints a JWT and sends it to the frontend (cookie/header).
- Authorized API calls
- Frontend libraries (
lib/*.ts) attach the JWT to requests. - Express middleware verifies the token and identifies the user.
- Controllers call services, which:
- Read/write data via Prisma.
- Call the Gonka API via
gonka-openaifor LLM operations.
- Sensitive data handling
- Secrets and tokens are supplied via environment variables.
- Optional encryption utilities allow storing certain values encrypted in the database.
- JWT secrets and encryption keys should be strong and never committed to source control.
- Response back to the user
- Backend returns normalized JSON payloads.
- Frontend updates React state/Zustand store and UI components to reflect messages, balance, analytics, etc.