Skip to main content

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:

PortComponent
8000Browser/API proxy
8443Terminal mTLS proxy
5173Retail portal
5174Support portal
8081merchant-api direct health/debug port
8082management-api direct health/debug port
8088auth direct health/debug port
9099Firebase 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

  1. Run up, then smoke all.
  2. Run ports and open the printed retail or support URL.
  3. Sign in with the printed local credential.
  4. Exercise the changed user flow against seeded data and local provider stubs.
  5. Rerun the narrow smoke scope that covers the flow.
  6. Capture the command, result, and relevant .dev-logs path 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.