Cross-platform setup and component-level run scripts for local development.
Linux/macOS use the .sh variants; Windows uses the .ps1 variants. They
replace the previous ad-hoc batch files (run-server.bat, run-app-chrome.bat,
run.bat, stop.ps1, ...).
For everyday use, prefer the root-level launchers. These are generated by
setup.sh / setup.ps1 (not committed) and regenerated on every setup run, so
they always match the current setup — just run setup and they appear in the repo
root:
| Scope | Linux / macOS | Windows |
|---|---|---|
| Server stack | ./run-server.sh |
.\run-server.ps1 |
| Client | ./run-client.sh |
.\run-client.ps1 |
To regenerate only the launchers (without re-running the full setup):
./setup.sh --launchers-only # Linux / macOS.\setup.ps1 -LaunchersOnly # WindowsFrom the repository root:
./setup.sh # Linux / macOS.\setup.ps1 # WindowsThis sets up all three components. Pass a single target to set up just one:
server, mail-server, or client.
Setup prompts you for the values server/.env needs — the app SECRET_KEY
(auto-generated default), database type/connection, Redis host/port/password, and
the Gmail OAuth client ID / secret / redirect URI — and writes a real .env from
your answers. Pressing Enter accepts the shown default; the Gmail fields are
optional (blank Gmail → /fileforge/oauth/gmail/authorize 503; server still
starts). The mail subsystem is part of the FileForge server, so there is no
separate mail-server/.env to configure.
Re-running with existing files. If a .env/config already exists, an
interactive run asks whether to reconfigure it (default: keep). Answer y
and it backs up the old file under backups/<timestamp>/<relative-path> before
re-asking every value; answer n (or just Enter) to keep it. To reconfigure
without being asked, pass --force (Linux) / -Force (Windows) -- the old file
is still backed up first. A non-interactive run always keeps existing files
untouched (idempotent / CI-safe).
For CI / unmanned runs, skip every prompt with --non-interactive (-y on Linux,
-NonInteractive on Windows); each field then takes its default, and any field
can be pre-seeded from the environment (e.g. GOOGLE_CLIENT_ID=… SECRET_KEY=… ./setup.sh -y). A non-tty / redirected stdin is auto-detected and treated as
non-interactive, so the script never hangs.
./setup.sh # interactive; asks before touching an existing .env
./setup.sh --force # reconfigure all .env/config (old files backed up)
./setup.sh server --force # reconfigure just server/.env.\setup.ps1 -Force
.\setup.ps1 server -Force| Component | Linux / macOS | Windows | URL |
|---|---|---|---|
| FastAPI backend (incl. mail subsystem) | scripts/run-server.sh |
scripts\run-server.ps1 |
http://localhost:8000 |
| Flutter client (web) | scripts/run-client.sh |
scripts\run-client.ps1 |
http://localhost:3031 |
The mail server is no longer a separate process. It was absorbed into the
FastAPI backend as the mail subsystem (/fileforge/mail/*); there is no Go
mailanchord build or :8090 listener anymore. scripts/run-mail-server.*
is kept only as a thin compatibility shim that forwards to run-server.*.
Each component runner runs in the foreground; use a separate terminal per component when invoking these lower-level scripts directly.
| Task | Linux / macOS | Windows |
|---|---|---|
| Build client release (apk/web) | scripts/build-client.sh [apk|web] |
scripts\build-client.ps1 -Target apk |
| Stop backends | scripts/stop.sh |
scripts\stop.ps1 |
- server — copy
server/.env.sample→server/.env(done by setup). Needs a reachable Redis (REDIS_HOSTin.env). - mail subsystem — absorbed into the FileForge server; there is no separate
mail-server/.env. Per-account SMTP settings are stored in the database, and Gmail OAuth accounts send over Gmail SMTP XOAUTH2 using the connected account's token. Gmail OAuth client credentials live inserver/.env(GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET/GOOGLE_REDIRECT_URI). - client — copy
client/config/dev.json→client/config/prod.json(done by setup) for production builds.
Common overrides:
PORT=9000 scripts/run-server.sh # server port
WEB_PORT=4152 scripts/run-client.sh # flutter web port
scripts/run-client.sh --clean # flutter clean before runscripts\run-server.ps1 -Port 9000
scripts\run-client.ps1 -WebPort 4152 -Clean