Skip to content

sebdanielsson/quiz-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

100 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Quiz App

A modern, full-stack quiz application built with Next.js 16, featuring OIDC authentication, real-time leaderboards, and a comprehensive REST API with API key authentication.

Monorepo Structure

This is a Bun workspaces + Turborepo monorepo with:

  • apps/web β€” Main Next.js quiz application
  • apps/docs β€” Documentation app (to be created)

All commands should be run from the repository root using Turborepo.

Features

  • 🎯 Quiz Management β€” Create, edit, and delete quizzes with multiple-choice questions
  • ✨ AI Generated Content β€” Use AI to help generate questions and answers
  • πŸ”Ž Image Browser β€” Browse and select images via Unsplash API integration
  • πŸ” OIDC Authentication β€” Secure sign-in via OpenID Connect (configurable provider)
  • πŸ‘‘ Role-Based Access β€” Admin permissions based on OIDC groups claim
  • πŸ† Leaderboards β€” Per-quiz and global leaderboards with rankings
  • ⏱️ Timed Quizzes β€” Optional time limits with timeout tracking
  • πŸ”„ Randomization β€” Shuffle questions for each attempt
  • πŸ”‘ API Keys β€” Programmatic access with scoped permissions and rate limiting
  • πŸ“– OpenAPI Docs β€” Interactive API documentation with Scalar
  • πŸŒ“ Dark Mode β€” System-aware theme switching

Tech Stack

  • Monorepo: Bun workspaces + Turborepo
  • Framework: Next.js 16 (App Router, Turbopack)
  • Runtime: Bun
  • Database: PostgreSQL with Drizzle ORM (via bun:sql)
  • Cache: Valkey/Redis (optional, via Bun native client)
  • Auth: BetterAuth with OIDC + API Key plugins
  • UI: shadcn/ui (Base UI - Nova), Lucide Icons
  • Validation: Zod
  • AI: AI SDK
  • Image browser: Unsplash API integration

Getting Started

Prerequisites

  • Bun >= 1.3.8
  • PostgreSQL database
  • An OIDC provider (e.g., Keycloak, Auth0, Okta, Pocket ID)

Installation

# Clone the repository
git clone <repository-url>
cd quiz-app

# Install dependencies
bun install

# Set up environment variables
cp apps/web/.env.example apps/web/.env.local

Environment Variables

Create a .env.local file with the following:

# App URL
NEXT_PUBLIC_APP_URL=http://localhost:3000

# OIDC Configuration
OIDC_ISSUER=https://your-oidc-provider.com
OIDC_CLIENT_ID=your-client-id
OIDC_CLIENT_SECRET=your-client-secret

# Database (PostgreSQL required)
DATABASE_URL=postgresql://user:password@localhost:5432/quiz_app

RBAC Configuration

The app includes a flexible Role-Based Access Control system. See docs/rbac.md for full documentation.

Quick examples:

# Public quiz platform (guests can browse, must sign in to play)
RBAC_PUBLIC_BROWSE_QUIZZES=true
RBAC_PUBLIC_VIEW_QUIZ=true
RBAC_PUBLIC_LEADERBOARD=true

# Role mappings (OIDC groups β†’ app roles)
RBAC_ROLE_ADMIN_GROUPS=admin,staff
RBAC_ROLE_CREATOR_GROUPS=teachers

# Default role for authenticated users without group mapping
RBAC_DEFAULT_ROLE=user
Variable Default Description
RBAC_PUBLIC_BROWSE_QUIZZES false Allow guests to view quiz list
RBAC_PUBLIC_VIEW_QUIZ false Allow guests to view quiz details
RBAC_PUBLIC_PLAY_QUIZ false Allow guests to play (results not saved)
RBAC_PUBLIC_LEADERBOARD false Allow guests to view leaderboards
RBAC_DEFAULT_ROLE user Default role for authenticated users
RBAC_ROLE_ADMIN_GROUPS admin OIDC groups that map to admin role
RBAC_ROLE_MODERATOR_GROUPS (empty) OIDC groups that map to moderator role
RBAC_ROLE_CREATOR_GROUPS (empty) OIDC groups that map to creator role

Database Setup

The app uses PostgreSQL with Bun's native SQL driver (bun:sql).

# Start PostgreSQL (via Docker Compose)
docker compose up -d

# Run migrations
bun run db:migrate

# Or push schema directly (development)
bun run db:push

Caching (Optional)

The app includes an optional Redis/Valkey caching layer to reduce database load for high-traffic deployments. See docs/caching.md for full documentation. Caching is opt-in β€” if no Redis URL is configured, all queries hit the database directly.

Development

# Start development server
bun --bun run dev

Open http://localhost:3000 in your browser.

Production

# Build for production
bun --bun run build

# Start production server
bun --bun run start

Project Structure

quiz-app/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ (auth)/           # Authentication pages
β”‚   β”‚   └── sign-in/
β”‚   β”œβ”€β”€ (dashboard)/      # Main app pages
β”‚   β”‚   β”œβ”€β”€ page.tsx      # Quiz list (home)
β”‚   β”‚   β”œβ”€β”€ leaderboard/  # Global leaderboard
β”‚   β”‚   β”œβ”€β”€ settings/     # Admin API key management
β”‚   β”‚   └── quiz/
β”‚   β”‚       β”œβ”€β”€ new/      # Create quiz
β”‚   β”‚       └── [id]/     # Quiz detail, edit, play, results
β”‚   β”œβ”€β”€ actions/          # Server actions
β”‚   β”œβ”€β”€ api/              # REST API endpoints
β”‚   β”‚   β”œβ”€β”€ auth/         # BetterAuth handler
β”‚   β”‚   β”œβ”€β”€ leaderboard/  # Global leaderboard
β”‚   β”‚   └── quizzes/      # Quiz CRUD + attempts + leaderboards
β”‚   └── docs/             # OpenAPI documentation (Scalar)
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ auth/             # Auth components
β”‚   β”œβ”€β”€ layout/           # Header, theme, pagination
β”‚   β”œβ”€β”€ quiz/             # Quiz-related components
β”‚   β”œβ”€β”€ settings/         # API key manager
β”‚   └── ui/               # Reusable UI components
β”œβ”€β”€ docs/
β”‚   └── rbac.md           # RBAC configuration documentation
└── lib/
    β”œβ”€β”€ auth/             # Auth configuration & helpers
    β”œβ”€β”€ db/               # Database schema & queries
    β”œβ”€β”€ rbac/             # Role-based access control
    β”œβ”€β”€ openapi.ts        # OpenAPI 3.1 specification
    └── validations/      # Zod schemas

REST API

The Quiz App provides a comprehensive REST API for programmatic access. All endpoints require authentication via API key.

Authentication

Include your API key in the x-api-key header:

curl -H "x-api-key: your_api_key_here" https://yourapp.com/api/quizzes

API Key Management

Admins can create and manage API keys through the web UI at /settings. Each API key can have specific permission scopes:

Scope Description
quizzes:read List and view quizzes, view leaderboards
quizzes:write Create, update, and delete quizzes (requires admin role)
attempts:read View quiz attempts
attempts:write Submit quiz attempts

Rate Limiting

API keys are rate-limited to 100 requests per minute by default. When rate-limited, the API returns a 429 Too Many Requests response.

API Documentation

Interactive API documentation is available at /docs powered by Scalar. The documentation includes:

  • πŸ“‹ Full endpoint reference with request/response schemas
  • πŸ§ͺ "Try it" functionality to test endpoints directly in the browser
  • πŸ“¦ Code snippets in multiple languages (JavaScript, Python, cURL, etc.)
  • πŸ” Authentication setup for API key configuration

Error Responses

All endpoints return consistent error responses:

{
  "error": "Error message describing what went wrong"
}
Status Code Description
400 Bad Request β€” Invalid input data
401 Unauthorized β€” Missing or invalid API key
403 Forbidden β€” Insufficient permissions
404 Not Found β€” Resource doesn't exist
429 Too Many Requests β€” Rate limit exceeded
500 Internal Server Error β€” Something went wrong

Scripts

Command Description
bun --bun run dev Start development server
bun --bun run build Build for production
bun --bun run start Start production server
bun --bun run tsc TypeScript type checking
bun --bun run lint Run ESLint
bun --bun run format Format code with Prettier
bun --bun run format:check Check code formatting with Prettier
bun --bun run stylelint Run Stylelint for CSS files
bun --bun run db:push Push schema changes to database
bun --bun run db:generate Generate migration files
bun --bun run db:migrate Run migrations
bun --bun run db:studio Open Drizzle Studio
bun test Run tests

License

MIT

Releases

No releases published

Sponsor this project

Packages

No packages published

Contributors 3

  •  
  •  
  •