This guide explains how to run the Mentat Protocol web frontend integrated with the FastAPI backend.
┌─────────────────┐ ┌──────────────────┐ ┌────────────┐
│ Vue 3 Web │ HTTP │ FastAPI Backend │ │ PostgreSQL │
│ Frontend ├────────►│ + TortoiseORM ├────────►│ Database │
│ (Port 5173) │ REST │ (Port 8000) │ │ │
└─────────────────┘ └──────────────────┘ └────────────┘
│
│ Axios Client
│ JWT Auth
│ Pinia Stores
└──► Real-time market data, auth, curation
- Node.js 18+ (for frontend)
- Python 3.11+ (for backend)
- PostgreSQL 14+ (for database)
- npm or yarn (package manager)
# Create PostgreSQL database
createdb mentat_dev
# Or using psql
psql -U postgres
CREATE DATABASE mentat_dev;
\qcd apps/backend
# Install Python dependencies
uv sync
# Configure environment
cp .env.example .env
# Edit .env with your database credentials
# Initialize database with Aerich
aerich init-db
# Run backend server
uvicorn src.main:app --reload --host 0.0.0.0 --port 8000Backend will be available at: http://localhost:8000 API Docs: http://localhost:8000/docs
cd apps/web
# Install Node dependencies
npm install
# Configure environment
cp .env.example .env
# Default API URL is http://localhost:8000
# Run development server
npm run devFrontend will be available at: http://localhost:5173
The web app now uses real JWT-based authentication:
- User clicks "Connect Wallet" or "Sign in"
- AuthModal opens with registration form
- User enters wallet address (required) + optional email/password
- Frontend calls
POST /api/v1/auth/register - Backend creates user and returns JWT token
- Token stored in localStorage
- User state managed by Pinia auth store
- User enters credentials (wallet or email/password)
- Frontend calls
POST /api/v1/auth/login - Backend validates and returns JWT token
- Token automatically included in subsequent requests
- All API requests include
Authorization: Bearer <token>header - Axios interceptor handles token injection
- 401 responses trigger automatic logout
The frontend now uses real backend APIs instead of mock data:
| Frontend Function | Backend Endpoint | Description |
|---|---|---|
fetchActiveMarkets() |
GET /api/v1/markets?state=active |
Get active markets |
fetchFeaturedMarkets() |
GET /api/v1/markets?sort_by=total_volume |
Get top markets |
fetchMarketDetail(id) |
GET /api/v1/markets/{id} |
Get market details |
fetchDrafts() |
GET /api/v1/drafts |
Get user's drafts |
createDraft(data) |
POST /api/v1/drafts |
Create market draft |
fetchCuratorQueue() |
GET /api/v1/curator/queue |
Get curator queue |
approveDraft(id) |
POST /api/v1/curator/{id}/approve |
Approve draft |
The integration includes adapters that transform backend API types to match frontend expectations:
- Backend:
MarketListItem→ Frontend:MarketSummary - Backend:
MarketDetail→ Frontend:MarketDetail - Handles field name conversions (snake_case ↔ camelCase)
- Converts basis points to percentages
- Adds computed/derived fields
apps/web/src/
├── config/
│ └── api.ts # API endpoints configuration
├── lib/
│ └── apiClient.ts # Axios instance with auth interceptors
├── stores/
│ └── auth.ts # Pinia auth store
├── services/
│ ├── api.ts # Real API service functions
│ ├── adapters.ts # Type adapters
│ └── mockApi.ts # (deprecated, keep for reference)
├── types/
│ ├── index.ts # Frontend types
│ └── api.ts # Backend API types
└── components/
├── AuthModal.vue # Login/Register modal
└── AppHeader.vue # Updated with auth UI
apps/backend/src/
├── api/v1/
│ ├── auth.py # Authentication endpoints
│ ├── markets.py # Market endpoints
│ ├── drafts.py # Draft management
│ └── curator.py # Curator workflow
├── models/
│ ├── user.py # User model
│ ├── market.py # Market models
│ └── curation.py # Draft/curation models
└── schemas/
├── user.py # Request/response schemas
├── market.py
└── curation.py
VITE_API_URL=http://localhost:8000
VITE_APP_NAME=Mentat Protocol
VITE_APP_ENV=developmentDATABASE_URL=postgresql://postgres:postgres@localhost:5432/mentat_dev
SECRET_KEY=your-secret-key-change-in-production
CORS_ORIGINS=http://localhost:5173,http://localhost:3000# Via API
curl -X POST http://localhost:8000/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"wallet_address": "DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK",
"username": "testuser"
}'
# Or use the web UI: Click "Connect Wallet" buttonNavigate to http://localhost:5173/ to see:
- Active markets fetched from backend
- Real-time data (currently empty until you create markets)
- Sign in to web app
- Go to "Create" page
- (Creator studio UI integration TBD)
- Sign in with curator account
- Go to "Curate" page
- View pending drafts from backend
- Update models in
apps/backend/src/models/ - Create migration:
cd apps/backend aerich migrate --name "description"
- Apply migration:
aerich upgrade
- Update TypeScript types in
apps/web/src/types/api.ts - Update adapters if needed
- Add route to
apps/backend/src/api/v1/ - Add endpoint constant to
apps/web/src/config/api.ts - Add service function to
apps/web/src/services/api.ts - Update components to use new service
If you see CORS errors in the browser console:
- Check
CORS_ORIGINSin backend.env - Ensure frontend dev server URL is included
- Restart backend server
- Check that JWT token is in localStorage (
auth_token) - Verify backend
SECRET_KEYhasn't changed - Token expires after 7 days by default
# Check PostgreSQL is running
pg_isready
# Check database exists
psql -l | grep mentat_dev
# Verify DATABASE_URL in backend .envThe database starts empty. To seed data:
- Create a user via registration
- Create drafts via API
- Approve drafts as curator
- Markets will appear in discovery
- Connect Creator Studio UI to draft creation API
- Implement WebSocket for real-time market updates
- Add wallet signature verification
- Implement proof submission UI
- Add market trading interface
- Integrate with Solana devnet
# Use production ASGI server
gunicorn src.main:app \
--workers 4 \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8000# Build for production
npm run build
# Serve with nginx, Vercel, or Netlify- Set
ENVIRONMENT=productionandDEBUG=false - Use strong
SECRET_KEY(32+ random bytes) - Enable HTTPS
- Configure production database
- Set proper CORS origins
- Backend API docs: http://localhost:8000/docs
- Frontend issues: Check browser console
- Database issues: Check PostgreSQL logs
- General issues: See repo README.md