Local development

Run the same tenant flows on your workstation.

The local environment uses PostgreSQL, Eureka service discovery, tenant hostnames, and an optional trusted HTTPS certificate. Use HTTPS when testing browser redirects, tenant isolation, or passkeys.

Profile convention

eureka
Local database settings, local ports, Eureka registration, and load-balanced service WebClients.
local-https
HTTPS overlay for local certificates and direct authorization-server token and issuer URLs.
non-eureka
Direct service URLs for environments such as Kubernetes. Do not combine it with the local Eureka profile.
kubernetes
Kubernetes environment values, normally paired with non-eureka in deployed workloads.
# Local HTTP
SPRING_PROFILES_ACTIVE=eureka ./gradlew bootRun

# Local HTTPS
SPRING_PROFILES_ACTIVE=eureka,local-https ./gradlew bootRun

Service ports and databases

RepositoryPortDatabase
discovery-service8761None
role-rest-service8082role
authentication-rest-service8083authentication
user-rest-service8084user
email-rest-service8085None
account-rest-service8086account2
attempt-rest-service8087attempt
organization-rest-service8088organization
authorization9001authorization + tenant databases
authzmanager9093authzmanager
api-gateway8080None

Authorization also connects to freeauth, business1auth, and business2auth for tenant-specific authorization data.

Start services in dependency order

  1. Start PostgreSQL and confirm every required local database is available.
  2. Start discovery-service and verify the Eureka registry on port 8761.
  3. Start role, authentication, user, account, attempt, organization, and email services.
  4. Confirm the services are registered in Eureka before starting authorization.
  5. Start authorization after its dependencies so tenant and organization seeding can complete.
  6. Start authzmanager and api-gateway, then test the tenant HTTPS URLs.

Eureka uses test:test locally. Verify registrations athttp://localhost:8761/eureka/apps before diagnosing WebClient failures.

Configure tenant hostnames

Add these entries to /etc/hosts:

127.0.0.1 platform.openissuer.test
127.0.0.1 free.openissuer.test business1.openissuer.test business2.openissuer.test
127.0.0.1 platform.admin.openissuer.test free.admin.openissuer.test
127.0.0.1 business1.admin.openissuer.test business2.admin.openissuer.test

Create the local HTTPS certificate

Install and trust the local certificate authority once:

brew install mkcert nss
mkcert -install
mkdir -p ~/openissuer-local-certs

Create the certificate used by the local-https profile:

mkcert \
  -cert-file ~/openissuer-local-certs/openissuer.test.pem \
  -key-file ~/openissuer-local-certs/openissuer.test-key.pem \
  platform.openissuer.test free.openissuer.test \
  business1.openissuer.test business2.openissuer.test \
  platform.admin.openissuer.test free.admin.openissuer.test \
  business1.admin.openissuer.test business2.admin.openissuer.test \
  authorization-server localhost 127.0.0.1

Fully quit and reopen the browser after installing the local CA. Passkeys require a trusted secure context, so tenant passkey testing must use HTTPS.

Run the browser-facing services

# authorization repository
SPRING_PROFILES_ACTIVE=eureka,local-https ./gradlew bootRun

# authzmanager repository
SPRING_PROFILES_ACTIVE=eureka,local-https ./gradlew bootRun

# api-gateway repository
SPRING_PROFILES_ACTIVE=eureka,local-https ./gradlew bootRun

Common local URLs:

https://free.openissuer.test:9001
https://business1.openissuer.test:9001
https://free.admin.openissuer.test:9093
https://business1.admin.openissuer.test:9093

Database and Flyway behavior

Each service applies its Flyway migrations when it starts. Never edit an already-applied migration in a persistent environment. Add a new migration for an incremental schema change.

A checksum mismatch after an intentional migration squash requires a clean local database. Drop and recreate only the affected local application database, then restart the service so Flyway can rebuild it. Do not use Flyway repair merely to hide an unexpected checksum change.

Run tests and diagnose startup failures

./gradlew test

# Faster compile and test-source verification
./gradlew testClasses
Unresolved server port
Activate eureka so the local port variables are loaded.
Eureka returns 401
Confirm the local registry credentials are test:test and the registry is running.
Service name cannot resolve
Confirm both services use eureka and the target appears in the registry.
TLS required on this port
Use local-https consistently for services calling the HTTPS authorization server.
Port already in use
Stop the existing process or verify that another copy of the service is not already running.