Team Quiz

 

📋 Complete Build Prompt

Project name: Team Bug-Fix Race (ROC Amstelland Edition)

Stack: PHP 8.1, MariaDB, Apache, Vanilla JS, Tailwind CSS.

Branding: ROC Amstelland – red as accent (#e11d48 or Tailwind rose-600/red-600). UI language: English.

1) One‑paragraph summary for the builder

Build a lightweight, real‑time(ish) classroom web app where student teams submit a single open‑text answer per question. A teacher controls the match, creates rounds from a pre‑entered question list, and judges answers manually. Scoring is 6/3/1 for the first/second/third accepted answers per question based on the server timestamp of the submissions. A team may submit once per question. The teacher starts/stops each question without a time limit. Live views show the current question, incoming answers for the teacher, and a public leaderboard. Authentication is minimal: teacher login + team join by 5‑char code.

2) User roles & pages

Teacher

Student (Team)

Public/Share

3) Gameplay rules (authoritative spec)

Constraints:

4) Real‑time options (choose one at build time)

  1. Short‑polling (default MVP): client polls JSON endpoints every 1–2s. Easiest to host on Apache/PHP.

  2. SSE (Server‑Sent Events): simple one‑way push from server to clients for live updates (scoreboard/answers).

  3. WebSocket (Ratchet/Swoole): lowest latency, most complex. Optional v2.

Implement MVP with short‑polling, keep code structured so SSE can be swapped in later.

5) Data model (MariaDB)

-- users (teachers only)
CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  email VARCHAR(190) UNIQUE NOT NULL,
  password_hash VARCHAR(255) NOT NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

-- question bank
CREATE TABLE questions (
  id INT AUTO_INCREMENT PRIMARY KEY,
  title VARCHAR(255) NOT NULL,
  body TEXT NOT NULL,             -- markdown/text
  code_snippet TEXT NULL,          -- optional fenced code
  tags VARCHAR(255) NULL,
  created_by INT NOT NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (created_by) REFERENCES users(id)
) ENGINE=InnoDB;

-- matches (a session for a class)
CREATE TABLE matches (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  status ENUM('draft','active','finished') NOT NULL DEFAULT 'draft',
  created_by INT NOT NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (created_by) REFERENCES users(id)
) ENGINE=InnoDB;

-- match_questions (ordered list)
CREATE TABLE match_questions (
  id INT AUTO_INCREMENT PRIMARY KEY,
  match_id INT NOT NULL,
  question_id INT NOT NULL,
  position INT NOT NULL,                      -- 1..N order
  status ENUM('pending','open','closed') NOT NULL DEFAULT 'pending',
  opened_at DATETIME NULL,
  closed_at DATETIME NULL,
  FOREIGN KEY (match_id) REFERENCES matches(id),
  FOREIGN KEY (question_id) REFERENCES questions(id),
  UNIQUE KEY uq_match_pos (match_id, position)
) ENGINE=InnoDB;

-- teams
CREATE TABLE teams (
  id INT AUTO_INCREMENT PRIMARY KEY,
  match_id INT NOT NULL,
  name VARCHAR(120) NOT NULL,
  join_code CHAR(5) NOT NULL,                 -- generated before start
  total_score INT NOT NULL DEFAULT 0,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  UNIQUE KEY uq_match_team_name (match_id, name),
  UNIQUE KEY uq_join_code (join_code),
  FOREIGN KEY (match_id) REFERENCES matches(id)
) ENGINE=InnoDB;

-- submissions (one per team per question)
CREATE TABLE submissions (
  id INT AUTO_INCREMENT PRIMARY KEY,
  match_question_id INT NOT NULL,
  team_id INT NOT NULL,
  answer_text TEXT NOT NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  verdict ENUM('pending','accepted','rejected') NOT NULL DEFAULT 'pending',
  verdict_by INT NULL,                         -- teacher user id
  verdict_at DATETIME NULL,
  FOREIGN KEY (match_question_id) REFERENCES match_questions(id),
  FOREIGN KEY (team_id) REFERENCES teams(id),
  FOREIGN KEY (verdict_by) REFERENCES users(id),
  UNIQUE KEY uq_team_once (match_question_id, team_id),
  KEY idx_mq_created (match_question_id, created_at)
) ENGINE=InnoDB;

-- per-question score ledger (derived but stored for performance)
CREATE TABLE scores (
  id INT AUTO_INCREMENT PRIMARY KEY,
  match_question_id INT NOT NULL,
  team_id INT NOT NULL,
  points INT NOT NULL,
  rank INT NOT NULL,                           -- 1,2,3 for accepted order
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (match_question_id) REFERENCES match_questions(id),
  FOREIGN KEY (team_id) REFERENCES teams(id),
  UNIQUE KEY uq_score_once (match_question_id, team_id)
) ENGINE=InnoDB;

6) Scoring logic (deterministic)

Pseudocode:

$accepted = SELECT * FROM submissions
  WHERE match_question_id=? AND verdict='accepted'
  ORDER BY created_at ASC;
$pointsMap = [6,3,1];
for each team in accepted (i=0..2) assign $pointsMap[$i]; others 0.

7) HTTP routes (MVP)

Auth

Teacher – Matches & Questions

Teacher – Moderation & Live

Question Bank

Student – Join & Play

Public Leaderboard

Team


Revision #1
Created 2025-10-03 20:24:35 UTC by Max
Updated 2025-10-03 20:27:27 UTC by Max