Real-time multiplayer chess platform with lobby and in-game chat, leaderboards, and support for guest and registered players.
weChess follows a decoupled architecture with a Mindbricks-generated Node.js microservices backend and a standalone React SPA frontend.
┌──────────────────────────────────────────────────────────────┐
│ Frontend (React SPA) │
│ React 19 · Vite 7 · TypeScript · Tailwind CSS v4 │
│ Zustand (state) · TanStack Query (data) · Socket.IO │
└──────────────────┬───────────────────────────────────────────┘
│ HTTPS / WSS
▼
┌──────────────────────────────────────────────────────────────┐
│ API Gateway (Frontgate / BFF) │
│ https://wechess.mindbricks.co │
└──────┬───────┬───────┬───────┬───────┬───────┬──────────────┘
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
┌──────┐┌──────┐┌──────┐┌──────┐┌──────┐┌──────┐
│ Auth ││Game- ││InGame││Lobby ││Leader││Notif.│
│ ││ play ││ Chat ││ Chat ││board ││ │
└──────┘└──────┘└──────┘└──────┘└──────┘└──────┘
PostgreSQL databases per service · Redis for real-time
| Service | Route Prefix | Port | Purpose |
|---------|-------------|------|---------|
| auth | /auth-api | 3011 | User registration, login, JWT tokens, roles, verification, password reset, 2FA |
| gameplay | /gameplay-api | 3000 | Game CRUD, matchmaking, moves, invitations, game lifecycle, WebSocket game hub |
| ingamechat | /ingamechat-api | 3000 | In-game chat messages, moderation, WebSocket chat hub |
| lobbychat | /lobbychat-api | 3000 | Lobby rooms, lobby messages, moderation, WebSocket lobby hub |
| leaderboard | /leaderboard-api | 3000 | ELO ratings, player stats, leaderboard rankings |
| notification | — | — | Email/SMS templates for verification, 2FA, password reset |
| bff | — | — | Backend-for-Frontend aggregation layer |
| mcpbff | — | — | MCP (Model Context Protocol) BFF for AI integrations |
| document | — | — | Static documentation server with Flexsearch |
| frontgate | — | — | API gateway / routing layer |
Mindbricks is an AI-driven backend development platform that generates production-ready Node.js microservices from declarative project configurations. Instead of writing backend code manually, you define your data models, APIs, business logic, and authentication in a structured configuration — Mindbricks generates and deploys the entire backend.
-
Project ID:
19cbe0a3-ff70-4285-968b-504239115f3d -
Project Codename:
wechess -
Production URL:
https://wechess.mindbricks.co
There are two ways to work with the Mindbricks backend:
-
Mindbricks Web UI: Navigate to
https://app.mindbricks.comand open the weChess project -
Mindbricks MCP Server (in Cursor): Use the integrated MCP tools directly from the IDE
When working in Cursor with the Mindbricks MCP server connected, these are the primary tools:
| Tool | Purpose |
|------|---------|
| getProjectOverview | See the top-level project structure |
| readAt | Read configuration at any path (e.g., services/gameplay/dataObjects/chessGame) |
| updateAt | Update configuration — deep merges changes with existing data |
| deleteAt | Remove items (properties, data objects, APIs, services) |
| validateService / validateProject | Catch configuration errors before building |
| buildServiceRepo | Regenerate code and push to GitLab (triggers auto-deploy) |
| getPreviewStatus | Check which version is running on the preview environment |
| getPreviewLogs / getServicePreviewLogs | Debug runtime errors in the preview |
| httpRequest | Test API endpoints directly from Cursor |
| loginAsSuperadmin | Get an authenticated token for testing |
| getServiceApiDocument | Get the full API specification for a service |
| getOntologyDocByPath | Learn the schema for a specific configuration path |
| getOntologyTree | See the full configuration hierarchy |
1. Understand current state
└─> getProjectOverview / readAt
2. Consult the ontology (schema)
└─> getOntologyDocByPath / getOntologyDocByPatternName
3. Make changes
└─> updateAt (deep merge) / deleteAt (remove items)
4. Validate
└─> validateService / validateProject
5. Build & Deploy
└─> buildServiceRepo → auto-deploys via GitLab webhook
6. Verify deployment
└─> getPreviewStatus (poll until commitId matches and status = "ready")
7. Test
└─> loginAsSuperadmin → httpRequest to live endpoints
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| playerWhiteId | ID | Yes | References auth:user.id |
| playerBlackId | ID | No | References auth:user.id |
| createdById | ID | Yes | Who created the game |
| status | Enum | Yes | pending, active, paused, completed, terminated |
| mode | Enum | Yes | public, private |
| gameType | Enum | Yes | timed, untimed, blitz, rapid |
| currentFEN | String | Yes | Board state in FEN notation |
| invitationCode | String | No | For private games |
| result | Enum | No | whiteWin, blackWin, draw, aborted |
| saveStatus | Enum | Yes | notSaveable, requested, paused |
| saveRequestWhite | Boolean | No | White's save/pause request |
| saveRequestBlack | Boolean | No | Black's save/pause request |
| terminatedById | ID | No | Admin who terminated |
| guestPlayerWhite | Boolean | No | Is white a guest? |
| guestPlayerBlack | Boolean | No | Is black a guest? |
| movedAt | DateTime | No | Last move timestamp |
| reportStatus | Enum | No | none, reported, underReview |
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| gameId | ID | Yes | References chessGame.id |
| movedById | ID | Yes | References auth:user.id |
| moveNotation | String | Yes | Standard algebraic notation |
| moveNumber | Integer | Yes | Sequential move number |
| moveTime | Integer | No | Time taken in milliseconds |
| moveTimestamp | DateTime | Yes | When the move was made |
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| gameId | ID | Yes | References chessGame.id |
| senderId | ID | Yes | Who sent the invitation |
| recipientId | ID | Yes | Who receives it |
| status | Enum | Yes | pending, accepted, declined, cancelled |
| expiresAt | DateTime | Yes | Invitation expiry |
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| gameId | ID | Yes | Which game this message belongs to |
| content | String | Yes | Message text |
| removed | Boolean | No | Soft-removed by moderation |
| reportStatus | Enum | No | none, reported, underReview |
Lobby rooms are created per day. Messages belong to rooms and support moderation (remove, report, mute).
Tracks ELO ratings, win/loss/draw counts, streaks, and ranked standings.
1. Fetch the ontology for DataObject:
getOntologyDocByPatternName("DataObject")
2. Create the data object:
updateAt("wechess", "services/gameplay/dataObjects/tournament", {
objectSettings: {
basicSettings: { name: "tournament" },
authorization: { dataObjectAccess: "accessPrivate" }
},
properties: [
{
basicSettings: { name: "name", type: "String", isRequired: true, allowUpdate: true },
indexSettings: { indexedInDb: true }
},
{
basicSettings: { name: "startDate", type: "DateTime", isRequired: true, allowUpdate: true }
}
]
})
3. Add business APIs for it:
updateAt("wechess", "services/gameplay/businessLogic/createTournament", { ... })
4. Validate:
validateService("wechess", "gameplay")
5. Build:
buildServiceRepo("wechess")
1. Fetch the ontology:
getOntologyDocByPatternName("BusinessApi")
2. Define the API:
updateAt("wechess", "services/gameplay/businessLogic/getActiveGames", {
basicApiSettings: {
name: "getActiveGames",
type: "custom",
httpMethod: "get",
httpRoute: "/v1/activegames",
authorization: { ... }
},
actions: { ... }
})
3. Validate and build as above.
The project uses role-based access control (RBAC) with three roles:
| Role | Value | Description |
|------|-------|-------------|
| Guest | guest | Auto-registered temporary users, limited features |
| Registered Player | registeredPlayer | Full access to games, leaderboard, chat |
| Administrator | administrator | Full access + user management, game moderation, chat moderation |
-
Preview environments auto-deploy when code is pushed via
buildServiceRepo -
Cold previews (inactive) can be woken with
wakeupPreview -
Use
getPreviewStatusto get live service URLs -
Use
getPreviewLogs/getServicePreviewLogsfor debugging -
Use
restartPreviewServiceif a service missed an update
| Technology | Version | Purpose |
|-----------|---------|---------|
| React | 19.2 | UI framework |
| TypeScript | 5.9 | Type safety |
| Vite | 7.3 | Build tool and dev server |
| Tailwind CSS | 4.2 | Utility-first styling |
| Zustand | 5.0 | Lightweight state management |
| TanStack Query | 5.90 | Server state, caching, data fetching |
| React Router | 7.13 | Client-side routing |
| Socket.IO Client | 4.8 | Real-time WebSocket communication |
| chess.js | 1.4 | Chess logic and move validation |
| react-chessboard | 5.10 | Interactive chess board UI |
| Axios | 1.13 | HTTP client |
frontend/
├── index.html # HTML shell
├── vite.config.ts # Vite config (React, Tailwind, aliases, code-splitting)
├── tsconfig.json # TypeScript project references
├── tsconfig.app.json # App TS config (paths: @/* → ./src/*)
├── eslint.config.js # ESLint flat config
├── package.json
├── Dockerfile # Production Docker build
├── nginx.conf # Production Nginx config
├── .gitlab-ci.yml # CI/CD pipeline (Docker build on main)
└── src/
├── main.tsx # Entry point
├── App.tsx # Root component (providers, routing)
├── index.css # Global styles (Tailwind imports)
│
├── api/ # API layer (Axios clients + service modules)
│ ├── clients.ts # Base URL config, interceptors, service clients
│ ├── auth.ts # Auth service API functions
│ ├── gameplay.ts # Gameplay service API functions
│ ├── chat.ts # In-game chat API functions
│ ├── lobby.ts # Lobby chat API functions
│ ├── leaderboard.ts # Leaderboard API functions
│ ├── bucket.ts # File upload (S3 bucket) API
│ └── mcpbff.ts # MCP BFF API functions
│
├── components/ # Shared UI components
│ ├── Header.tsx # Global navigation header
│ ├── ProtectedRoute.tsx # Auth guard (supports requireAdmin)
│ ├── ErrorBoundary.tsx # React error boundary
│ ├── Toast.tsx # Toast notification system (ToastContainer)
│ ├── NotificationCenter.tsx
│ ├── ChatPanel.tsx # Reusable chat panel component
│ └── SecretField.tsx # Hidden/reveal input field
│
├── pages/ # Route-level page components
│ ├── Home.tsx # Landing page
│ ├── Login.tsx # Login form
│ ├── Register.tsx # Registration form
│ ├── Verification.tsx # Email/mobile verification
│ ├── ForgotPassword.tsx # Password reset flow
│ ├── Email2FA.tsx # Two-factor authentication
│ ├── Profile.tsx # User profile management
│ ├── GameLobby.tsx # Game lobby with matchmaking
│ ├── GamePlay.tsx # Active chess game with board
│ ├── GameHistory.tsx # Past games viewer
│ ├── Leaderboard.tsx # Rankings and stats
│ ├── ComputerPlay.tsx # Play against AI (offline)
│ ├── UserManagement.tsx # Admin: manage users
│ ├── AdminGames.tsx # Admin: manage games
│ └── AdminChat.tsx # Admin: moderate chat
│
├── hooks/
│ └── useAuth.ts # Authentication hook (login, logout, guest, session restore)
│
├── stores/ # Zustand state stores
│ ├── authStore.ts # Auth state (user, tokens, isAuthenticated)
│ └── notificationStore.ts # In-app notification state
│
├── lib/ # Utility libraries
│ ├── socketManager.ts # WebSocket hub manager (game, chat, lobby hubs)
│ ├── gameTypeConfig.ts # Game type definitions and settings
│ ├── lobbyRoomUtils.ts # Lobby room ID generation
│ ├── notificationSounds.ts
│ └── utils.ts # General utilities
│
├── types/
│ └── index.ts # TypeScript interfaces for all domain entities
│
└── assets/ # Static assets (currently empty)
| Path | Component | Auth Required | Admin Only |
|------|-----------|:---:|:---:|
| / | Home | No | No |
| /login | Login | No | No |
| /register | Register | No | No |
| /verify | Verification | No | No |
| /forgot-password | ForgotPassword | No | No |
| /2fa-verify | Email2FA | No | No |
| /computer | ComputerPlay | No | No |
| /profile | Profile | Yes | No |
| /lobby | GameLobby | Yes | No |
| /game/:gameId | GamePlay | Yes | No |
| /history | GameHistory | Yes | No |
| /leaderboard | Leaderboard | Yes | No |
| /admin/users | UserManagement | Yes | Yes |
| /admin/games | AdminGames | Yes | Yes |
| /admin/chat | AdminChat | Yes | Yes |
Zustand is used for client-side state that persists across routes:
-
authStore— User object, JWT tokens, authentication status. Tokens are persisted tolocalStorageunderwechess_accessToken,wechess_userBucketToken,wechess_applicationBucketToken. -
notificationStore— In-app notification queue for game events.
TanStack Query is used for server state:
-
Configured with
refetchOnWindowFocus: false,retry: 1,staleTime: 30_000 -
Used for API data that should be cached and revalidated (games list, leaderboard, user data)
All API communication goes through Axios clients defined in src/api/clients.ts:
-
Base URL:
https://wechess.mindbricks.co(hardcoded, no env variable) -
Request interceptor: Automatically attaches
Authorization: Bearer <token>from Zustand store -
Response interceptor: Auto-logout on 401 responses
-
Service clients:
authApi,gameApi,chatApi,leaderboardApi,lobbyApi,bucketApi
Each service has its own API module (src/api/*.ts) that exports typed functions wrapping Axios calls.
-
Create the page component in
src/pages/NewPage.tsx -
Add TypeScript types to
src/types/index.tsif new entities are needed -
Create API functions in the relevant
src/api/*.tsmodule -
Register the route in
src/App.tsx— wrap with<ProtectedRoute>if auth is required -
Add navigation in
src/components/Header.tsxif it should appear in the nav bar -
Connect WebSocket if real-time features are needed (use
socketManager.ts)
-
Check if a client exists in
src/api/clients.tsfor the target service -
If not, create a new service client:
export const newApi = createServiceClient('/new-api'); -
Create the API module:
src/api/newService.ts -
Define types in
src/types/index.ts -
Use in components via TanStack Query hooks or direct calls
-
Tailwind CSS v4 with the
@tailwindcss/viteplugin -
Dark theme by default (
bg-background text-foreground) -
Brand color: green (
#22c55e/green-500) -
Utility classes from
clsx,tailwind-merge,class-variance-authorityavailable -
No component library — all UI is custom-built
-
ESLint flat config with TypeScript ESLint, React Hooks, and React Refresh plugins
-
Path alias
@/*maps to./src/*(configured in both Vite and TSConfig) -
Code splitting: manual chunks for
react,chess, andsocket.ioin Vite config
All API requests go through: https://wechess.mindbricks.co
| Method | Endpoint | Auth | Description |
|--------|----------|:----:|-------------|
| POST | /login | No | Login with email + password |
| POST | /logout | Yes | End session |
| GET | /currentuser | Yes | Get current user and refresh tokens |
| POST | /v1/registeruser | No | Register a new user |
| GET | /v1/users/:id | Yes | Get user by ID |
| GET | /v1/users | Admin | List users (filterable by email, fullname, roleId) |
| GET | /v1/searchusers?keyword= | Admin | Search users |
| POST | /v1/users | Admin | Create user |
| PATCH | /v1/users/:id | Admin | Update user |
| DELETE | /v1/users/:id | Admin | Delete user |
| PATCH | /v1/profile/:id | Yes | Update own profile (fullname, avatar) |
| PATCH | /v1/userpassword/:id | Yes | Change own password |
| DELETE | /v1/archiveprofile/:id | Yes | Archive own account |
| PATCH | /v1/userrole/:id | Admin | Change user role |
| PATCH | /v1/userpasswordbyadmin/:id | Admin | Reset user password |
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | /verification-services/email-verification/start | Send verification email |
| POST | /verification-services/email-verification/complete | Verify email code/link |
| POST | /verification-services/password-reset-by-email/start | Request password reset |
| POST | /verification-services/password-reset-by-email/complete | Complete password reset |
| POST | /verification-services/email-2factor/complete | Complete 2FA verification |
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | /v1/game | Create a new game |
| GET | /v1/game/:id | Get game by ID |
| PATCH | /v1/game/:id | Update game (status, FEN, result, etc.) |
| DELETE | /v1/game/:id | Delete game |
| GET | /v1/games | List games (filter by status, mode, invitationCode) |
| POST | /v1/gamemove | Record a move |
| GET | /v1/gamemoves?gameId= | List moves for a game |
| POST | /v1/gameinvitation | Create a private game invitation |
| PATCH | /v1/gameinvitation/:id | Update invitation status |
| GET | /v1/gameinvitations | List invitations (filter by recipientId, senderId, status) |
| GET | /game-hub/:roomId/eligible | Check WebSocket room eligibility |
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v1/listgamechatmessages/:gameId | List chat messages for a game |
| POST | /v1/gamechatmessages | Send a chat message |
| PATCH | /v1/gamechatmessagemoderation/:id | Moderate a message (report, remove) |
| DELETE | /v1/gamechatmessages/:id | Delete a message |
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v1/listlobbyrooms/:roomId | Get lobby room by ID |
| POST | /v1/ensurelobbyroom | Create or get a lobby room |
| GET | /v1/listlobbymessages/:roomId | List messages in a lobby room |
| POST | /v1/lobbymessages | Send a lobby message |
| PATCH | /v1/lobbymessagemoderation/:id | Moderate a lobby message |
| DELETE | /v1/lobbymessages/:id | Delete a lobby message |
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v1/leaderboardtopn?topN= | Get top N leaderboard entries |
| GET | /v1/leaderboardentries/:userId | Get user's leaderboard entry |
| POST | /v1/leaderboardentries | Create leaderboard entry |
| PATCH | /v1/leaderboardentries/:id | Update leaderboard entry |
| GET | /v1/playerstatses/:userId | Get player stats |
| POST | /v1/playerstatses | Create player stats |
| PATCH | /v1/playerstatses/:id | Update player stats |
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | /upload | Upload file (multipart form data with bucketId and files) |
Bucket IDs follow the pattern {userId}-public-user-bucket for user uploads.
interface ApiResponse<T> {
status: string; // "success" or "error"
statusCode: number; // HTTP status code
dataName?: string; // Name of the data key (e.g., "chessGame")
rowCount?: number; // Number of rows returned
paging?: {
pageNumber: number;
pageRowCount: number;
totalRowCount: number;
pageCount: number;
};
[dataName]: T; // Dynamic key containing the data
}interface ApiError {
result: string; // "error"
status: number; // HTTP status
message: string; // Human-readable error
errCode: number; // Application error code
date: string; // ISO timestamp
detail?: string; // Additional detail
}weChess uses Socket.IO for real-time features with three distinct hubs:
| Hub | Namespace | Path | Purpose |
|-----|-----------|------|---------|
| gameHub | /gameplay-api/hub/gameHub | /gameplay-api/socket.io/ | Game moves, lifecycle events, matchmaking |
| gameChatHub | /ingamechat-api/hub/gameChatHub | /ingamechat-api/socket.io/ | In-game chat messages |
| lobbyChatHub | /lobbychat-api/hub/lobbyChatHub | /lobbychat-api/socket.io/ | Lobby room chat messages |
| Subscription | Namespace | Purpose |
|-------------|-----------|---------|
| gameLifecycleEvents | /ingamechat-api/events/gameLifecycleEvents | Game start/end/pause notifications |
| gameEvents | /leaderboard-api/events/gameEvents | Score and stat updates |
Connection: Authenticated via auth.token callback (JWT from Zustand store).
const socket = io(`${BASE_URL}${namespace}`, {
path: socketPath,
auth: (cb) => cb({ token: accessToken }),
transports: ['websocket', 'polling'],
reconnection: true,
});Room operations:
| Event (emit) | Payload | Description |
|-------------|---------|-------------|
| hub:join | { roomId, meta? } | Join a room (game, lobby) |
| hub:leave | { roomId } | Leave a room |
| hub:send | { roomId, messageType, content } | Send a message to a room |
| hub:event | { roomId, event, data? } | Emit a custom event (typing, moves) |
| hub:block | { roomId, userId, reason?, duration? } | Block a user from a room |
| hub:unblock | { roomId, userId } | Unblock a user |
| hub:silence | { roomId, userId, reason?, duration? } | Mute a user |
| hub:unsilence | { roomId, userId } | Unmute a user |
import { connectHub, joinRoom, sendHubMessage, disconnectHub } from '@/lib/socketManager';
// Connect to a hub
const socket = connectHub('gameHub');
// Join a game room
joinRoom('gameHub', gameId, { userId, username });
// Listen for events
socket.on('hub:message', (msg) => { /* handle */ });
socket.on('hub:event', (evt) => { /* handle */ });
// Send a game move
sendHubMessage('gameHub', gameId, 'move', { from: 'e2', to: 'e4', fen: '...' });
// Cleanup
disconnectHub('gameHub');
1. User submits email + password
└─> POST /auth-api/login
2. Server returns JWT + user data
├─> accessToken (30-day expiry)
├─> userBucketToken (for file uploads)
└─> applicationBucketToken
3. Tokens stored in Zustand + localStorage
└─> Axios interceptor attaches to all requests
4. If 2FA is enabled:
└─> Server returns { status: "2fa_required", userId }
└─> User redirected to /2fa-verify
└─> POST /verification-services/email-2factor/complete
5. Session restore on page reload:
└─> useAuth hook checks stored token
└─> GET /auth-api/currentuser
└─> Re-hydrates user state
-
Frontend generates random credentials (
Guest_XXXXXXXX/guest_XXXXXXXX@wechess.guest) -
Auto-registers via
POST /auth-api/v1/registeruser -
Auto-logs in via
POST /auth-api/login -
Assigned
guestrole — limited to playing games, no leaderboard stats
-
Algorithm: JWT with auto-rotating keys
-
Token period: 30 days
-
Key refresh: Every 150 days
-
Storage:
localStoragekeyswechess_accessToken,wechess_userBucketToken,wechess_applicationBucketToken
The ProtectedRoute component in src/components/ProtectedRoute.tsx:
-
Checks
isAuthenticatedfrom Zustand store -
Shows loading state while
isLoadingis true -
Redirects to
/loginif not authenticated -
Optionally requires
administratorrole viarequireAdminprop
# Navigate to frontend directory
cd frontend
# Install dependencies
npm install
# Start development server
npm run dev
# → http://localhost:5173
# Build for production
npm run build
# Preview production build
npm run preview
# Run linting
npm run lint
The recommended workflow for making backend changes from within Cursor:
Step 1: Understand the Current State
────────────────────────────────────
• Use getProjectOverview to see top-level structure
• Use readAt("wechess", "services/gameplay") to inspect a service
• Use readAt("wechess", "services/gameplay/dataObjects/chessGame") to inspect a data object
Step 2: Consult the Ontology
────────────────────────────
• Use getOntologyTree to see the config hierarchy
• Use getOntologyDocByPath("services/gameplay/dataObjects") to learn the schema
• Fetch each pattern type ONCE — reuse from context
Step 3: Make Changes
────────────────────
• Use updateAt for adding or modifying configuration
- Deep merge: only specified fields change, everything else preserved
- Scalar fields: updated if specified, preserved if omitted
- Objects: recursively merged
• Use deleteAt for removing items
- deleteAt("wechess", "services/gameplay/dataObjects/chessGame/properties/fieldName")
Step 4: Validate
────────────────
• validateService("wechess", "gameplay") — catches design errors
Step 5: Build & Deploy
──────────────────────
• buildServiceRepo("wechess") — regenerates code, pushes to GitLab
• Save the returned commitId
Step 6: Monitor Deployment
──────────────────────────
• Poll getPreviewStatus until service commitId matches
• Check getServicePreviewLogs for runtime errors
Step 7: Test APIs
─────────────────
• loginAsSuperadmin("wechess") — get auth token
• httpRequest to test endpoints using URLs from getPreviewStatus
• Always call getServiceApiDocument first to learn correct endpoint paths
When building new frontend features that consume backend APIs:
Step 1: Get the API Documentation
─────────────────────────────────
• Use getServiceApiDocument("wechess", "serviceName") from the MCP
• Or read the existing src/api/*.ts modules for established patterns
Step 2: Define Types
────────────────────
• Add TypeScript interfaces to src/types/index.ts
• Match the backend data model (use readAt to inspect field names and types)
Step 3: Create API Functions
────────────────────────────
• Add functions to the appropriate src/api/*.ts module
• Follow existing patterns: export async functions, destructure { data }
Step 4: Build the UI
────────────────────
• Create page component in src/pages/
• Use TanStack Query for data fetching
• Use Zustand stores for cross-component state
• Use socketManager for real-time features
Step 5: Register Routes
───────────────────────
• Add route in src/App.tsx
• Wrap with ProtectedRoute if auth needed
• Add navigation link in Header.tsx
From Cursor with the Mindbricks MCP, you can test endpoints directly:
1. loginAsSuperadmin({ projectId: "wechess" })
→ Returns auth token
2. getPreviewStatus({ projectId: "wechess" })
→ Returns service URLs
3. httpRequest({
projectId: "wechess",
url: "https://wechess.mindbricks.co/gameplay-api/v1/games",
method: "GET",
useProjectToken: true
})
The frontend deploys via GitLab CI/CD on push to main:
-
Trigger: Push to
mainbranch -
Build: Docker builds the image using the Dockerfile
-
Tag: Image tagged as
wechess-frontend:latestandwechess-frontend:<commit-sha> -
Deploy:
docker compose up -d wechesson the production server
The Dockerfile uses a multi-stage build:
-
Stage 1: Node.js to build the Vite app
-
Stage 2: Nginx to serve the static files (configured via
nginx.conf)
Backend services are automatically deployed through Mindbricks:
-
Run
buildServiceRepo("wechess")— pushes generated code to GitLab -
GitLab webhook triggers the matrix preview server
-
Preview server clones, installs, and starts each service
-
Services go through:
pending→cloning→installing→starting→healthcheck→ready
Service statuses can be monitored via getPreviewStatus.
Preview environments go cold after inactivity:
-
getPreviewStatusreturnsstatus: "cold" -
Call
wakeupPreview("wechess") -
Poll
getPreviewStatusevery 3–5 seconds untilready: true
| Resource | URL |
|----------|-----|
| API Gateway | https://wechess.mindbricks.co |
| Auth Service | https://wechess.mindbricks.co/auth-api |
| Gameplay Service | https://wechess.mindbricks.co/gameplay-api |
| Chat Service | https://wechess.mindbricks.co/ingamechat-api |
| Lobby Service | https://wechess.mindbricks.co/lobbychat-api |
| Leaderboard Service | https://wechess.mindbricks.co/leaderboard-api |
| File Bucket | https://wechess.mindbricks.co/bucket |
| File | Purpose |
|------|---------|
| frontend/src/api/clients.ts | API base URL and Axios client factory |
| frontend/src/lib/socketManager.ts | WebSocket connection management |
| frontend/src/stores/authStore.ts | Auth state and token persistence |
| frontend/src/hooks/useAuth.ts | Login, logout, guest login, session restore |
| frontend/src/types/index.ts | All shared TypeScript interfaces |
| frontend/src/App.tsx | Route definitions and provider tree |
| wechess/.mbx-services.json | Mindbricks project config (project ID + service list) |
Fetching data with TanStack Query:
const { data, isLoading } = useQuery({
queryKey: ['games', status],
queryFn: () => listGames({ status }),
});Authenticated API call:
// Token is automatically attached by the Axios interceptor
const game = await getGame(gameId);Real-time game move:
sendHubMessage('gameHub', gameId, 'move', {
from: 'e2', to: 'e4',
fen: chess.fen(),
moveNotation: 'e4',
});Protected admin route:
<Route path="/admin/users" element={
<ProtectedRoute requireAdmin>
<UserManagement />
</ProtectedRoute>
} />