Skip to content

Local Development Setup

This guide covers running the full Cargo stack on your machine: the api backend, the app client, and the backoffice admin console, backed by MongoDB.

Repo Layout

Directory What it is Stack
api/ Backend service Spring Boot (WebFlux, GraphQL, reactive MongoDB)
app/ Client-facing web app (shippers and capacity providers) Angular
backoffice/ Admin console Angular
nginx/ Reverse proxy config used in deployment -- not needed for local dev
docs/ This documentation site mkdocs (git submodule, see Repo Setup)

app and backoffice are separate Angular projects that both talk to the same api instance over GraphQL.

Prerequisites

  • JDK 25. api/build.gradle pins the Gradle toolchain to Java 25; if you don't have a matching JDK installed, the Gradle toolchain will download one automatically on first build.
  • Node.js and npm (app and backoffice pin packageManager: npm@11.16.0 in package.json).
  • Docker, running. The backend starts a local MongoDB container for you through Spring Boot's Docker Compose support, so you don't need to run docker compose by hand.
  • Git, with the shared hooks configured. See Repo Setup for the one-time core.hooksPath step that keeps the cargo-docs submodule in sync.

Backend (api)

1. Configure environment variables

Copy the example env file and fill it in:

cd api
cp .env.example .env

.env is gitignored and loaded automatically on startup (ApiApplication loads it before Spring Boot starts). It is read regardless of which Spring profile is active.

Variable Purpose
MONGODB_URI Connection string for MongoDB. The value in .env.example already matches the credentials in compose.yaml (root / secret, database mydatabase), so it works out of the box with the Docker-managed MongoDB.
CORS_ALLOWED_ORIGINS Origins allowed to call the API. Defaults to http://localhost:4200,http://localhost:4201, which already covers backoffice and app.
JWT_SECRET Signs the app's own JWTs (HS256). Must be at least 32 bytes, or the API fails to start with cargo.jwt.secret must be at least 256 bits (32 bytes) for HS256. Generate one with openssl rand -base64 32.
JWT_EXPIRATION_MINUTES Token lifetime, defaults to 1440 (24 hours).
GOOGLE_CLIENT_ID OAuth client ID used to verify Google sign-in tokens. Only needed if you're testing the "Sign in with Google" flow; it must match the client ID baked into app/backoffice's environment.development.ts. Email/password login works without it.
ADMIN_BOOTSTRAP_EMAIL / ADMIN_BOOTSTRAP_PASSWORD / ADMIN_BOOTSTRAP_NAME On first startup, if ADMIN_BOOTSTRAP_EMAIL is set and no admin user exists yet, the API seeds one admin user with these credentials (AuthProvider.PASSWORD). Leave ADMIN_BOOTSTRAP_EMAIL blank to skip seeding.
MEDIA_STORAGE_TYPE / MEDIA_STORAGE_DIR Where uploaded media is stored locally. Defaults to local storage under ./data/media.

2. Run the API with the local profile

The local Spring profile (application-local.yaml) is what turns on Docker Compose support, so make sure it's active:

./gradlew bootRun --args='--spring.profiles.active=local'

or export SPRING_PROFILES_ACTIVE=local before running. On startup, Spring Boot reads compose.yaml and starts the mongodb container for you if it isn't already running.

The API listens on http://localhost:8080. A few useful endpoints:

  • GraphQL: http://localhost:8080/graphql
  • GraphiQL (interactive explorer): http://localhost:8080/graphiql

3. Log in as the bootstrap admin

If you set ADMIN_BOOTSTRAP_EMAIL/ADMIN_BOOTSTRAP_PASSWORD, you can authenticate with the login mutation:

mutation {
  login(email: "you@example.com", password: "your-password") {
    token
  }
}

Run it from GraphiQL, or send it as a normal GraphQL POST request. Use the returned token as a bearer token for subsequent requests.

Frontend apps

Both Angular apps expect the API at http://localhost:8080 in development (see src/environments/environment.development.ts in each project), which matches the default api setup above.

Client app (app)

cd app
npm install
npm start

Serves at http://localhost:4201.

Backoffice (backoffice)

cd backoffice
npm install
npm start

Serves at http://localhost:4200.

Putting it together

For a full local environment, run these three in separate terminals:

Service Command URL
API cd api && ./gradlew bootRun --args='--spring.profiles.active=local' http://localhost:8080
Backoffice cd backoffice && npm start http://localhost:4200
App cd app && npm start http://localhost:4201

MongoDB is started automatically by the API through Docker Compose; you don't need to run it separately.

Troubleshooting

  • API fails to start with a JWT secret error. JWT_SECRET in .env is missing or shorter than 32 bytes. Generate a new one with openssl rand -base64 32.
  • API can't connect to MongoDB. Make sure Docker is running before you start the API, and that MONGODB_URI in .env still matches the credentials in compose.yaml.
  • Frontend requests are blocked by CORS. Check that the origin you're serving from is listed in CORS_ALLOWED_ORIGINS. The default already covers ports 4200 and 4201.
  • Port already in use. 8080 (api), 4200 (backoffice), 4201 (app), and 27017 (MongoDB) all need to be free.