Overview
Kuest Prediction Market uses PostgreSQL as its primary database with Drizzle ORM for type-safe database operations. The application supports both Supabase and self-hosted PostgreSQL deployments.Database Requirements
- PostgreSQL: Version 14 or higher
- Extensions (optional):
pg_cron: For database-level scheduled jobspg_net: For HTTP requests from database (Supabase only)uuid-osspor custom ULID function: For ID generation
Configuration Options
You have two main deployment options:Supabase
Managed PostgreSQL with built-in storage, auth helpers, and scheduled jobs
Self-Hosted
Your own PostgreSQL instance with external storage (S3, MinIO, R2)
Supabase Setup
Step 1: Create a Supabase Project
- Go to https://supabase.com and create a new project
- Wait for the project to initialize (usually 2-3 minutes)
- Navigate to Project Settings → API
Step 2: Configure Environment Variables
Add these variables to your.env file:
.env
The
POSTGRES_URL for Supabase uses the direct database connection, not the pooled connection. Find this under Project Settings → Database → Connection string → Direct connection.Step 3: Enable Extensions
Run these SQL commands in the Supabase SQL Editor:Step 4: Run Migrations
- Connect to your database
- Create a
migrationstracking table - Apply all pending migrations in order
- Set up the storage bucket (if using Supabase Storage)
- Configure cron jobs (if extensions are available)
Self-Hosted PostgreSQL Setup
Step 1: Provision a PostgreSQL Database
Choose a hosting provider:- Neon - Serverless Postgres with free tier
- Railway - Simple deployment platform
- Digital Ocean - Managed databases
- AWS RDS - Enterprise-grade
- Self-hosted via Docker
Step 2: Configure Connection String
Add to your.env file:
.env
Step 3: Configure Storage
Since you’re not using Supabase, configure S3-compatible storage:.env
Step 4: Run Migrations
- Skips Supabase-specific policies
- Replaces
service_rolewithCURRENT_USERin policies - Skips storage bucket creation
- Skips database scheduler setup
Database Schema
The application creates the following table groups:Authentication Tables
Authentication Tables
Managed by Better Auth with custom fields for Web3 integration.
users: User accounts with wallet addresses, settings, and affiliate trackingsessions: Active user sessions with device informationaccounts: OAuth provider connectionswallets: Connected Web3 wallets (SIWE)verifications: Email verification and 2FA codestwo_factors: TOTP secrets and backup codes
Events Tables
Events Tables
Prediction market events and outcomes.
events: Market events synced from Kuest CLOB- Event metadata including titles, descriptions, images
- Resolution data and timestamps
- Category and tag relationships
Orders Tables
Orders Tables
User trading history and order management.
orders: All user orders (market, limit, conditional)- Order status tracking and fill information
- Links to events and outcomes
Bookmarks Tables
Bookmarks Tables
User-saved events for quick access.
bookmarks: User event bookmarks- Timestamps for sorting
Notifications Tables
Notifications Tables
In-app and email notifications.
notifications: User notification queue- Read/unread status
- Notification types and content
Affiliates Tables
Affiliates Tables
Referral tracking and affiliate management.
affiliates: Affiliate relationships- Referral codes and conversion tracking
Settings Tables
Settings Tables
Application configuration and cached data.
settings: Global application settings- Cached translations and sports menu
- Tag definitions
Subgraph Tables
Subgraph Tables
Cached blockchain data from The Graph.
- Market volume statistics
- Leaderboard data
- Performance metrics
Migration Process
The migration system (scripts/migrate.js) provides:
Automatic Migration Tracking
Environment Detection
The script automatically detects your deployment mode:Transaction Safety
Each migration runs in a transaction:Scheduled Jobs
Supabase with pg_cron
Supabase with pg_cron
When using Supabase with
pg_cron and pg_net extensions enabled, the migration script automatically sets up:- sync-events (every 5 minutes): Fetch new events from Kuest CLOB
- sync-resolution (every 5 minutes): Check for resolved markets
- sync-translations (every 10 minutes): Update translated content
- sync-volume (twice per hour): Update volume statistics
- clean-jobs (every 15 minutes): Clean up old job queue entries
- clean-cron-details (daily): Remove old cron execution logs
npm run db:push to ensure they use the latest configuration.Self-Hosted or External Scheduler
Self-Hosted or External Scheduler
For self-hosted PostgreSQL or if All sync endpoints require
pg_cron is unavailable, configure external schedulers:Vercel Cron Jobs (vercel.json):Authorization: Bearer <CRON_SECRET> header.Connection Pooling
The application usespostgres-js with connection pooling:
src/lib/drizzle.ts
- prepare: false: Disables prepared statements (required for PgBouncer)
- connect_timeout: 10 seconds to establish connection
- idle_timeout: 20 seconds before closing idle connections
Troubleshooting
Error: POSTGRES_URL is not set
Error: POSTGRES_URL is not set
The database connection string is missing. Add
POSTGRES_URL to your .env file:Error: SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY must be set together
Error: SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY must be set together
If you set one Supabase variable, you must set both. Either:
- Set both variables for Supabase mode
- Remove both and use S3 configuration instead
Migration fails with 'relation already exists'
Migration fails with 'relation already exists'
A previous migration was partially applied. Options:
- Safe: Manually insert the migration version into the
migrationstable - Destructive: Drop the database and re-run migrations (loses all data)
Cron jobs not created
Cron jobs not created
Check that:
pg_cronextension is installed:SELECT * FROM pg_extension WHERE extname = 'pg_cron';pg_netextension is installed (Supabase only)CRON_SECRETenvironment variable is set
Connection timeout errors
Connection timeout errors
Increase the connection timeout in your database configuration:Also check:
- Database server is accessible
- Firewall rules allow connections
- SSL/TLS configuration is correct
Next Steps
Storage Configuration
Set up file storage for user uploads
Authentication
Configure wallet authentication
Environment Variables
Complete variable reference
Deploy to Vercel
Deploy your application