---
title: "Local Environment Setup"
slug: onboarding-local-environment
section: Developer Onboarding
status: stable
description: "Getting the Alliance portal stack running on your own machine, so you can develop and debug against a real, logged-in session instead of guessing from code alone."
last-updated: 2026-10-07
---

# Local Environment Setup

Getting the Alliance portal stack running on your own machine, so you can develop and debug against a real, logged-in session instead of guessing from code alone.

## Overview

Most day-to-day work touches more than one service at once — a portal frontend, its BFF, Keycloak for auth, and the underlying Globus API. The local stack wires all of it together so a login actually works end-to-end on your machine, not just in a deployed environment.

> **This page is an orientation, not a command reference.** Exact commands, ports, and known breakages drift as the stack evolves — the authoritative, kept-current source is the platform engineering team's local-stack runbook. Ask your buddy or platform engineer for the current version if anything below is stale.

## Prerequisites

- **Node** — Node 20: PPPToo declares `engines` `>=20 <21`, and the BackOfficePrototype and itrequestportal Docker images and the main CI workflows use Node 20, so a newer LTS is not guaranteed to work (the PPPToo server image itself builds on Node 22). Python is not part of the toolchain for any Alliance repo.
- **A browser you can automate** — headless browser automation in PPPToo's `e2e/` workspace goes through `puppeteer`, pointed at your existing Chrome via `E2E_CHROME_PATH` or `PUPPETEER_EXECUTABLE_PATH`; without either it uses puppeteer's own browser download.
- **Docker** (or native installs) for Keycloak and Redis, if you're not pointing at shared dev instances of those.
- **1Password CLI/desktop access** — local dev credentials for Keycloak realms and API keys live in the Globus Dev vault (see the Access & Accounts Checklist page).

## The Stack

A full local run typically brings up:

| Component | Role |
| --- | --- |
| BackOfficePrototype (BOP) | The Globus staff-facing back office — applicants, applications, program configuration. |
| PPPToo (Participant Portal v2) | The applicant-facing portal, plus its NestJS BFF layer that proxies to Globus. |
| HostPortalPrototype | The host-organization-facing portal. |
| Keycloak | Identity provider for the `applicant-portal` realm — every portal login flows through it. |
| Redis | Not part of the current stack: the PPPToo BFF is stateless (Bearer tokens, no server-side session) and BackOfficePrototype's server has no Redis dependency. |

## Boot Order

Auth has to exist before anything can log in, and the API has to exist before a BFF can proxy to it. As a rule of thumb: bring up Keycloak and Redis first, then the API-owning service (BOP), then the portal(s) and their BFFs last.

## Verifying It Worked

Don't consider the stack "up" until you've done a real login, not just confirmed the process is listening:

1. Hit each service's health endpoint.
2. Log in through the portal UI (or via a direct BFF login call) with a dedicated test identity — never a real person's credentials.
3. Confirm the session survives a page reload (this is what actually proves Keycloak + BFF are wired correctly together, not just individually up; the portal keeps its tokens client-side in `sessionStorage`, so there is no server-side session).

## Common Gotchas

- **Windows optional-deps gap:** installing `globus-sdk-src` on Windows can fail on optional native deps. Install with scripts skipped (`--ignore-scripts` on your package manager) rather than fighting the native build.
- **BackOffice client build variables:** `VITE_PUBLIC_ENV` is baked into the bundle at build time and decides PostHog masking. `development` (or an unset value under `vite dev`) turns PII masking off, so replays and captures show real text and inputs; any other value, or an unset value in a built bundle, masks all text and inputs. PostHog itself stays off unless `VITE_POSTHOG_KEY` is set (`VITE_POSTHOG_HOST` defaults to `https://us.i.posthog.com`). `VITE_APPLICANT_PORTAL_BASE_URL` is read in `client/src/lib/constants.ts` (default `https://applicant-portal.replit.app`), but no other file in `client/src` imports that constant.
- **CSRF tokens for local API testing:** the PPPToo BFF is Bearer-token only and has no CSRF layer. BackOfficePrototype's cookie-session routes do: echo the session's CSRF token in the `X-CSRF-Token` header on mutating calls, because a bare `curl`/Postman POST with only a session cookie will 403.
- **DB seed state flip-flops:** a clean local DB boot doesn't always land on the same seed data twice in a row. If a test that worked yesterday now fails on missing data, check whether the seed step actually ran before assuming your code regressed.
- **Address autocomplete needs a Maps key:** the BackOffice address field (organisation, partner detail, housing and activity-site forms) reads `VITE_GOOGLE_MAPS_API_KEY` at build time and loads the Google Maps Places script with it. With the variable unset no script loads and no suggestions appear, so the field behaves as a plain text input.
- **Never reset your own or a colleague's real portal password to test locally.** Use one of the dedicated E2E bot accounts (see the Security & Secrets Handling page) — they exist exactly so nobody's real login has to be touched.
