This guide uses only browser-based tools. No software installation required - works on locked-down school laptops and Chromebooks!
The Driller platform has three parts that work together:
| Component | Service | Purpose |
|---|---|---|
| Database | Supabase | Stores student progress, scores, and teacher review queue |
| Backend Server | Railway | Handles AI grading, saves data, manages WebSocket connections |
| Frontend Website | Vercel | The student-facing app they interact with |
Code Storage: GitHub holds all the code. When you push changes, Railway and Vercel automatically redeploy.
┌──────────────────────────────────────────────────────────────┐
│ GitHub │
│ (Your Code Repository) │
└──────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ Railway │ │ Vercel │
│ (Backend Server) │ │ (Frontend Website) │
│ │ │ │
│ • AI Grading │◄───│ • Student Interface │
│ • Save/Load Progress │ │ • Problems & Grading │
│ • Teacher Review │ │ • Leaderboards │
└─────────────────────────┘ └─────────────────────────┘
│
▼
┌─────────────────────────┐
│ Supabase │
│ (Database) │
│ │
│ • Student Progress │
│ • Star Counts │
│ • Time Tracking │
└─────────────────────────┘
Create accounts on these 4 free services. Start with GitHub, then use "Sign in with GitHub" for the others (easier!).
GitHub stores your code and connects to the other services.
Click "Continue with GitHub" to link accounts.
Click "Login with GitHub" to link accounts.
Click "Continue with GitHub" to link accounts.
"Forking" creates your own copy of the code that you control.
github.com/YOUR-USERNAME/lrsl-driller
github.com/YOUR-USERNAME/lrsl-driller
driller-- =============================================
-- DRILLER PLATFORM DATABASE SCHEMA
-- Copy this entire block and run it in Supabase
-- =============================================
-- Users table
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY,
username TEXT UNIQUE NOT NULL,
real_name TEXT,
role TEXT DEFAULT 'student',
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Progress table
CREATE TABLE IF NOT EXISTS progress (
id BIGSERIAL PRIMARY KEY,
username TEXT NOT NULL,
cartridge_id TEXT NOT NULL,
mode_id TEXT NOT NULL,
streaks JSONB DEFAULT '{}',
star_counts JSONB DEFAULT '{"gold":0,"silver":0,"bronze":0,"tin":0}',
unlocked_tiers JSONB DEFAULT '[]',
total_problems INTEGER DEFAULT 0,
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(username, cartridge_id)
);
-- Leaderboard table
CREATE TABLE IF NOT EXISTS leaderboard (
id BIGSERIAL PRIMARY KEY,
username TEXT NOT NULL,
cartridge_id TEXT NOT NULL,
gold INTEGER DEFAULT 0,
silver INTEGER DEFAULT 0,
bronze INTEGER DEFAULT 0,
tin INTEGER DEFAULT 0,
total_problems INTEGER DEFAULT 0,
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(username, cartridge_id)
);
-- Teacher review queue
CREATE TABLE IF NOT EXISTS review_queue (
id BIGSERIAL PRIMARY KEY,
username TEXT NOT NULL,
cartridge_id TEXT NOT NULL,
mode_id TEXT NOT NULL,
problem_context JSONB,
answers JSONB,
requested_at TIMESTAMPTZ DEFAULT NOW(),
status TEXT DEFAULT 'pending',
teacher_grades JSONB,
reviewed_at TIMESTAMPTZ,
reviewed_by TEXT
);
-- Time tracking: sessions
CREATE TABLE IF NOT EXISTS time_sessions (
id BIGSERIAL PRIMARY KEY,
session_id TEXT UNIQUE NOT NULL,
username TEXT NOT NULL,
session_start TIMESTAMPTZ NOT NULL,
active_time_ms BIGINT DEFAULT 0,
total_time_ms BIGINT DEFAULT 0,
last_sync TIMESTAMPTZ DEFAULT NOW(),
is_complete BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Time tracking: problems
CREATE TABLE IF NOT EXISTS time_problems (
id BIGSERIAL PRIMARY KEY,
session_id TEXT NOT NULL,
username TEXT NOT NULL,
problem_id TEXT,
cartridge_id TEXT,
mode_id TEXT,
active_time_ms BIGINT DEFAULT 0,
total_time_ms BIGINT DEFAULT 0,
completed BOOLEAN DEFAULT FALSE,
result JSONB,
completed_at TIMESTAMPTZ DEFAULT NOW()
);
-- Create indexes for faster queries
CREATE INDEX IF NOT EXISTS idx_progress_username ON progress(username);
CREATE INDEX IF NOT EXISTS idx_leaderboard_cartridge ON leaderboard(cartridge_id);
CREATE INDEX IF NOT EXISTS idx_review_queue_status ON review_queue(status);
CREATE INDEX IF NOT EXISTS idx_time_sessions_username ON time_sessions(username);
CREATE INDEX IF NOT EXISTS idx_time_problems_username ON time_problems(username);
-- Enable Row Level Security
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE progress ENABLE ROW LEVEL SECURITY;
ALTER TABLE leaderboard ENABLE ROW LEVEL SECURITY;
ALTER TABLE review_queue ENABLE ROW LEVEL SECURITY;
ALTER TABLE time_sessions ENABLE ROW LEVEL SECURITY;
ALTER TABLE time_problems ENABLE ROW LEVEL SECURITY;
-- Allow all operations (for simplicity)
CREATE POLICY "Allow all on users" ON users FOR ALL USING (true);
CREATE POLICY "Allow all on progress" ON progress FOR ALL USING (true);
CREATE POLICY "Allow all on leaderboard" ON leaderboard FOR ALL USING (true);
CREATE POLICY "Allow all on review_queue" ON review_queue FOR ALL USING (true);
CREATE POLICY "Allow all on time_sessions" ON time_sessions FOR ALL USING (true);
CREATE POLICY "Allow all on time_problems" ON time_problems FOR ALL USING (true);
https://abcdefghijk.supabase.coeyJ...Railway will start building - this takes about 1 minute. It will likely fail the first time - that's okay! We need to configure it.
railway-servernode server.js| Variable Name | Value |
|---|---|
SUPABASE_URL |
Your Project URL from Part 3 (e.g., https://abcdefghijk.supabase.co) |
SUPABASE_ANON_KEY |
Your anon public key from Part 3 (starts with eyJ...) |
Railway will automatically redeploy after adding variables.
https://lrsl-driller-production-xxxx.up.railway.app)Before deploying, expand "Environment Variables" and add:
| Name | Value |
|---|---|
VITE_API_URL |
Your Railway URL from Part 4 (e.g., https://lrsl-driller-production-xxxx.up.railway.app) |
https://lrsl-driller.vercel.app)
AI grading provides intelligent feedback on free-response answers. Without it, the app uses keyword matching (still works, just less sophisticated).
| Variable Name | Value |
|---|---|
GEMINI_API_KEYS |
Your Gemini API key |
GROQ_API_KEYS |
Your Groq API key |
key1,key2,key3
When you're ready to create your own cartridges or customize the app, use Project IDX - Google's free cloud IDE.
https://github.com/YOUR-USERNAME/lrsl-driller
When you edit files in Project IDX and want to deploy:
git add .
git commit -m "Description of your changes"
git push
That's it! Railway and Vercel will automatically detect the push and redeploy within 1-2 minutes.
git push, both Railway and Vercel will rebuild and deploy your changes.
See the CARTRIDGE-DEVELOPMENT-GUIDE.md file in your repository for detailed instructions on creating lessons.
Quick summary - create a folder in cartridges/ with these 4 files:
manifest.json - Defines inputs, modes, hintsgenerator.js - Generates random problemsgrading-rules.js - Scores student answersai-grader-prompt.txt - (Optional) AI grading instructionsVITE_API_URL in Vercel matches your Railway URL exactlyhttps://SUPABASE_URL and SUPABASE_ANON_KEY in Railway variablesSUPABASE_URL is the Project URL (e.g., https://abcdefghijk.supabase.co)SUPABASE_ANON_KEY is the anon public key (starts with eyJ...)railway-servernode server.jsGEMINI_API_KEYS or GROQ_API_KEYS are set in RailwayInclude: which step you're on, the exact error message, and screenshots if possible.
| Service | Dashboard Link |
|---|---|
| GitHub | github.com |
| Supabase | supabase.com/dashboard |
| Railway | railway.app/dashboard |
| Vercel | vercel.com/dashboard |
| Project IDX | idx.google.com |
| Gemini API | aistudio.google.com |
| Groq API | console.groq.com |
Watch these step-by-step walkthrough videos: