New maintenance.py runs a background asyncio loop (started from the app lifespan) that purges games which either finished more than PIRATS_PURGE_ FINISHED_DAYS (default 14) ago or have had no activity for PIRATS_PURGE_ INACTIVE_DAYS (default 30). "Activity" is a game's most-recent GameEvent timestamp; games with no events are undatable and left alone. Each purge is logged with the crew name, uuid, reason, idle days and an estimated byte footprint; every run that removes anything VACUUMs the SQLite file and logs the disk space actually reclaimed. Child rows go via the ORM cascade already declared on Game's relationships. Configurable via PIRATS_PURGE_ENABLED / _INTERVAL_HOURS / _FINISHED_DAYS / _INACTIVE_DAYS, exposed as services.pirats.purge.* in the NixOS module and documented in the README. Unit test covers the selection logic and cascade; smoke-tested the VACUUM/reclaim path against a file DB. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
180 lines
6.8 KiB
Markdown
180 lines
6.8 KiB
Markdown
# Rats with Gats Remote Play (`pirats`)
|
||
|
||
A web-based remote play companion app for the tabletop roleplaying game **Rats with Gats** (where players roleplay as gunslinging pirate rats, or "Pi-Rats", in the magical land of Yeld). The application manages lobbies, character creation, card mechanics, scene phases, obstacles, challenges, and player voting. See [RULEBOOK.md](RULEBOOK.md) for the game rules.
|
||
|
||
It is built with a **FastAPI** + **SQLModel** (SQLite) backend and a **Svelte 5** single-page frontend (in `frontend/`), which polls the backend's JSON state endpoint for near-real-time updates.
|
||
|
||
---
|
||
|
||
## Features
|
||
|
||
- **Game Lobby:** Create games and join as players via a unique game ID.
|
||
- **Character Creation:**
|
||
- Fill out the character profile (appearance, smell, catchphrase).
|
||
- Delegate custom "Like/Hate" relationship questionnaire cards to other crewmates (answering them for each other!).
|
||
- Draft three "Secret Pirate Techniques" which are automatically shuffled and swapped among players.
|
||
- Bind swapped techniques to Face Cards (Jack, Queen, King) for play.
|
||
- **Dynamic Card Mechanics:**
|
||
- Automated 54-card deck shuffling and card drawing.
|
||
- Automatically matches card suits to thematic obstacles (Clubs for combat, Spades for stealth/cunning, Hearts for social/morale, Diamonds for nautical/athletics).
|
||
- **Scene Management:**
|
||
- Assign roles (Pi-Rats or "The Deep" narrator).
|
||
- Dynamic challenge creation linking multiple active obstacles.
|
||
- Automatically handles card matching colors/values, automatic success when playing Face Card techniques, and Joker card triggers to discard/replace obstacles.
|
||
- **Between-Scenes Voting:**
|
||
- Vote on crewmates to rank up.
|
||
- Toggle personal objectives (Get a Gat, Earn a Name, Die like a Pirate).
|
||
|
||
---
|
||
|
||
## Installation & Running
|
||
|
||
This project supports standard Python package tools as well as Nix flakes.
|
||
|
||
### Option 1: Standard Python Installation
|
||
|
||
#### Prerequisites
|
||
- Python >= 3.9
|
||
- Virtual environment tool (optional but recommended)
|
||
|
||
#### 1. Setup Virtual Environment (Optional)
|
||
```bash
|
||
python -m venv .venv
|
||
source .venv/bin/activate
|
||
```
|
||
|
||
#### 2. Install Package
|
||
Install the package and its dependencies in editable mode:
|
||
```bash
|
||
pip install -e .
|
||
```
|
||
|
||
#### 3. Run the App
|
||
Launch the FastAPI server using the installed package entrypoint:
|
||
```bash
|
||
pirats --host 0.0.0.0 --port 8000 --reload
|
||
```
|
||
Alternatively, run it with `uvicorn`:
|
||
```bash
|
||
uvicorn pirats.main:app --host 0.0.0.0 --port 8000 --reload
|
||
```
|
||
|
||
Once running, access the web UI at [http://localhost:8000](http://localhost:8000).
|
||
|
||
#### Configuration (environment variables)
|
||
|
||
| Variable | Default | Purpose |
|
||
| --- | --- | --- |
|
||
| `DATABASE_URL` | `sqlite:///./rats_with_gats.db` | SQLAlchemy database URL. |
|
||
| `PIRATS_LOG_FILE` | _(unset)_ | If set, also write logs to this file (rotating, 10 MB × 5 backups). Logs always go to stderr regardless. |
|
||
| `PIRATS_LOG_LEVEL` | `INFO` | Minimum log severity (`DEBUG`/`INFO`/`WARNING`/`ERROR`/`CRITICAL`). |
|
||
| `PIRATS_DEV_MODE` | _(unset = on)_ | Default Dev Mode for new games. Unset is treated as a local checkout (on); set to `0`/`false` to disable. |
|
||
| `PIRATS_PURGE_ENABLED` | `true` | Periodically purge old finished/inactive games. |
|
||
| `PIRATS_PURGE_INTERVAL_HOURS` | `24` | How often the purge task runs. |
|
||
| `PIRATS_PURGE_FINISHED_DAYS` | `14` | Purge games that finished more than this many days ago. |
|
||
| `PIRATS_PURGE_INACTIVE_DAYS` | `30` | Purge games with no activity for this many days. |
|
||
|
||
---
|
||
|
||
### Option 2: Using Nix Flakes
|
||
|
||
If you use the Nix package manager, this repository provides a complete environment.
|
||
|
||
#### 1. Enter the Development Shell
|
||
Includes Python, all runtime dependencies, and testing tools (`pytest`):
|
||
```bash
|
||
nix develop
|
||
```
|
||
|
||
#### 2. Run the Application
|
||
Run the package directly from the flake:
|
||
```bash
|
||
nix run . -- --host 0.0.0.0 --port 8000
|
||
```
|
||
|
||
#### 3. Build the Application Package
|
||
```bash
|
||
nix build .
|
||
```
|
||
The executable will be located in `./result/bin/pirats`.
|
||
|
||
---
|
||
|
||
## Deploying as a NixOS Service
|
||
|
||
The Nix flake exposes a NixOS module that configures the application to run as a systemd service with appropriate sandboxing.
|
||
|
||
Add this flake to your system configuration and configure the service:
|
||
|
||
```nix
|
||
services.pirats = {
|
||
enable = true;
|
||
host = "127.0.0.1";
|
||
port = 8000;
|
||
databasePath = "/var/lib/pirats/rats_with_gats.db";
|
||
logFile = "/var/log/pirats/pirats.log"; # rotating; stderr also goes to the journal
|
||
logLevel = "info";
|
||
openFirewall = false; # Set to true to open ports in the firewall
|
||
purge = {
|
||
enable = true; # periodically remove old finished/inactive games
|
||
intervalHours = 24;
|
||
finishedDays = 14; # purge games finished more than 14 days ago
|
||
inactiveDays = 30; # ...or with no activity for 30 days
|
||
};
|
||
};
|
||
```
|
||
|
||
The service writes its log to `logFile` (under the systemd-managed `/var/log/pirats`
|
||
`LogsDirectory`, so the sandboxed `DynamicUser` can write to it) and additionally
|
||
to the systemd journal via stderr (`journalctl -u pirats`).
|
||
|
||
---
|
||
|
||
## Running Tests
|
||
|
||
Tests are written using `pytest`.
|
||
|
||
### Running with Pip
|
||
```bash
|
||
pytest
|
||
```
|
||
|
||
### Running with Nix
|
||
```bash
|
||
nix develop --command pytest
|
||
```
|
||
|
||
---
|
||
|
||
## Project Structure
|
||
|
||
```
|
||
pirats/
|
||
├── pyproject.toml # Python package metadata and dependencies
|
||
├── flake.nix # Nix package (incl. frontend build), dev shell, NixOS service module
|
||
├── tests/
|
||
│ └── test_game.py # Game logic and CRUD test suite (pure-crud, no HTTP for most)
|
||
├── frontend/ # Svelte 5 + Vite SPA
|
||
│ └── src/
|
||
│ ├── pages/ # Routes: Home, Join, Dashboard (game UI), Admin
|
||
│ ├── components/ # One component per game phase, Card.svelte, and scene/ (ScenePhase sub-panels)
|
||
│ └── lib/ # api.js (fetch wrapper), cards.js (card display helpers), suggestions.js (Suggest-button pools)
|
||
└── src/
|
||
└── pirats/ # FastAPI backend package
|
||
├── main.py # App setup, /api/game create/join/state endpoints, CLI entrypoint
|
||
├── models.py # SQLModel tables (Game, Player, Obstacle, Challenge, Vote, GameEvent)
|
||
├── cards.py # Card parsing, deck building, obstacle table from the rulebook
|
||
├── crud.py # Facade re-exporting all crud_* modules
|
||
├── crud_*.py # Game logic by phase: base (deck/hands/rank), character, scene, challenge, upkeep
|
||
├── routes_*.py # Thin API routers by phase, mounted under /api
|
||
└── static/ # Built frontend lands here (gitignored; populated by the Nix build)
|
||
```
|
||
|
||
### Frontend Development
|
||
|
||
Run the backend (`pirats --reload`) and the Vite dev server side by side; Vite proxies `/api` to port 8000:
|
||
|
||
```bash
|
||
cd frontend && npm install && npm run dev
|
||
```
|