Local development and manual QA
scripts/local-validation.sh is the supported lifecycle for the integrated local environment. It coordinates the current microservices, Spanner and Firebase Auth emulators, local provider/capture stubs, API proxies, seeded data, and retail/support portal dev servers. Use scripts/test-local.sh for automated test batteries instead of treating the stack helper as a test runner.
Everything on this page is local. It does not deploy, migrate staging, or connect a browser to production.
Check the workstation
From the repository root, run:
./scripts/local-validation.sh doctor
The doctor checks Bash, Bazel, curl, Docker, Firebase CLI, OpenSSL, pnpm, psql, Python 3, a reachable Docker daemon, the token harness, and Gateway Maven credentials. The stack also requires Docker Compose V2. If Gateway artifacts return an authentication error, refresh Google Cloud authentication and source the repository helper:
source scripts/gateway-maven-credentials.sh
./scripts/local-validation.sh doctor
Do not create or commit an .env file just to satisfy the doctor. Use the credential helper and the generated local-validation environment.
Start and smoke the stack
For normal development:
./scripts/local-validation.sh up
./scripts/local-validation.sh smoke all
./scripts/local-validation.sh ports
up is incremental. It builds service images through Bazel, loads changed images, recreates unhealthy or changed containers, starts provider stubs and proxies, seeds the local emulators, and starts the portal servers. Plain up publishes browser-facing endpoints on reachable host interfaces so a LAN or tailnet browser can use the printed URL.
Use loopback-only Firebase Auth only for a deterministic CI or PR proof path:
./scripts/local-validation.sh up --localhost
Use a cold rebuild only when incremental reconciliation is not sufficient:
./scripts/local-validation.sh up --cold
--cold stops services, removes local containers, rebuilds/loads images, and recreates the stack. It is not a Cloud Spanner reset.
One-command local validation
On a Linux development host, the full path is:
./scripts/local-validation.sh full
It runs the automated local checks, boots the high-fidelity stack, runs deep smoke, writes JSON/Markdown reports under .dev-logs/full-local-validation/<run-id>/, prints the ports, and leaves the stack running for manual QA. Useful non-default controls are:
./scripts/local-validation.sh full --dry-run
./scripts/local-validation.sh full --plain --json
./scripts/local-validation.sh full --down-after
--dry-run prints the step graph without executing it. --down-after stops the local stack after the report is written.
Endpoints and credentials
Always run ./scripts/local-validation.sh ports after startup. It prints the current URLs and seeded login instead of relying on copied credentials. The stable user-facing ports are:
| Port | Component |
|---|---|
8000 | Browser/API proxy |
8443 | Terminal mTLS proxy |
5173 | Retail portal |
5174 | Support portal |
8081 | merchant-api direct health/debug port |
8082 | management-api direct health/debug port |
8088 | auth direct health/debug port |
9099 | Firebase Auth emulator |
Prefer the API proxy on port 8000 for browser-visible application paths. Direct service ports are for focused health checks and debugging; they do not reproduce edge routing.
Manual QA path
- Run
up, thensmoke all. - Run
portsand open the printed retail or support URL. - Sign in with the printed local credential.
- Exercise the changed user flow against seeded data and local provider stubs.
- Rerun the narrow smoke scope that covers the flow.
- Capture the command, result, and relevant
.dev-logspath in the PR evidence.
Available smoke scopes are discoverable with ./scripts/local-validation.sh --help. Common focused reruns are:
./scripts/local-validation.sh smoke auth
./scripts/local-validation.sh smoke purchasing
./scripts/local-validation.sh smoke app-stubs
./scripts/local-validation.sh smoke money-path
./scripts/local-validation.sh smoke browser
./scripts/local-validation.sh smoke terminal-lifecycle
./scripts/local-validation.sh smoke deep
smoke all covers authentication, strict local guardrails, feature resolution, purchasing, local provider adapters, the money path, and focused browser flows. smoke deep adds the deeper runtime checks used by full.
Rebuild, restart, and inspect
Keep a healthy environment running and update only the changed component:
./scripts/local-validation.sh rebuild merchant-api
./scripts/local-validation.sh restart retail
./scripts/local-validation.sh restart support
./scripts/local-validation.sh logs merchant-api
./scripts/local-validation.sh logs retail
./scripts/local-validation.sh status
Use rebuild <service> for a microservice image change. Use restart retail or restart support after portal environment/configuration changes. Log component names include services plus retail, support, qa-api-proxy, qa-terminal-mtls-proxy, and the local provider/capture components.
Devices and simulators
Plain up is LAN/tailnet reachable by default. Re-resolve and probe an already-running environment with:
./scripts/local-validation.sh expose lan
Print the exact endpoint variables and a fresh onboarding token for an app lane with:
./scripts/local-validation.sh mobile android
./scripts/local-validation.sh mobile ios
./scripts/local-validation.sh mobile peak-mobile-android
./scripts/local-validation.sh mobile peak-mobile-ios
Append activate to print that lane's build-and-activate command; the helper does not build the app. Android emulators use host alias 10.0.2.2; iOS simulators use 127.0.0.1; physical devices use the host LAN IP or tailnet name printed by ports. A Linux run cannot stand in for Mac/Xcode or unavailable physical-device evidence.
Seed and reset local state
Rerun the deterministic local seed without stopping the stack:
./scripts/local-validation.sh seed
./scripts/local-validation.sh verify-seed
To stop the stack:
./scripts/local-validation.sh down
To stop it and delete generated state under .dev-logs/local-validation:
./scripts/local-validation.sh reset
reset is scoped to the local validation environment. Run up afterward to recreate runtime state. Do not use Cloud Spanner drop/reinstall scripts for local cleanup; those accept arbitrary project/instance/database identifiers and belong to the explicitly authorized procedure in Database reset and reinstall.
Automated tests
After the manual flow works, run the focused Bazel targets or the appropriate scripts/test-local.sh battery described in Testing strategy. A green browser smoke does not replace unit, contract, or compilation evidence, and a green Bazel test does not replace a user-visible smoke for UI behavior.