README.en.md
Rama main · réplica de lectura del repositorio original.
# Teacher Cover, Substitutions & Exam Invigilation Manager
> **Open-source** web app, developed with **Claude Code**, to organise **teacher cover / substitutions** and
> **exam invigilation** in a school: automatic, fair duty assignment, PDF reports
> and timetable import from [FET](https://lalescu.ro/liviu/fet/).
[Català](README.md) · [Castellano](README.es.md) · **English**
[](LICENSE)


**Live demo:** [demo.gestor.alienamrt.org](https://demo.gestor.alienamrt.org) — log in with `user_demo` or `admin_demo` (to see the admin features), password `demo1234`. _The demo resets daily at 4:00._
> ⚠️ The demo is **public and shared**: other people may be using it at the same time and can see whatever you enter. Do not upload timetables or real personal data from your school.
<!--
Keywords (for search discovery):
teacher cover supervision · substitute teacher scheduling · relief teacher ·
exam invigilation scheduler · invigilation rota · teacher absence management ·
gestión de guardias y sustituciones · gestió de guàrdies i substitucions.
-->
If you are looking for **cover supervision software**, a **substitute teacher
scheduler** or a tool to build a fair **exam invigilation rota**, this project
covers the whole workflow in a single, self-hostable, free application.
---
## Screenshots
| Daily substitutions | Invigilation & groups | Exam scheduler |
|---|---|---|
|  |  |  |
> _Screenshots use the sample institution (`Prof 1`, `Prof 2`…); no real data._
---
## Features
- **Daily cover & substitutions** with automatic substitute assignment
- **Exam invigilation** and management of groups without class
- **Fair workload distribution** based on load and configurable constraints
- **PDF export** (substitutions, invigilation, intervals, management reports)
- **Exam scheduler** with automatic optimisation (3 generation engines)
- **FET timetable import** (XML from _Free Timetabling Software_)
- **Multi-institution**: one database per school, global authentication
- **Roles**: `super_admin`, `admin`, `user`
- **Multilingual UI**: Catalan, Spanish, English and Italian
## Architecture
**Stack:** FastAPI + Vue 3 + PrimeVue · SQLite · Docker + Caddy
```
Caddy (reverse proxy + HTTPS)
├── /api/* → backend:8000 (FastAPI)
└── /* → frontend:80 (Vue 3 + Nginx)
data/
├── auth.db # Global users
└── {institution}/
├── gestor.db # School data
├── *.xml # School's FET timetable
└── exports/ # Generated PDFs
```
The FastAPI backend exposes the API under `/api/*`, handles XML timetable parsing,
automatic assignment of substitutes and invigilators, and PDF export. The Vue 3 +
PrimeVue frontend organises navigation into tabs: substitutions, invigilation,
groups and the exam scheduler. The scheduling engine (`scheduler_engine/`) ships
three generators (attempts, backtracking and Simulated Annealing) with a
configurable constraint model.
The logic called by the routes lives in `serveis/` (the state of a day,
`DiaEscolar`, and the single rule for when a substitute can no longer cover;
generating substitutions, marking absences, validating before the PDF), and the
assignment engine in `core/`.
### Rules
- A teacher is free if their group is marked as having no class at that hour
(exactly, including combined groups) or if they are released.
- Only the "Generate pending", "Regenerate all" and "Reassign" (in the
pre-PDF validation) buttons assign substitutes. Changes to the day (released groups, absences,
covered absences) remove substitutes who can no longer cover and leave the row pending,
with a notice.
- A teacher with a covered absence (their classes are covered in the XML, by a
substitute or by other teachers) is left out of everything during the
period: they neither cover, nor are covered, nor supervise.
Over 700 tests (`cd backend && pytest tests/`) on temporary institutions with
the sample timetable.
For the full dependency map and the rules in detail see
[ARQUITECTURA.md](ARQUITECTURA.md) (in Catalan).
---
## Quick local test
To try the app with the bundled sample data, without Docker or a domain.
**Requirements:** Python 3.10+ and Node.js 22+
### 1. Clone
```bash
git clone https://github.com/mrtvillaret/fet-substitutions-manager.git
cd fet-substitutions-manager
```
### 2. Backend
```bash
cd backend
python3 -m venv venv
source venv/bin/activate # Linux/macOS
# venv\Scripts\activate # Windows
pip install -r requirements.txt
cp .env.example .env
# Edit .env: set absolute paths in DATA_DIR and AUTH_DB_PATH pointing to
# {project path}/data and {project path}/data/auth.db
uvicorn main:app --reload --host 0.0.0.0 --port 8000
```
The backend automatically creates the databases (`auth.db` and
`data/{APP_INSTITUCIO}/gestor.db`) on first start and, if there are no users
yet, a super_admin from `ADMIN_USERNAME`/`ADMIN_PASSWORD` in `.env`.
API at `http://localhost:8000` · Docs at `http://localhost:8000/docs`.
### 3. Frontend
In another terminal:
```bash
cd frontend
npm install
npm run dev
```
Open `http://localhost:5173` and log in with the `super_admin` credentials defined
in the backend `.env`. The dev frontend proxies to the backend
via Vite.
### 4. Load the sample data
Once inside, go to **Settings > Import XML** and upload `data/exemple/teachers.xml`.
It is a sample timetable generated with FET.
---
## Local Docker (no domain)
To try it with Docker without configuring a domain or HTTPS, there is a
`docker-compose.local.yml.example` that starts only backend + frontend (no Caddy)
and serves the app at `http://localhost:8080`.
```bash
cp .env.example .env
cp docker-compose.local.yml.example docker-compose.local.yml
# Edit .env: generate SECRET_KEY (openssl rand -hex 32), set COOKIE_SECURE=false
# (required for plain HTTP) and an ADMIN_PASSWORD
docker compose -f docker-compose.local.yml up --build -d
```
Open `http://localhost:8080`.
> ⚠️ This mode has no HTTPS; local development only. **Do not use in production**,
> tokens travel in clear text.
---
## Production deployment
Recommended with Docker + Caddy (automatic HTTPS). You will need:
- A server with Docker and Docker Compose
- A domain pointing to the server
### 1. Clone and configure
```bash
git clone https://github.com/mrtvillaret/fet-substitutions-manager.git
cd fet-substitutions-manager
cp .env.example .env
cp Caddyfile.example Caddyfile
cp docker-compose.yml.example docker-compose.yml
```
Edit `.env`:
```env
SECRET_KEY= # required — generate with: openssl rand -hex 32
APP_INSTITUCIO=school_name # slug without spaces/accents
ADMIN_INSTITUCIO=school_name # identical to APP_INSTITUCIO
ADMIN_PASSWORD=a-strong-password
```
Edit `Caddyfile` and replace `el-teu-domini.exemple.com` with your real domain
(with DNS already pointing to the server).
### 2. Start
```bash
docker compose up --build -d
```
Caddy obtains the TLS certificate automatically. The app will be at
`https://{your-domain}`.
The application **will not start** without `SECRET_KEY`, or, on a new
installation (no users yet), without `ADMIN_PASSWORD`. Neither has a default
value, on purpose: no installation should end up exposed with credentials that
are published in this repository. If super_admin access is lost, it can be
recovered with `ADMIN_PASSWORD_RECUPERACIO` (see `.env.example`), which must be
removed from the environment after use.
### 3. First login
- Log in as `super_admin` with the password set in `ADMIN_PASSWORD`
- **Change the password** immediately from Settings > Users
- Upload your school's XML (generated by [FET](https://lalescu.ro/liviu/fet/))
from Settings > Import XML
### Access log
If you enable the proxy's access log (see `Caddyfile.example`), IP addresses
are stored. The example ships with a configurable retention period.
### Updates
```bash
cd /path/to/project
git pull
docker compose up --build -d
```
---
## Sample data
The `data/exemple/` directory includes a `teachers.xml`: a sample timetable
generated with [FET](https://lalescu.ro/liviu/fet/).
---
## Backups
All data lives in the `./data/` folder. Make periodic copies of this folder with
your preferred tool (cron + rsync, rclone to a cloud, etc.).
```bash
# Minimal rsync example
rsync -a /opt/gestor/data/ /backup/gestor-data/
```
---
## License
Released under the [GNU Affero General Public License, version 3 or later](LICENSE).
Copyright (C) 2026 Martí Villaret Ausellé.