The server

The Spring Boot 4 service behind Switchyard: the admin API the dashboard uses, and the SDK API client libraries use. How to run and configure it is in the main README; the full API is in PLAN.md.

Code layout

Package What
project Projects and their environments, SDK key rotation
flag Flags (boolean or multivariate), on/off per environment, targeting (Targeting) and the checks that need the flag's project (TargetingValidator)
segment Segments: reusable groups of contexts that flag rules target
browser /client/v1: browser flags' values for a public client-side ID, evaluated with the Java client
sdk /sdk/v1/flags and /sdk/v1/stream: the in-memory SDK cache (SdkService), its database reads (SdkStore), the SSE streams (StreamHub) and the change events that drive them
audit The append-only change history
auth The filter that checks admin tokens, sign-in sessions and SDK keys; GitHub sign-in (SignInController, GitHubClient, Accounts); roles (AccessGuard, called by every service before it changes anything) and members; /api/me; secret hashing
common Errors as RFC 9457 problem details, CORS for the dashboard, shared constants

Database migrations are in src/main/resources/db/migration (Flyway): V1__init.sql for the schema, V2__targeting.sql for rules and rollouts, V3__accounts.sql for GitHub sign-in and undo, V4__flag_model.sql for variations, prerequisites and segments, V5__client_side.sql for client-side IDs, V6__roles.sql for roles and protected environments.

Building the container image

Dockerfile builds the GraalVM native image and puts it on a slim Debian base. Build from the repository root, since it needs the Java client too: docker build -f server/Dockerfile -t switchyard-server .. CI publishes it to GitHub Container Registry on every push to main; docs/DEPLOY.md runs it on Render.

How a change reaches apps

  1. An admin request changes a flag. In the same transaction, the environment's version goes up by one and the change is written to the audit log.
  2. After the transaction commits, SdkService updates its cached version for the environment, then StreamHub sends event: version to that environment's open streams.
  3. Clients fetch /sdk/v1/flags with their last ETag. The payload comes from memory: the database isn't touched on the SDK path except to fill the cache.

Everything after the commit happens inside this process, which assumes a single server instance. See the design decisions in PLAN.md.

Tests

bash
./mvnw -f ../clients/java/pom.xml install -DskipTests   # the contract tests use the real Java client
./mvnw verify

Integration tests run Postgres 17 in Docker (Testcontainers) and are skipped when Docker isn't running. GitHubSignInTests stands up a fake GitHub with the JDK's HTTP server. StreamLoadTests (1,000 clients) only runs on request:

bash
./mvnw verify -Dtest=StreamLoadTests -Dswitchyard.load=true

On Windows, stop any running copy of the server first: it locks target/*.jar, and packaging fails after the tests pass.