Quickstart: Run the Whole Stack Locally
The fastest path from a fresh clone to a working end-to-end setup (server + mobile app on a phone/emulator on the same LAN). For deeper detail on any single component, see the per-component setup guides linked at each step.
This quickstart covers the minimum golden path: server + mobile app. GSM/SMS fallback and the admin frontend are optional add-ons, covered at the end.
1. Prerequisites checklist
- Docker + Docker Compose v2, Node ≥ 18, pnpm (mobile app's declared package manager — see
mobile-app/sapot-mobile-app/package.json'spackageManagerfield) - Android device or emulator, on the same Wi-Fi network as the machine running the server
- Nix (used to pin the mobile app's dev toolchain)
2. Start the server
All three commands run from the repo root, because docker/up.sh lives there, not in server/:
cp server/.env.example server/.env # edit placeholder secrets before anything but local dev
./docker/up.sh up --build -d
docker compose exec api alembic upgrade head
The first two bring up MariaDB, Redis, the API, an Nginx TLS terminator, the admin dashboard, and the tileserver together, with no local MariaDB/Redis install and no manual cert setup, auto-detecting this machine's LAN IP for the dev TLS certificate's SAN.
The third creates the schema. It is a required, separate step: the schema is owned by Alembic (ADR 0007) and nothing in the container runs it for you, so without it the API starts but every database-backed request fails. Re-run it after any pull that adds a migration.
Checkpoint: curl -sk https://<your-lan-ip>/version (or https://localhost/version from the same machine) returns a JSON version payload. If not, see Troubleshooting: server won't start.
Full detail: docker-setup.md. Prefer to run the API directly without Docker? See server-setup.md (bare-metal, requires installing MariaDB/Redis yourself).
3. Start the mobile app
# from mobile-app/
bash configure_nix.sh
nix develop -L
cd sapot-mobile-app
pnpm install
cp .env.example .env
Point the app at your server's LAN IP:
# mobile-app/sapot-mobile-app/.env
EXPO_PUBLIC_DEV_HOST=192.168.1.x # same host from step 2
pnpm dev
Open the app on your device/emulator (same Wi-Fi network as the server), go to the getting-started screen, tap Server Mode, then the cog icon on that card, and enter the same LAN IP.
Checkpoint: the app's login/registration screen loads without a network error. If it hangs or errors, see Troubleshooting: mobile app can't reach the server.
Full detail: mobile-app-setup.md.
4. Register a user and verify end-to-end messaging
- Register a new account in the app. To skip registration entirely, pick LAN Mode on the getting-started screen instead of Server Mode. It asks only for a first and last name and signs you in as a guest, with no server dependency for LAN messaging.
- Repeat step 3 on a second device on the same LAN.
- Discover the peer (automatic via mDNS on the same network) and send a message.
Checkpoint: the message appears on the recipient device. This confirms LAN peer discovery, transport (WebRTC data channel or LAN TCP+TLS), and E2E encryption are all working together.
5. Optional: GSM/SMS fallback
Only needed if testing SMS delivery to devices off the LAN. See gsm-module-setup.md — requires a serial-attached GSM modem and a shared GSM_SECRET matching the server's.
6. Optional: Admin frontend
Step 2's stack already builds and serves the dashboard: open https://<your-lan-ip>/admin (the
/admin prefix is required; the app sets basePath: "/admin"). A fresh database has no admin
account and the dashboard has no signup, so create the first one before you can log in. See
admin-frontend-setup.md.
Next steps
- architecture/system-overview.md — how the pieces fit together
- TROUBLESHOOTING.md — common setup failures and fixes
- environment-config.md — full environment variable reference