Technical overview for developers and contributors.
┌─────────────────┐ ┌─────────────────┐
│ Frontend │─────▶│ API │
│ (React, Vite) │ HTTP │ (Hono/Bun) │
└─────────────────┘ └────────┬────────┘
│
┌─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
┌──────────┐ ┌────────────┐ ┌──────────┐
│ Worker │ │ Executor │ │ Directus │
│ (BullMQ) │ │ (SQL eval) │ │ (CMS) │
└────┬─────┘ └─────┬──────┘ └────┬─────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Redis │ │ Executor │ │ Directus │
│ (queue) │ │ (Node) │ │ (PHP) │
└──────────┘ └──────────┘ └──────────┘
│ │ │
└────────────────────────┼─────────────────────────┘
▼
┌────────────┐
│ PostgreSQL │
└────────────┘
- Stack: React 19, Vite 7, React Router, Tailwind CSS
- Role: Student-facing SPA. Auth via cookies, no localStorage tokens.
- Build:
pnpm build:frontend→apps/frontend/build/ - Dev:
pnpm dev:frontend→ http://localhost:5173
- Stack: Bun, Hono
- Role: REST API, auth (JWT in HTTP-only cookie), orchestration
- Port: 3100
- Docs: http://localhost:3100/docs (Swagger UI), http://localhost:3100/openapi.json
- Stack: BullMQ, Redis
- Role: Async SQL validation jobs. API enqueues, worker runs executor.
- Dependency: Redis must be running
- Stack: Node.js, isolated SQL runner
- Role: Runs student SQL in sandbox, compares to expected result
- Called by: Worker (not directly by API)
- Stack: Directus (PHP)
- Role: CMS for flexible content. Can be used for course metadata, media.
- Port: 8055
- Note: Core flows work without Directus; it extends content authoring.
- PostgreSQL: Primary data store. Schema in
packages/db. - Redis: Job queues (BullMQ) and session/cache if used.
- Frontend POSTs to
/api/users/loginwith email/password - API validates, sets
studykit_tokencookie (JWT) - Frontend navigates to
/courses; subsequent requests include cookie
- Frontend GETs
/api/courses/:id(with cookie) - API returns course, lectures, content tree
- For specific content: GET
/api/lectures/:lid/contents/:cid - If SQL problem: frontend POSTs solution to
/api/sql-solutions - API enqueues job; Worker runs Executor, result streamed via SSE
- Frontend POSTs to
/api/courses/:id/progresswhen viewing content - API records
viewedContentIdsper user - Analytics: GET
/api/courses/:id/analytics(teacher only)
- Method: JWT in HTTP-only cookie (
studykit_token) - Middleware:
authMiddlewareinapps/api/src/middleware/auth.ts - Roles:
student,teacher,admin— enforced viaauthorize()middleware - CORS: Credentials allowed from configured origins
studykit/
├── apps/
│ ├── api/ # Hono REST API
│ ├── frontend/ # React SPA
│ ├── worker/ # BullMQ processor
│ └── executor/ # SQL sandbox
├── packages/
│ └── db/ # Drizzle schema, shared types
├── docs/
│ ├── ARCHITECTURE.md
│ ├── CONTRIBUTING.md
│ └── VISION.md
└── docker-compose.yml
| File | Purpose |
|---|---|
apps/api/src/app.ts |
API entry, routes, CORS |
apps/api/src/routes/*.ts |
Route handlers |
apps/api/openapi.ts |
OpenAPI spec |
packages/db/schema |
DB tables, relations |
apps/frontend/src/routes.tsx |
React Router, loaders |
apps/frontend/src/types/Course.ts |
Frontend course types |
See .env.example. Main variables:
DATABASE_URL— PostgreSQL connection stringREDIS_URL— Redis for BullMQJWT_SECRET— Signing key for tokensVITE_API_URL— API base URL (frontend)