Files
Roster/README.md
T

119 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Roster Formatter
A local browser app that turns the current one-page roster PDF into the established formatted PNG. The web app and command-line tool use the same renderer.
## Start with Docker Compose
From this folder:
```bash
docker compose up -d --build
```
Open <http://127.0.0.1:8787>, upload the roster PDF, choose its month, and select **Format roster**.
Common commands:
```bash
docker compose restart # restart it later
docker compose logs -f app # watch logs
docker compose down # stop it
docker compose up -d --build # rebuild after code changes
```
The Compose service restarts automatically unless you explicitly stop it. Its direct browser port binds only to `127.0.0.1`.
The service also joins the existing external `tabernet` Docker network, so Caddy can reach it at `roster-formatter:8787`. For a Caddy hostname, add that hostname to `.env`:
```dotenv
ROSTER_ALLOWED_HOSTS=roster.example.com
```
Then a minimal Caddy route is:
```caddyfile
roster.example.com {
reverse_proxy roster-formatter:8787
}
```
The `tabernet` network must already exist. Because roster images contain personal information, add authentication in Caddy before exposing this service outside your private network.
## Saved files and automatic cleanup
Every successful PNG is returned to the browser with a **Download PNG** button and saved in [`output/`](output). The Compose container mounts that folder, so saved PNGs survive rebuilds and restarts.
Layout defaults are persistent too. Change values under **Advanced adjustments**, then select **Save as defaults** to prefill them for future rosters. **Reset changes** restores the currently saved values, while **Use original values** loads the production geometry without saving it. The server stores these defaults in `output/.roster-layout-defaults.json`, inside the same mounted volume, and the roster cleanup never removes that settings file.
On startup, every six hours, and after each successful format, the app removes only filenames matching its roster pattern, such as `MARCH 2026 Roster.png`, when either its roster month or saved-file age is outside the three-calendar-month window. The file-age check prevents an accidentally future-dated filename from bypassing cleanup. Other files are not removed. Cleanup is permanent.
Change the retention window or browser port with a `.env` file beside `compose.yaml`:
```dotenv
ROSTER_RETENTION_MONTHS=6
ROSTER_PORT=8788
TZ=America/Chicago
```
Set `ROSTER_RETENTION_MONTHS=0` to disable cleanup.
The image runs as UID/GID `1000:1000`, matching this machine. On a host with a different checkout owner, set `ROSTER_UID` and `ROSTER_GID` in `.env`, then rebuild so the container can write to `output/`:
```dotenv
ROSTER_UID=1001
ROSTER_GID=1001
```
## Layout guarantees
With the advanced fields untouched, the renderer preserves the original production values:
| Setting | Default |
| --- | ---: |
| Canvas | 792 × 612 PDF points |
| PNG export | 1650 × 1275 pixels at 150 DPI |
| Roster vertical shift | 100 |
| Bottom trim | 60 |
| Logo position | X 50, Y -10 |
| Logo scale | 0.27 |
| Date position | X 460, Y 88 |
| Date font size | 48 |
The web page exposes the layout values in a collapsed **Advanced adjustments** section. Only an intentional field change—or explicitly saving that change as the new default—alters logo/date scale or placement. The canvas size and PNG DPI are not editable. The original production values remain available through **Use original values**.
The page theme defaults to **System** and follows the browser/operating-system color preference. The **System / Light / Dark** control remembers the choice in that browser. Theme changes affect only the webpage and never the generated PNG.
Input is deliberately limited to a one-page, unrotated, 11 × 8.5 inch landscape PDF. This prevents a differently sized upload from silently changing the established geometry.
## Run without Docker
The existing `venv` already contains the formatter dependencies. Start the web app with:
```bash
venv/bin/python server.py
```
Or create a fresh environment:
```bash
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python server.py
```
The original CLI workflow is still available and now accepts an explicit input path:
```bash
venv/bin/python main.py --input input/original.pdf --month "July 2026"
```
## Tests
Run the standard-library test suite with:
```bash
PYTHONDONTWRITEBYTECODE=1 venv/bin/python -m unittest discover -v
```
Uploads and intermediate PDFs are created in isolated temporary directories and removed immediately after formatting. Only the final PNG is retained in `output/`.