# sortof A Project Zomboid mod load-order sorter. Paste Steam Workshop IDs or a collection URL, get back the three lines (`WorkshopItems=`, `Mods=`, `Map=`) you paste into your dedicated server's `.ini` file. ## Stack - **API** — FastAPI + asyncpg, Python 3.12. - **Cache** — PostgreSQL 16. One row per `(workshop_id, mod_id)` parsed from each mod's `mod.info`. Cache invalidates on Steam's `time_updated`; no manual TTLs. - **Drain worker** — pulls cache misses via DepotDownloader, parses `mod.info` and `media/maps/*/map.info`, writes back to Postgres. - **Frontend** — vanilla JSX in `frontend/`, served by FastAPI `StaticFiles`, transpiled in-browser by Babel-standalone. No build step, no npm. - **Deployment** — Docker for Postgres only; the API and drain workers run as systemd units on the host. ## What it actually does - Resolves bare workshop IDs **and** collection URLs (anonymous Steam API expansion). - Topologically sorts mods by `requirements`, `loadAfter`, `loadBefore` with explicit support for `loadFirst` / `loadLast` and the "patch" tier. - Detects multi-branch wsids (e.g. AuthenticZ, Project RV Interior), auto-picks a sensible default by build flavor or input cross-reference, and surfaces the alternates in a picker. - Emits actionable warnings: missing dependencies (with one-click "add" buttons when the dep is in our cache), build-mismatch flags with swap-or-remove actions, duplicate-mod_id conflicts, addon detection, and required-item suggestions scraped from the Workshop page. - Tracks community-reported broken mods per PZ build, with thumbs-up / thumbs-down voting and a search panel. ## Bootstrapping (rough) 1. `docker compose up -d sortof_db` — runs Postgres on `127.0.0.1:5439`, applies `init/*.sql` migrations on first boot. 2. Create the two virtualenvs: ```bash python3.12 -m venv api/.venv && api/.venv/bin/pip install -r api/requirements.txt python3.12 -m venv worker/.venv && worker/.venv/bin/pip install -r worker/requirements.txt ``` 3. Drop a `.env` next to `docker-compose.yml` with `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`, and `SORTOF_CORS_ORIGINS`. 4. Set `DD_PATH` to wherever DepotDownloader lives, then start the API (`api/.venv/bin/uvicorn app:app --host 127.0.0.1 --port 8801`) and a drain worker (`worker/.venv/bin/python drain.py`). For the systemd units, see `docs/` (and the running host). ## Layout ``` api/ FastAPI service + adapters + sort engine worker/ drain worker — DepotDownloader + mod.info parser frontend/ vanilla JSX + index.html (no build step) init/ Postgres bootstrap migrations (runs in order) data/ checked-in JSON like pz_versions.json docs/ specs, plans, audit notes ``` ## License TBD.