No description
Find a file
Andras Schmelczer 853f88c66b
All checks were successful
Test / test (push) Successful in 7s
Deploy to Pages / deploy (push) Successful in 10s
Build and Publish Docker Image / build-and-push (push) Successful in 23s
Improve security
2026-06-06 19:39:24 +01:00
.forgejo/workflows Set up CI 2026-06-06 19:36:15 +01:00
backend Improve security 2026-06-06 19:39:24 +01:00
frontend Improve security 2026-06-06 19:39:24 +01:00
.gitignore Remove clutter 2025-08-31 13:45:01 +01:00
.prettierignore Set up CI 2026-06-06 19:36:15 +01:00
.prettierrc.json Set up CI 2026-06-06 19:36:15 +01:00
package-lock.json Set up CI 2026-06-06 19:36:15 +01:00
package.json Set up CI 2026-06-06 19:36:15 +01:00
README.md Set up CI 2026-06-06 19:36:15 +01:00

Fizika

Practice web app for the Hungarian emelt szintű fizika (advanced-level physics) written school-leaving exam. Students generate quizzes from a bank of past exam questions — by topic, by exam paper, or as a random "érettségi" set — answer them, and review their past results (stored locally in the browser).

Live at https://fizika.schmelczer.dev.

Architecture

frontend/  Static site (HTML + CSS + jQuery, no build step).
           Deployed to Pages. Fetches questions from the backend API.

backend/   Express server. Serves the admin panel and a small REST API for
           editing questions and images. Reads/writes a single JSON file plus
           an images directory.

The backend is the single source of truth for question data. The frontend always fetches it from GET /api/fizika (see frontend/js/load.js); the question JSON is no longer shipped with the static site.

Access control

Authentication is handled at the reverse proxy (nginx + basic auth), not in the app. The proxy exposes only two endpoints publicly; everything else (the admin panel and all /api/admin/* routes) requires a login:

Path Access Purpose
/api/fizika public question data for the public app
/api/pics/* public question images
everything else private admin panel + edit API

The app trusts the proxy, so do not expose the backend port directly without adding authentication in front of it.

API

Method Route Description
GET /api/fizika All questions
GET /api/images List image filenames
GET /api/pics/:file Serve an image
GET /api/admin/questions All questions (admin)
POST /api/admin/questions Create a question
PUT /api/admin/questions/:id Update a question
DELETE /api/admin/questions/:id Delete a question
POST /api/admin/images/upload Upload an image
DELETE /api/admin/images/:filename Delete an image

Configuration

The backend is configured via environment variables:

Variable Default Description
PORT 3001 Port to listen on
DATA_PATH ../frontend/fizika.json Path to the questions JSON file
PICS_PATH ../frontend/pics Directory holding question images
FRONTEND_URL * Allowed CORS origin

In production DATA_PATH and PICS_PATH point at mounted volumes that hold the canonical data. The defaults are dev conveniences only — set both explicitly to a JSON file and a directory that exist before starting.

Development

cd backend
npm install
DATA_PATH=/path/to/fizika.json PICS_PATH=/path/to/pics npm run dev

Then open frontend/index.html (or serve frontend/ statically). On localhost the frontend talks to the backend on port 3001 automatically.

Tests

Backend tests use Node's built-in test runner (no extra dependencies):

cd backend
npm test

Formatting

Prettier formats the whole repo. Run from the repo root:

npm install        # once, to install Prettier
npm run format       # write
npm run format:check # verify (also run in CI)

CI / Deployment

Forgejo Actions workflows in .forgejo/workflows/:

  • test.yml — formatting check + backend tests on every push/PR.
  • docker-publish.yml — builds and publishes the backend image from backend/.
  • deploy.yml — deploys frontend/ to Pages.