Development Guide

1. Angular Developer Quick Start

For Angular/frontend developers who just need to run the backend services, use Docker to start everything with a single command.

1.1. Prerequisites

1.2. Quick Start

# 1. Install npm dependencies
npm install

# 2. Start all backend services (MySQL, Admin Service, Gateway)
npm run docker:backend:up

# 3. Start Angular dev server with hot reload
npm start

Access the application at http://localhost:9001

The backend Gateway API is available at http://localhost:12505

1.3. What Gets Started

The docker:backend:up command starts three services:

Service Port Description

MySQL

3306

Database for both services

Admin Service

12504

Core business logic and APIs

Gateway (BFF)

12505

Backend-for-Frontend, routes API calls

1.4. Docker Commands Reference

Command Description

npm run docker:backend:up

Start all backend services

npm run docker:backend:down

Stop all backend services

npm run docker:backend:logs

View logs from all services

npm run docker:backend:restart

Restart all backend services

npm run docker:backend:reset

Stop, remove volumes, and restart (fresh database)

1.5. Interactive Setup Script

For guided setup with port conflict detection and troubleshooting:

# Windows (PowerShell)
.\scripts\setup-backend.ps1

# macOS / Linux
./scripts/setup-backend.sh

The script will:

  • Check Docker is installed and running

  • Detect port conflicts

  • Offer to use local MySQL if one is already running

  • Pull latest images and start services

  • Display access URLs when ready

1.6. Using Local MySQL

If you have MySQL running locally and prefer to use it instead of Docker MySQL:

docker compose -f src/main/docker/dev.yml -f src/main/docker/dev-local-mysql.yml up -d --wait

Ensure your local MySQL has the required setup:

CREATE DATABASE IF NOT EXISTS `registration-ui`;
CREATE DATABASE IF NOT EXISTS `admin-service`;
CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
FLUSH PRIVILEGES;

1.7. Troubleshooting

Services won’t start

Check Docker Desktop is running. Run docker info to verify.

Port already in use

Another service is using a required port. Use the interactive setup script for guidance.

Connection refused

Wait for services to be healthy. Check status with docker compose -f src/main/docker/dev.yml ps

Database errors

Reset with npm run docker:backend:reset for a fresh database.

2. Prerequisites

Before building this project, install and configure the following dependencies:

2.1. Node.js and npm

Node.js is used to run a development web server and build the project. Install Node either from source or as a pre-packaged bundle for your system.

Angular CLI with Webpack is used as the build system.

npm manages CSS and JavaScript dependencies. Upgrade dependencies by specifying newer versions in package.json.

npm update
npm install

Run npm run to list all available scripts for this project.

2.2. Java

The backend requires Java Development Kit (JDK) version 11 LTS or later.

2.3. Environment Variables

Configure the following environment variables:

  • JAVA_HOME - Points to your JDK installation

  • MVN_HOME - Points to your Maven installation

Ensure both $JAVA_HOME/bin and $MVN_HOME/bin are in your PATH. Remove any conflicting Java installation directories from the PATH.

3. Installing Dependencies

After installing Node, run the following command to install dependencies and development tools:

npm install

Run this command again when dependencies change in package.json.

3.1. Adding New Dependencies

To add a runtime dependency (example: Leaflet library):

npm install --save --save-exact leaflet

To add TypeScript type definitions from DefinitelyTyped:

npm install --save-dev --save-exact @types/leaflet

Then import the JS and CSS files in your application:

src/main/webapp/app/app.module.ts
import 'leaflet/dist/leaflet.js';
src/main/webapp/content/scss/vendor.scss
@import 'leaflet/dist/leaflet.css';

4. Using Angular CLI

Use Angular CLI to generate custom client code:

ng generate component my-component

This generates:

create src/main/webapp/app/my-component/my-component.component.html
create src/main/webapp/app/my-component/my-component.component.ts
update src/main/webapp/app/app.module.ts

5. PWA Support

This application includes Progressive Web App (PWA) support, disabled by default.

To enable the service worker, uncomment the following in src/main/webapp/app/app.module.ts:

ServiceWorkerModule.register('ngsw-worker.js', { enabled: false }),

6. Building for Production

6.1. Packaging as JAR

Build the optimized production JAR:

./mvnw -Pprod clean verify

This concatenates and minifies client CSS and JavaScript files and updates index.html to reference them.

Run the built application:

java -jar target/*.jar

Navigate to http://localhost:12505 in your browser.

See Using JHipster in production for more details.

6.2. Packaging as WAR

To deploy to an application server:

./mvnw -Pprod,war clean verify

7. Using Docker

Docker configurations are available in src/main/docker to launch required services.

7.1. Full Development Stack

Start all backend services (MySQL, Admin Service, Gateway) using pre-built images from Docker Hub:

npm run docker:backend:up

Or directly with docker compose:

docker compose -f src/main/docker/dev.yml up -d --wait

See Angular Developer Quick Start for more details on the available commands.

7.2. Admin Service Only (Local Gateway Development)

When developing the Java Gateway locally, you can run just the Admin Service and MySQL in Docker while running the Gateway from your IDE:

# Start Admin Service and MySQL only
npm run docker:admin-service:up

# Run Gateway locally (from IDE or command line)
./mvnw

This setup is useful when you need to:

  • Debug the Gateway code in your IDE

  • Make changes to the Gateway without rebuilding Docker images

  • Test Gateway configuration changes quickly

Command Description

npm run docker:admin-service:up

Start Admin Service and MySQL

npm run docker:admin-service:down

Stop Admin Service and MySQL

npm run docker:admin-service:restart

Restart Admin Service and MySQL

npm run docker:admin-service:reset

Reset and restart (fresh database)

The Admin Service API will be available at http://localhost:12504

7.3. Individual Services

Start only the MySQL database:

npm run docker:db:up
# or: docker compose -f src/main/docker/mysql.yml up -d

Stop and remove the container:

npm run docker:db:down
# or: docker compose -f src/main/docker/mysql.yml down

7.4. Dockerizing the Application

Build a Docker image:

npm run java:docker

For ARM64 processors (e.g., Apple M1):

npm run java:docker:arm64

Run the dockerized application:

docker compose -f src/main/docker/app.yml up -d

On macOS Big Sur or later with Docker Desktop, enable "Use the new Virtualization framework" for better processing performance.

See Using Docker and Docker-Compose for more information.

8. JHipster Control Center

Start a local JHipster Control Center (accessible at http://localhost:7419):

docker compose -f src/main/docker/jhipster-control-center.yml up

9. Continuous Integration

Configure CI using the JHipster ci-cd sub-generator:

jhipster ci-cd

See Setting up Continuous Integration for more information.

10. Multi-Tenant Development Testing

The Registration Portal supports multi-tenancy, where each tenant is identified by the domain name used to access the application. During development, you can test tenant resolution using custom hostnames.

10.1. How Tenant Resolution Works

The TenantResolutionFilter resolves tenants in the following priority order:

  1. Domain match - The full hostname is matched against the domain column in the tenant table

  2. X-TENANT-ID header - Falls back to the X-TENANT-ID HTTP header if no domain match is found

Localhost and IP addresses are excluded from domain resolution to allow standard development access.

10.2. Setting Up Custom Hostnames

To test tenant resolution locally, configure your system’s hosts file to map custom hostnames to localhost.

10.2.1. Windows

Edit C:\Windows\System32\drivers\etc\hosts (requires Administrator privileges):

127.0.0.1 reg1
127.0.0.1 reg2
127.0.0.1 runningclub

10.2.2. macOS / Linux

Edit /etc/hosts (requires sudo):

sudo nano /etc/hosts

Add entries:

127.0.0.1 reg1
127.0.0.1 reg2
127.0.0.1 runningclub

10.3. Configuring Tenants in the Database

Insert or update records in the tenant table to match your custom hostnames:

-- Example: Create a tenant for hostname 'reg1'
INSERT INTO tenant (name, domain, registration_system_id)
VALUES ('Test Registration Site 1', 'reg1', 1);

-- Example: Create a tenant for hostname 'runningclub'
INSERT INTO tenant (name, domain, registration_system_id)
VALUES ('Running Club Portal', 'runningclub', 2);

The domain column must contain the exact hostname (without port) that will be used to access the application.

10.4. Accessing the Application

With the hosts file configured and tenants in the database, access the application using the custom hostname:

http://reg1:9000/membership/register/1
http://runningclub:9000/membership/register/1

The tenant context will be automatically resolved based on the hostname, and the TenantContext will be populated with the corresponding tenantId and registrationSystemId.

10.5. Verifying Tenant Resolution

Check the application logs for tenant resolution messages:

TenantResolutionFilter : Attempting to resolve tenant by domain: reg1
TenantResolutionFilter : Resolved tenant by domain: tenantId=1, registrationSystemId=1

If no tenant is found, you will see:

TenantResolutionFilter : No tenant resolved for request to: /membership/register/1 (this may be intentional for public endpoints)

10.6. Troubleshooting

Hostname not resolving

Verify the hosts file entry is correct and flush DNS cache if needed (ipconfig /flushdns on Windows)

"Invalid Host header" error

Ensure the webpack dev server is configured with allowedHosts: 'all' in webpack/webpack.custom.js

Tenant not found

Verify the domain column in the tenant table exactly matches the hostname (case-sensitive)

BrowserSync not accessible

Ensure BrowserSync is configured with host: '0.0.0.0' to listen on all interfaces