Docker setup, Makefile targets, hot reload, ngrok tunneling, and helper scripts.
- Docker and Docker Compose (v2)
- ngrok account — sign up (free tier works)
- (Optional) Go 1.25+ for running tests outside Docker
make install.\install.ps1Use the project in two phases:
- Phase 1 — first bootstrap
- Set
NGROK_AUTHTOKEN - Optionally set a stable
NGROK_URL - Leave
APPMAX_CLIENT_ID,APPMAX_CLIENT_SECRET,APPMAX_APP_ID_UUID, andAPPMAX_APP_ID_NUMERICblank on purpose - Run
make installon macOS/Linux or.\install.ps1on Windows PowerShell - Copy the printed
Frontend URL,Install URL, andCallback URLinto Appmax
- Set
- Phase 2 — credential activation
- Wait for Appmax to email the 4 app credentials
- Fill
APPMAX_*in.env - Run
make installagain on macOS/Linux or.\install.ps1again on Windows PowerShell
As of March 20, 2026, App Store URL changes are not automatically replicated into the Appmax sandbox. If those URLs change after the first Appmax registration, contact desenvolvimento@appmax.com.br and ask them to replicate the update.
Each full install run (make install on macOS/Linux or .\install.ps1 on Windows PowerShell) executes:
env-init— copies.env.exampleto.envif missinggenerate-key— generates a 32-characterAPP_KEYif not setteardown— removes old containers and volumesup— builds and starts all containersmigrate— runs database migrationstest— runs Go tests inside the app containervalidate— verifies all endpoints are reachable via ngrok
| Service | Image | Purpose | Ports | Health Check |
|---|---|---|---|---|
postgres |
postgres:16-alpine |
Database | 5432 |
pg_isready every 5s, 10 retries |
redis |
redis:7-alpine |
Cache (install state, merchant tokens) | 6379 |
redis-cli ping every 5s, 10 retries |
app |
Dockerfile dev target |
Go app with Air hot reload | 8080 |
wget /health every 5s, 30 retries, 180s start period |
ngrok |
ngrok/ngrok:alpine |
Public HTTPS tunnel | 4040 (inspector) |
Checks /api/tunnels every 3s, 20 retries |
nginx |
nginx:alpine |
Reverse proxy | 80 |
— |
Startup order: postgres + redis → app (waits for both healthy) → ngrok (waits for app healthy) → nginx.
The Dockerfile has two build targets:
FROM golang:1.25-alpine AS builder
# CGO_ENABLED=0 static binary → /app/serverFROM golang:1.25-alpine AS dev
# Installs Air for hot reload
# Source code mounted via volume
# CMD ["air"]Config: .air.toml
| Setting | Value |
|---|---|
| Watches | *.go files, .env |
| Excludes | tmp/, .git/, tests/, vendor/ |
| Build command | go build -o ./tmp/server ./main.go |
| Delay after change | 500ms |
When you edit a .go file, Air rebuilds and restarts the server automatically.
| Target | Description |
|---|---|
make install |
Full setup: env → key → teardown → up → migrate → test → validate |
make up |
Build images and start all containers |
make down |
Stop containers, remove volumes and orphans |
make restart |
Restart all containers |
make logs |
Follow all container logs (docker compose logs -f) |
make health |
Wait for /health to respond (up to 60 attempts, 3s apart) |
make validate |
Verify all endpoints reachable via ngrok (checks frontend, health, install, callback, webhook) |
make test |
Run go test ./... inside the app container |
make migrate |
Run Goravel migrations (artisan migrate) |
make env-init |
Copy .env.example → .env if missing |
make generate-key |
Generate 32-char random APP_KEY if not set or invalid length |
make teardown |
Remove all containers and volumes |
make rename-module NEW=github.com/foo/bar |
Rename Go module path across all files |
ngrok provides a public HTTPS URL that tunnels to your local app. Appmax needs this for the first App Store registration and later for callback/webhook access.
In .env:
NGROK_AUTHTOKEN=your_token_here
NGROK_URL= # leave empty for dynamic URL
| Setting | Behavior |
|---|---|
NGROK_AUTHTOKEN set, NGROK_URL empty |
ngrok assigns a random URL (changes on restart) |
NGROK_AUTHTOKEN set, NGROK_URL set |
ngrok uses your reserved static domain |
NGROK_AUTHTOKEN empty |
ngrok container fails with instructions |
ngrok exposes a local web inspector at http://localhost:4040 where you can see
all tunneled requests, replay them, and inspect headers/bodies.
- Waits for the app health check to pass
- Requires
NGROK_AUTHTOKEN; warns for each missing Appmax credential (APPMAX_CLIENT_ID,APPMAX_CLIENT_SECRET,APPMAX_APP_ID_UUID,APPMAX_APP_ID_NUMERIC) - Queries ngrok's local API (
http://127.0.0.1:4040/api/tunnels) to discover the active tunnel URL - Prints the public URLs you use during the first Appmax registration and probes the tunnel paths:
GET /(frontend)GET /healthGET /install/startGET /integrations/appmax/callback/installGET /webhooks/appmax
| Script | Platform | Purpose |
|---|---|---|
install.ps1 |
Windows (PowerShell) | Full setup equivalent of make install |
scripts/rename-module.sh |
Unix | Renames the Go module path across all project files |
See .env.example for all available variables. Key groups:
| Group | Variables | Notes |
|---|---|---|
| App | APP_NAME, APP_ENV, APP_DEBUG, APP_HOST, APP_PORT, APP_URL, APP_KEY |
APP_KEY auto-generated by the full install command (make install / .\install.ps1) |
| ngrok | NGROK_AUTHTOKEN, NGROK_URL |
Required for the first bootstrap and public tunnel |
| Database | DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD |
DB_HOST=postgres inside Docker |
| Redis | REDIS_HOST, REDIS_PORT, REDIS_PASSWORD |
REDIS_HOST=redis inside Docker |
| Appmax URLs | APPMAX_AUTH_URL, APPMAX_API_URL, APPMAX_ADMIN_URL |
Defaults to production; set sandbox URLs for testing |
| Appmax Credentials | APPMAX_CLIENT_ID, APPMAX_CLIENT_SECRET, APPMAX_APP_ID_UUID, APPMAX_APP_ID_NUMERIC |
Leave blank during the first bootstrap; fill only after Appmax emails them |
make logsCommon causes:
- Missing
NGROK_AUTHTOKEN, invalid.env, or a startup error unrelated to the delayed Appmax credentials - Database migration error (check postgres logs)
- Port conflict on 8080
- Verify
NGROK_AUTHTOKENis set in.env - Check ngrok inspector:
http://localhost:4040 - If using a reserved domain (
NGROK_URL), verify it matches your ngrok account - If running the Appmax Endpoints flow in Postman, ensure the
NGROK_URLcollection variable is set to your tunnel URL — see Postman Variables
- Wait for postgres health check to pass (can take 30-50s on first start)
- Inside Docker, the app uses
DB_HOST=postgres(set automatically by docker-compose) - Locally, use
DB_HOST=127.0.0.1
- Check
.air.tomlexcludes — files intmp/,tests/,vendor/are ignored - Ensure the file has a
.goextension - Check
make logsfor build errors