Skip to main content

Local Development

Hephaestus supports full-stack development across Java and TypeScript. This guide focuses on the development environment; production operations are covered in the Admin Guide.

Prerequisites

Install and configure the following tools before you attempt a local build:

  1. Java JDK 21 – Required for the Spring Boot application server.
  2. Docker Desktop – Used for PostgreSQL, Keycloak, and NATS containers.
  3. Node.js LTS (>= 22.10) and npm (>= 10.8) – For the React client and TypeScript services.
  4. NATS CLI (optional) – Helpful when debugging webhook messages.

Open the repository using the project.code-workspace file in VS Code and install the workspace recommendations (@recommended in the Extensions view). Key extensions include:

  • Java Extension Pack
  • Spring Boot tools
  • Node.js + TypeScript tooling
  • ESLint + Prettier
  • Tailwind CSS IntelliSense

JetBrains alternatives such as IntelliJ (Java) and WebStorm (React/TypeScript) work equally well.

Application server

Maven profiles and local configuration

We ship three Maven profiles: local (default), prod, and spec. For development stick to the local profile.

Create application-server/src/main/resources/application-local.yml to override defaults. This file is gitignored.

Keep it local

Never commit application-local.yml. It may contain secrets and machine-specific configuration.

Running the server

  1. Start Docker Desktop.

  2. From server/application-server, run:

    ./mvnw spring-boot:run
  3. Access the API at http://localhost:8080 or explore http://localhost:8080/swagger-ui/index.html.

Port overrides

Every host-side port is configurable so multiple Hephaestus instances (or other services) can coexist on the same machine. Container-internal ports never change — only the localhost binding moves.

Default port map

ServiceDefaultVariableConfig location
PostgreSQL5432POSTGRES_PORTserver/application-server/.env
Keycloak8081KEYCLOAK_PORTserver/application-server/.env
Application server8080SERVER_PORTserver/application-server/.env
Intelligence service8000INTELLIGENCE_SERVICE_PORTserver/application-server/.env
Webapp (Vite dev)4200WEBAPP_PORTShell env or webapp/.env
Pre-flight check

Run npm run check:ports before starting the stack to verify all ports are free.

How it works

The .env file in server/application-server/ is read by both Docker Compose (for container port mappings) and Spring Boot (via spring.config.import). This means a single file controls the entire local stack.

Ports flow through the system like this:

.env (POSTGRES_PORT=15432)
├─► Docker Compose → '15432:5432' host mapping
└─► Spring Boot → jdbc:postgresql://localhost:15432/hephaestus

Changing ports

Basic example — move PostgreSQL and Keycloak to non-standard ports:

# server/application-server/.env
POSTGRES_PORT=15432
KEYCLOAK_PORT=18081

That's it for these two. The application server automatically picks up the new ports from the same .env file.

Changing the application server port:

# server/application-server/.env
SERVER_PORT=18080

If the webapp also needs to reach the server at the new port, set the server URL in the webapp environment:

# webapp/.env (or shell)
VITE_APPLICATION_SERVER_URL=http://localhost:18080

Changing the webapp port:

The Vite dev server reads WEBAPP_PORT from the shell environment (not from server/application-server/.env):

WEBAPP_PORT=5200 npm -w webapp run dev

When changing the webapp port, the server's CORS origin must also be updated so API calls are not rejected:

# server/application-server/.env
APPLICATION_HOST_URL=http://localhost:5200

Changing the intelligence service port:

INTELLIGENCE_SERVICE_PORT in server/application-server/.env tells the application server where to find the intelligence service. You must also set PORT in the intelligence service's own .env:

# server/application-server/.env
INTELLIGENCE_SERVICE_PORT=18000

# server/intelligence-service/.env
PORT=18000

Cascading effects reference

Changing a port in one place may require updates elsewhere. This table shows the full picture:

When you change...Also update...Why
KEYCLOAK_PORTGitHub OAuth callback URLKeycloak's broker endpoint moves
WEBAPP_PORTAPPLICATION_HOST_URL in .envCORS origin must match
SERVER_PORTWebapp's APPLICATION_SERVER_URL (if connecting directly)API base URL changes
INTELLIGENCE_SERVICE_PORTPORT in server/intelligence-service/.envService must listen on same port
POSTGRES_PORTNothing (automatic)Both Compose and Spring read from .env

Update the GitHub OAuth callback URL when changing KEYCLOAK_PORT:

http://localhost:<KEYCLOAK_PORT>/realms/hephaestus/broker/github/endpoint
Webapp defaults

The webapp has hardcoded dev defaults in webapp/src/environment/index.ts for APPLICATION_SERVER_URL (http://localhost:8080) and KEYCLOAK_URL (http://localhost:8081). In production these are injected via window.__ENV__. For local development with non-standard ports, set these as Vite environment variables or update the defaults.

GitHub configuration

Hephaestus supports two GitHub authentication modes. Pick the one that fits your workflow:

ModeBest forWorkspace creationRepository monitors
PATQuick local developmentManual (from config)Manual (you list them)
GitHub AppTesting webhooks, productionAutomatic (from installations)Automatic (from installation events)

Option A: Personal Access Token (simpler)

  1. Create a Personal Access Token with scopes: repo, read:org, read:user.

  2. Create application-local.yml:

    hephaestus:
    workspace:
    init-default: true
    default:
    login: your-github-org # e.g., "ls1intum" or "HephaestusTest"
    token: ghp_your_token
    repositories-to-monitor:
    - your-github-org/repo1
    - your-github-org/repo2
  3. Leave github.app.id unset or set to 0.

Option B: GitHub App

  1. Create a GitHub App with appropriate permissions.

  2. Create application-local.yml:

    github:
    app:
    id: 12345
    privateKey: |
    -----BEGIN RSA PRIVATE KEY-----
    ...
    -----END RSA PRIVATE KEY-----

    hephaestus:
    workspace:
    init-default: false # Workspaces created from installations
  3. Install the app on your organization. Workspaces and monitors are created automatically.

Limiting sync scope (development filters)

When using GitHub App mode, your app might have access to hundreds of repositories. Use filters to focus on specific orgs/repos during development:

monitoring:
filters:
allowed-organizations:
- ls1intum
- HephaestusTest
allowed-repositories:
- ls1intum/Hephaestus
- ls1intum/Artemis
- HephaestusTest/demo-repository

Empty lists = no filtering (production behavior). Non-empty = only sync matching items.

tip

Filters don't delete data—they just skip sync operations. Workspace and organization metadata is still created for all installations.

Keycloak integration

Keycloak runs in Docker as part of the development compose stack. The bundled realm import no longer ships test users—authentication always flows through GitHub and mirrors production.

Configure the GitHub identity provider

  1. Create a new GitHub OAuth application with the callback URL http://localhost:8081/realms/hephaestus/broker/github/endpoint.

  2. Export the generated Client ID and Client secret, then copy server/application-server/.env.example to server/application-server/.env and update the placeholders:

    cp server/application-server/.env.example server/application-server/.env
    # Edit .env and set:
    # KEYCLOAK_GITHUB_CLIENT_ID=<github-client-id>
    # KEYCLOAK_GITHUB_CLIENT_SECRET=<github-client-secret>
    # KEYCLOAK_GITHUB_ADMIN_USERNAME=<github-handle-with-admin-access>

    The Keycloak container resolves these placeholders during realm import, as documented in the Keycloak import guide.

    Pre-configured client secret

    The KEYCLOAK_CLIENT_SECRET is pre-configured with a development default (hephaestus-dev-secret). You do not need to copy a secret from the Keycloak admin console for local development.

  3. Run the application server with ./mvnw spring-boot:run. Docker containers (Keycloak, PostgreSQL) start automatically via Spring Boot's Docker Compose support.

  4. Sign in via GitHub using the account referenced by KEYCLOAK_GITHUB_ADMIN_USERNAME. During the first brokered login Keycloak automatically grants that account the admin realm role and the realm-managementrealm-admin client role, unlocking the administrative views in the application server and Keycloak console.

Troubleshooting Keycloak

If you encounter 401 Unauthorized errors or authentication issues after changing configuration:

cd server/application-server
docker compose down -v # Clear Keycloak data volume
docker compose up # Re-import realm with fresh settings

This deletes the Keycloak H2 database and forces a fresh realm import with your current .env values.

Webhook ingest service

When you run docker/compose.core.yaml or start the webhook ingest service locally, set the webhook secrets up front so signature checks succeed:

cp docker/.env.example docker/.env
export WEBHOOK_SECRET=$(openssl rand -hex 32)
echo "WEBHOOK_SECRET=$WEBHOOK_SECRET" >> docker/.env

The value must match the secret configured on your GitHub and GitLab webhooks (validated via X-Hub-Signature-256 when available).

To run the webhook ingest service locally:

cd server/webhook-ingest
cp .env.example .env
npm install
npm run dev

Web client (webapp)

  1. Install dependencies:

    npm install
  2. Start Vite (defaults to port 4200):

    npm -w webapp run dev
  3. Visit http://localhost:4200 (or your custom WEBAPP_PORT).

UI foundations

  • We ship Tailwind CSS 4 in JIT mode. Keep utility classes in JSX and rely on design tokens defined in src/styles.css.
  • Ensure Tailwind IntelliSense is enabled in your IDE—typeahead prevents typos and invalid compositions.
  • Avoid premature abstractions with @apply; duplication is fine when it keeps components readable.

Component workflow (Storybook + Chromatic)

Storybook is the source of truth for presentational components.

npm -w webapp run storybook           # Local playground on http://localhost:6006
npm -w webapp run build-storybook # Static bundle for Chromatic
npm -w webapp run chromatic:ci # Visual regression in CI
  • Every new UI component ships with at least one story covering empty, loading, and error states.
  • Chromatic runs on every pull request—review visual diffs before merging.
  • Reference ui.shadcn.com for composition patterns; stick to headless Radix primitives when you need new widgets.

OpenAPI client

The generated client in src/api is the only way the webapp talks to server services.

npm -w webapp run openapi-ts
  • Generated types drop the Dto suffix and mirror the Spring Boot API responses.
  • Pair every new endpoint with a typed TanStack Query hook for caching and invalidation.
  • Never hand-roll fetch calls—shared interceptors handle auth tokens and error telemetry.

Intelligence service (server/intelligence-service)

The intelligence service is a Node.js/TypeScript application using Hono and AI SDK v6. For detailed documentation including AI observability setup with Langfuse, see the dedicated Intelligence Service guide.

Quick start:

  1. Install dependencies:

    cd server/intelligence-service
    npm install
  2. Configure environment:

    cp .env.example .env
    # Edit .env with your DATABASE_URL and LLM provider credentials
  3. Start the development server:

    npm run dev

    The service is available at http://localhost:8000 with interactive docs at /docs.