Local setup
Goal: a fully working platform on your laptop in about 20 minutes, without manually copy-pasting any secret.
Prerequisites
- Node.js 20.11.1 — match the production version. We recommend
nvmso you can switch per-project. - Docker + Docker Compose — Docker Desktop on Mac is the easiest path.
- MySQL client (optional) — only needed if you want to poke at the containerised DB directly.
- An Infisical account on the team’s instance, with access to the development environment. Your tech lead can issue this.
1. Clone
git clone https://github.com/E-DigitalGroup/tunnelflight.git
cd tunnelflightThe monorepo contains four runtime apps plus the docs site:
| Folder | Stack | Deployed to |
|---|---|---|
api/ | Node + Express + MySQL + Redis | DigitalOcean App Platform |
www/ | Node + Express + EJS + Backbone | DigitalOcean App Platform |
admin/ | Next.js 14 + React 18 + Bootstrap | DigitalOcean App Platform |
tools/ | Cloudflare Worker (API) + React SPA (Pages) | Cloudflare Workers + Pages |
docs/ | Nextra v4 (Next.js static export) | Cloudflare Pages |
The DO-hosted apps (api, www, admin) live in the same DigitalOcean project and share the production MySQL cluster. tools/ is deliberately decoupled — see its overview for the disaster-recovery rationale. docs/ is what you’re reading right now.
2. Create infisical.env
The boot script reads its Infisical credentials from infisical.env at the
repo root. This file is gitignored — never commit it.
Create it with:
INFISICAL_SITE_URL=https://app.infisical.com
INFISICAL_CLIENT_ID=<your-client-id>
INFISICAL_CLIENT_SECRET=<your-client-secret>
INFISICAL_PROJECT_ID=<the-team-project-id>
INFISICAL_ENVIRONMENT=developmentAsk your tech lead for the client ID, client secret, and project ID. The secret is yours, do not share it.
3. Start
chmod +x docker-cleanup.sh docker-start.sh
# Wipes any existing IBA containers + volumes. Skip on first run.
./docker-cleanup.sh
./docker-start.shWhat docker-start.sh does, in order:
- Installs the Infisical CLI if you don’t already have it
(
brew install infisical/get-cli/infisicalon macOS). - Authenticates against Infisical with your credentials and exports
the resolved
.envto a temp file. - Pulls the latest production database dump from S3 and seeds the containerised MySQL.
- Brings up MySQL, Redis, the API, and WWW via
docker compose.
First run takes ~5 minutes (image pulls + DB restore). Subsequent runs are much faster — the containers and volumes persist.
4. Verify
| Service | URL | What you should see |
|---|---|---|
| API health | http://localhost:<api-port>/health | { "status": "ok" } |
| WWW | http://localhost:<www-port>/ | The IBA homepage |
| Admin (separate) | cd admin && npm run dev → http://localhost:3000 | The admin login |
| Docs (this site) | cd docs && npm run dev → http://localhost:3000 | This very page |
| Tools (separate) | cd tools && npm run dev → http://localhost:3000 (app) + :8787 (worker) | Member search UI |
The exact API and WWW ports are set in docker-compose.yml; the boot
script prints them as it starts up.
The admin, docs, and tools dev servers are intentionally not part of
docker-start.sh — they run with hot-reload outside Docker because that’s
where most active development happens. You start them as needed. Tools
also requires a separate one-time credential setup (cp api/.dev.vars.example api/.dev.vars then fill in the production DB read-only credentials your
tech lead provides) — see the Tools overview for details.
Common first-run snags
- “infisical.env: No such file” — you skipped step 2. Create the file
at the repo root (not under
api/, not underdocs/). - “Cannot connect to Docker daemon” — Docker Desktop isn’t running.
Start it and re-run
./docker-start.sh. - MySQL container restarts in a loop — the S3 dump may have failed
to download. Check that your Infisical access includes the AWS keys.
Re-run
./docker-cleanup.sh && ./docker-start.sh. - Port already in use — another local DB or Redis is bound to the
same port. Stop it, or change the port in
docker-compose.yml.
What’s next
Once everything’s running locally, head to Your first PR to learn the branch + commit + PR conventions.