# rs_maps — build and deploy Single Rust binary + one rootless Postgres container. See `DESIGN.md` for the reasoning. > **This code has not been compiled.** It was written without a Rust toolchain available, > so treat the first `cargo build` as the real review. Expect to fix a handful of import > paths and trait-bound details, not the structure. ## 1. Refresh dependency versions `Cargo.toml` has plausible versions, but pin them properly: ```bash cargo add axum -F multipart,macros cargo add tokio -F full cargo add sqlx --no-default-features -F runtime-tokio,tls-rustls,postgres,uuid,time,macros,migrate cargo add tower-sessions cargo add tower-sessions-sqlx-store -F postgres cargo add lettre --no-default-features -F tokio1-rustls,smtp-transport,builder,pool cargo add rust-embed -F debug-embed cargo build ``` Two version-sensitive spots to check first if it doesn't compile: - **`tower-sessions` / `tower-sessions-sqlx-store` must be a matching pair.** The store crate tracks the main crate's version and they break in lockstep. Check the store's own README for which `tower-sessions` it expects. - **axum 0.8 changed path params from `:id` to `{id}`.** This code uses `{id}`. If you end up on 0.7 for some reason, they all need changing back. ## 2. Database ```bash podman secret create mapserver-db-password - # type the password, then Ctrl-D mkdir -p ~/.config/containers/systemd cp deploy/postgres.container ~/.config/containers/systemd/ systemctl --user daemon-reload systemctl --user start postgres ``` Migrations run automatically on startup — both `./migrations` and the session store's own. ## 3. Config ```bash mkdir -p ~/.config/mapserver ~/gpx cp .env.example ~/.config/mapserver/.env chmod 600 ~/.config/mapserver/.env $EDITOR ~/.config/mapserver/.env ``` Must change: `DATABASE_URL`, `REG_TOKEN`, `PUBLIC_URL`, `BASE_PATH`, `GPX_DIR`. Leave `SMTP_HOST` empty for now — reset links get logged instead of emailed, and the whole flow is testable without a provider. ## 4. Run ```bash cargo build --release mkdir -p ~/.local/bin && cp target/release/mapserver ~/.local/bin/ cp deploy/mapserver.service ~/.config/systemd/user/ systemctl --user daemon-reload systemctl --user enable --now mapserver loginctl enable-linger "$USER" # or nothing starts at boot journalctl --user -u mapserver -f ``` ## 5. nginx Merge `deploy/nginx-snippet.conf` into your existing TLS server block, then `nginx -t && systemctl reload nginx`. ## 6. First account Visit `https://your-domain/maps/`, choose "Create an account", and enter the `REG_TOKEN` from `.env`. --- ## Testing the reset flow with real mail `mailpit` gives you a local SMTP server and a web inbox with no signup: ``` SMTP_HOST=127.0.0.1 SMTP_PORT=1025 SMTP_TLS=none SMTP_USERNAME= SMTP_PASSWORD= ``` When you move to a real provider: use an app-specific password (any account with 2FA will reject the normal one over SMTP), check SMTP isn't disabled by default on the account, and make sure `SMTP_FROM` is an address that account may send as. ## Things worth checking by hand after the first deploy - `curl -i https://your-domain/maps/api/gpx/file/../../etc/passwd` → 400 or 404, never a file - Live location works (needs HTTPS; it silently fails on plain HTTP) - Session survives `systemctl --user restart mapserver` - Upload a >2 MB GPX — catches both the axum and nginx body limits at once - Upload the same filename twice — second one should come back as `name-1.gpx` - Reboot the server, confirm both units come back (this is what `enable-linger` is for) ## Unit tests cargo test No database needed — every test is pure: base-path normalisation, bbox parsing, GPX filename safety, and the rate-limiter window.