Local Development
Overview
This guide sets up a local development environment for iterating on backend and frontend code against deployed AWS infrastructure. By the end, the FastAPI backend is running on localhost:8000 with hot-reload, the React frontend is running on localhost:8080 with API requests proxied to the backend, and environment variables are configured to reach deployed Cognito, DynamoDB, and SQS resources.
When to Use This Guide
Use this guide when:
- A successful
/ipa.deployhas completed and it is time to start writing application code - A new developer is onboarding and needs a working local environment
- Switching between deployed environments (for example, from
devtostage) and the local environment variables need updating - Troubleshooting backend or frontend code against live AWS infrastructure without redeploying
Before You Start
Before starting, confirm the following:
.envfile exists withAPP_NAMESPACE,APP_ENV,AWS_REGION, andAWS_ACCOUNT_IDset- At least one environment has been deployed with
/ipa.deploy(the backend stack provides DynamoDB tables the local server connects to) - Python 3.12 is installed
- uv is installed (Python package manager)
- Node.js 22+ and npm are installed
- AWS CLI is configured with credentials for the target account (via
AWS_PROFILEor the default credential chain)
Before / Target State
| Before | After |
|---|---|
| Deployed AWS infrastructure (DynamoDB, Cognito, SQS). No local servers running. Code changes require redeployment to test. | FastAPI backend on localhost:8000 with auto-reload. React frontend on localhost:8080 with Vite proxy forwarding API requests. Code changes are reflected immediately without redeployment. |
Steps
1. Sync environment variables from deployed stacks
To populate .env with the latest outputs from deployed CloudFormation stacks (Cognito, ECR, SQS), run from the project root:
make -f scripts/env.mk update-env
The command queries each deployed stack and writes the output values to .env. The terminal displays confirmation messages for each stack:
Writing OIDC configuration to .env...
Writing ECR configuration to .env...
Writing SQS configuration to .env...
To sync a single stack, use the specific target:
make -f scripts/env.mk update-env-cognito
make -f scripts/env.mk update-env-ecr
make -f scripts/env.mk update-env-sqs
The scripts/env.mk file is generated by /ipa.compose. If the file does not exist, run /ipa.compose first.
2. Start the backend
To install Python dependencies, run from the project root:
cd app-lib && make sync
This runs uv sync --all-extras, installing all backend dependencies including FastAPI, uvicorn, PynamoDB, and boto3 into the local .venv.
To start the FastAPI development server with auto-reload, run from the project root:
make dev-backend
The backend starts on http://localhost:8000. The terminal displays:
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process
To verify the backend is running, open a new terminal and run:
curl http://localhost:8000/health
Expected output:
{"status":"ok"}
The interactive API documentation is available at http://localhost:8000/docs.
3. Start the frontend
To install Node.js dependencies, run from the project root:
cd web-client && npm install
The postinstall script automatically copies the OIDC service worker to public/.
To start the Vite development server, run from the project root:
make dev-frontend
The frontend starts on http://localhost:8080. Vite is preconfigured to proxy /api, /health, and /version requests to the backend at http://localhost:8000. No additional proxy configuration is required.
Open http://localhost:8080 in a browser. The React application loads and API requests are forwarded to the local backend automatically.
4. Optional: Configure Cognito authentication locally
By default, authentication is enabled (AUTH_ENABLED=true). For local development without a deployed Cognito stack, disable it by setting the environment variable before starting the backend:
export AUTH_ENABLED=false
To test with Cognito authentication enabled locally:
a. Confirm the OIDC values are present in .env by running the sync from Step 1, or verify that OIDC_ISSUER and OIDC_CLIENT_ID are set.
b. Create web-client/public/config.local.js to override the frontend OIDC configuration:
window.__CONFIG__ = {
...window.__CONFIG__,
OIDC_AUTHORITY: "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXX",
OIDC_CLIENT_ID: "your-cognito-client-id",
OIDC_REDIRECT_URI: "http://localhost:8080/authentication/callback",
OIDC_END_SESSION_ENDPOINT: "https://your-domain.auth.us-east-1.amazoncognito.com/logout",
};
Replace the placeholder values with the actual OIDC values from .env. The config.local.js file is gitignored and loaded only on localhost.
The Cognito User Pool must include http://localhost:8080/authentication/callback in its allowed callback URLs. If the callback URL is missing, add it to the Cognito stack parameters and redeploy with /ipa.deploy.
d. Restart both the backend and frontend for the changes to take effect.
Verification
To confirm the local environment is fully operational:
-
Verify the backend health endpoint:
curl http://localhost:8000/healthExpected:
{"status":"ok"} -
Verify the backend version endpoint:
curl http://localhost:8000/versionExpected:
{"version":"1.0.0","build":"dev"} -
Open
http://localhost:8080in a browser and confirm the React application loads. -
Confirm a round-trip API call by navigating to a data page (for example, the Passengers page) and verifying that data loads from the deployed DynamoDB table through the local backend.
Troubleshooting
| Problem | Likely Cause | Fix |
|---|---|---|
curl: (7) Failed to connect to localhost port 8000 | Backend is not running or failed to start | Check the terminal for startup errors. Confirm Python 3.12 and uv are installed. Run cd app-lib && make sync to reinstall dependencies. |
DynamoDB AccessDeniedException in backend logs | AWS credentials are missing or the region does not match the deployed stacks | Confirm AWS_REGION in .env matches the deployment region. Verify AWS CLI credentials with aws sts get-caller-identity. |
| CORS errors in the browser console | Frontend is not using the Vite proxy (requests going directly to the backend) | Confirm API_BASE_URL is empty in web-client/public/config.js. The Vite proxy handles routing when API_BASE_URL is not set. |
| Cognito redirects to an error page after login | localhost:8080 is not in the allowed callback URLs for the Cognito User Pool | Add http://localhost:8080/authentication/callback to the Cognito stack's CallbackURLs parameter and redeploy. |
| Port 8000 or 8080 already in use | Another process is listening on the required port | Identify the process with lsof -i :8000 or lsof -i :8080 and stop it before starting the development servers. |
Next Steps
- Notebook Development — Prototype and test with Jupyter notebooks connected to deployed resources
- Regenerate API client — With the backend running, run
cd web-client && npm run codegento update the TypeScript API client from the OpenAPI schema - Backend developer docs — See the
app-lib/CLAUDE.md for backend architecture, feature structure, and testing conventions - Frontend developer docs — See the
web-client/CLAUDE.md for frontend architecture, component placement, and API layer conventions - Tear down the deployment — Run
/ipa.destroyto remove deployed infrastructure when no longer needed