Scaffold project layout

This commit is contained in:
ameer
2026-05-02 02:54:34 +08:00
parent 320f1e4440
commit f5ac80a7a5
36 changed files with 183 additions and 0 deletions

18
.env.example Normal file
View File

@@ -0,0 +1,18 @@
# SQLite database path
QUIZ_DB_PATH=./quiz.db
# Required cookie signing secret
QUIZ_SECRET_KEY=change-me-to-a-random-secret
# Required shared instructor password
QUIZ_ADMIN_PASSWORD=change-me
# Uvicorn bind settings
QUIZ_HOST=127.0.0.1
QUIZ_PORT=8001
# Public URL used for student join links and QR codes
QUIZ_PUBLIC_URL=https://quiz.ahkhan.me
# Python logging level
QUIZ_LOG_LEVEL=INFO

11
.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
.venv/
__pycache__/
*.py[cod]
.pytest_cache/
.coverage
htmlcov/
.env
quiz.db
*.db
*.db-shm
*.db-wal

3
NOTES.md Normal file
View File

@@ -0,0 +1,3 @@
# Notes
Implementation notes will be filled in as the application lands.

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# Live In-Lecture Quiz Portal
Development notes will be filled in as the implementation lands.

3
app/__init__.py Normal file
View File

@@ -0,0 +1,3 @@
"""Live quiz application package."""
__version__ = "0.1.0"

1
app/auth.py Normal file
View File

@@ -0,0 +1 @@
"""Cookie signing helpers."""

1
app/config.py Normal file
View File

@@ -0,0 +1 @@
"""Application configuration."""

1
app/csv_export.py Normal file
View File

@@ -0,0 +1 @@
"""CSV export helpers."""

1
app/db.py Normal file
View File

@@ -0,0 +1 @@
"""SQLite helpers."""

9
app/main.py Normal file
View File

@@ -0,0 +1,9 @@
from fastapi import FastAPI
def create_app() -> FastAPI:
app = FastAPI(title="Live In-Lecture Quiz Portal")
return app
app = create_app()

1
app/models.py Normal file
View File

@@ -0,0 +1 @@
"""Pydantic request and response models."""

1
app/pool.py Normal file
View File

@@ -0,0 +1 @@
"""Question pool validation."""

1
app/room.py Normal file
View File

@@ -0,0 +1 @@
"""In-process WebSocket room manager."""

1
app/routes_admin.py Normal file
View File

@@ -0,0 +1 @@
"""Instructor routes."""

1
app/routes_student.py Normal file
View File

@@ -0,0 +1 @@
"""Student routes."""

1
app/scoring.py Normal file
View File

@@ -0,0 +1 @@
"""Score functions."""

39
pyproject.toml Normal file
View File

@@ -0,0 +1,39 @@
[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"
[project]
name = "quiz"
version = "0.1.0"
description = "Live in-lecture quiz portal"
requires-python = ">=3.11"
dependencies = [
"fastapi~=0.115",
"uvicorn[standard]~=0.34",
"aiosqlite~=0.20",
"itsdangerous~=2.2",
"python-multipart~=0.0.20",
"qrcode[pil]~=8.0",
]
[project.optional-dependencies]
dev = [
"pytest~=8.3",
"pytest-asyncio~=0.25",
"pytest-cov~=6.0",
"httpx~=0.28",
]
[tool.setuptools]
packages = ["app"]
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
[tool.coverage.run]
source = ["app"]
[tool.coverage.report]
show_missing = true
fail_under = 80

13
static/admin.html Normal file
View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Quiz Admin</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<main id="admin-app"></main>
<script type="module" src="/static/admin.js"></script>
</body>
</html>

2
static/admin.js Normal file
View File

@@ -0,0 +1,2 @@
const app = document.querySelector("#admin-app");
app.textContent = "Loading admin...";

15
static/observer.html Normal file
View File

@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Quiz Observer</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<main class="shell">
<h1>Quiz Observer</h1>
<p>This read-only view is reserved for a future classroom display.</p>
</main>
</body>
</html>

2
static/quiz.js Normal file
View File

@@ -0,0 +1,2 @@
const app = document.querySelector("#app");
app.textContent = "Loading quiz...";

13
static/student.html Normal file
View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Quiz</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<main id="app"></main>
<script type="module" src="/static/quiz.js"></script>
</body>
</html>

17
static/style.css Normal file
View File

@@ -0,0 +1,17 @@
:root {
color-scheme: light dark;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
body {
margin: 0;
min-height: 100vh;
background: #f6f7f9;
color: #18212f;
}
.shell {
max-width: 960px;
margin: 0 auto;
padding: 24px;
}

1
tests/conftest.py Normal file
View File

@@ -0,0 +1 @@
"""Test fixtures."""

2
tests/test_api_admin.py Normal file
View File

@@ -0,0 +1,2 @@
def test_placeholder_api_admin():
assert True

View File

@@ -0,0 +1,2 @@
def test_placeholder_api_student():
assert True

2
tests/test_auth.py Normal file
View File

@@ -0,0 +1,2 @@
def test_placeholder_auth():
assert True

2
tests/test_csv_export.py Normal file
View File

@@ -0,0 +1,2 @@
def test_placeholder_csv_export():
assert True

2
tests/test_late_join.py Normal file
View File

@@ -0,0 +1,2 @@
def test_placeholder_late_join():
assert True

View File

@@ -0,0 +1,2 @@
def test_placeholder_load_simulation():
assert True

2
tests/test_pool.py Normal file
View File

@@ -0,0 +1,2 @@
def test_placeholder_pool():
assert True

2
tests/test_reconnect.py Normal file
View File

@@ -0,0 +1,2 @@
def test_placeholder_reconnect():
assert True

2
tests/test_scoring.py Normal file
View File

@@ -0,0 +1,2 @@
def test_placeholder_scoring():
assert True

View File

@@ -0,0 +1,2 @@
def test_placeholder_state_machine():
assert True

2
tests/test_ws_admin.py Normal file
View File

@@ -0,0 +1,2 @@
def test_placeholder_ws_admin():
assert True

2
tests/test_ws_student.py Normal file
View File

@@ -0,0 +1,2 @@
def test_placeholder_ws_student():
assert True