Update readme, justfile and .gitignore

This commit is contained in:
2026-07-02 19:15:37 +03:00
parent 9d8eacfb2b
commit e43ebf250e
3 changed files with 96 additions and 34 deletions

View File

@@ -1,18 +1,54 @@
<h1 align="center">rota</h1>
Desktop app for generating monthly schedules for medical residents. The scheduling engine uses a parallel constraint-satisfaction DFS with a least-flexibility-first heuristic.
<p align="center">
Desktop app for generating monthly shift schedules for medical residents.
</p>
### Features
- Configurable residents, shift types, and forbidden pairings
- Negative shift requests and manual pre-assignments
- Fairness-aware workload distribution
- Export to `.docx` and `.txt`
<p align="center">
<img alt="Tauri" src="https://img.shields.io/badge/Tauri-2-24C8DB?logo=tauri&logoColor=white">
<img alt="Rust" src="https://img.shields.io/badge/Rust-2021-000000?logo=rust&logoColor=white">
<img alt="SvelteKit" src="https://img.shields.io/badge/SvelteKit-5-FF3E00?logo=svelte&logoColor=white">
<img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-green">
</p>
### Stack
- **Frontend**: SvelteKit + TypeScript + Tailwind CSS
- **Backend**: Rust (Tauri)
## Features
### Usage
```bash
just --list
```
- **Configurable roster**: residents, their allowed shift types, and per-resident shift caps
- **Constraints**: forbidden pairings, day-off (negative) requests, and manual pre-assignments that the solver works around
- **Fairness**: workload, weekend/holiday, and per-shift-type loads are balanced across the team
- **Interactive swaps**: after generating, ask the engine for all legal swaps for any shift and apply one without breaking constraints
- **Export**: one click writes the schedule and per-resident metrics to `.docx` and `.txt`
## How it works
A month is laid out as a sequence of **slots**. Days alternate between two kinds of duty:
| Day | Shift | Slots per day |
|-----|-------|---------------|
| odd | *open* | 2 |
| even | *closed* | 1 |
The solver fills every slot with exactly one resident subject to the hard constraints:
- no resident works two consecutive days
- forbidden ("toxic") pairs never share a day
- a resident is never placed on a day they requested off, or into a shift type they aren't allowed to take
- per-resident caps on total shifts, weekend/holiday shifts, and shifts of each type are respected
The search is a **backtracking DFS** over the slots, with a few tricks to make it fast and produce good schedules:
- **Least-flexibility-first**: at each slot, candidate residents are ordered by how few options they have left in the rest of the month, so the most constrained people get placed first (a fail-first / most-constrained heuristic).
- **Parallel roots**:the first slot's candidates are fanned out across threads with [rayon](https://github.com/rayon-rs/rayon); the first thread to find a complete schedule wins and signals the others to stop.
- **Timeout**: the search aborts after 5s and reports that no solution was found rather than hanging.
## Getting started
### Prerequisites
- [Rust](https://www.rust-lang.org/tools/install) (stable) and the [Tauri 2 system dependencies](https://tauri.app/start/prerequisites/) for your OS
- [Node.js](https://nodejs.org/) and [pnpm](https://pnpm.io/)
- [`just`](https://github.com/casey/just) (optional, for the shortcuts below)
## Commands
Run `just --list` to see every recipe.