Skip to content

Deployment

The local deployment uses six services:

  • postgres: PostgreSQL 17 with a persistent named volume;
  • api: Spring Boot application available on port 8989 locally. The base Compose file does not publish the API port; make docker-up adds the local override that publishes it;
  • backend: static Vite build served by Nginx on port 5173.
  • docs: MkDocs site published on port 8000.
  • java-site: Maven Site with aggregated Javadocs published on port 8083.
  • presentation: Marp presentation published on port 8082.

Start the Stack

make docker-up

After startup:

  • Documentation: http://localhost:8000
  • Java Maven Site: http://localhost:8083
  • Java API documentation: http://localhost:8083/apidocs/
  • API health: http://localhost:8989/actuator/health
  • Swagger UI: http://localhost:8989/swagger-ui.html
  • Management console: http://localhost:5173

The local Compose file supplies a development administrator account and JWT secret. The default console login is admin / admin.

Deployments on platforms such as Dokploy should use docker/compose.yml alone. The API remains available to other Compose services on port 8080, with no host port published. The local development override is docker/compose.local.yml.

Inspect service logs with:

make docker-logs

Stop containers while retaining PostgreSQL data:

make docker-down

Persistence Behavior

The API persists DomainTemplateEntity rows in domain_templates. The Compose volume is named from the project and the declared postgres-data volume; Docker Compose resolves the final volume name automatically.

The API also persists local authentication data in auth_roles, auth_users, and auth_user_roles. At startup it seeds the ANONYMOUS, ADMIN, and USER roles, then forces the administrator account from APP_ADMIN_USERNAME and APP_ADMIN_PASSWORD. If that username already exists, the account is enabled, its password hash is replaced from the environment value, and the ADMIN role is guaranteed.

Hibernate uses ddl-auto: update. This is convenient for this solution because it initializes domain_templates, but it does not remove obsolete schema objects. A volume created by an earlier version may therefore still contain domain_records. That table is unused and its presence does not indicate that the current application writes to it.

Reset the Demo Database

Reset the volume when you want to remove all demo data and obsolete tables. This operation is destructive.

docker compose -f docker/compose.yml -f docker/compose.local.yml down --volumes
make docker-up

The second command creates a fresh PostgreSQL volume and Hibernate recreates domain_templates on API startup.

Build Documentation and Slides

make docs-build
make presentation-build

The host commands make docs-build and make docs-serve use the lightweight docs/mkdocs.yml configuration with MkDocs Material. Both read docs/src and write generated output to site_output.

The Docker documentation service uses ghcr.io/tiogars/mkdocs-docker-image:latest with the richer docs/mkdocs/mkdocs.yml configuration, including PDF generation. The full docs directory is mounted read-only at /server/docs so the configuration, hooks, assets, overrides, templates, and Markdown sources are all available. site_output is mounted separately at /server/site_output for generated files. The server watches both the sources and the configuration directory.

Restart only the documentation service after changing its Compose configuration:

make docker-up-docs

To build HTML and PDF output with the image's bundled plugins:

docker compose -f docker/compose.yml run --rm --no-deps docs build --config-file docs/mkdocs/mkdocs.yml --strict

MKDOCS_CONFIG overrides the server configuration path inside the container. Use a path under the mounted tree, such as docs/mkdocs/mkdocs.yml, rather than a host path or ../docs/....

Production Considerations

Keep the API, database, console, and documentation as independently deployable units. Replace ddl-auto: update with versioned migrations, provide managed PostgreSQL credentials through secrets, terminate TLS at the platform edge, and set the console API base URL to the public API origin.

Provide these security variables through the deployment secret store:

Variable Required Purpose
APP_ADMIN_USERNAME Yes Forced administrator username.
APP_ADMIN_PASSWORD Yes Forced administrator password, stored only as a BCrypt hash.
APP_JWT_SECRET Yes JWT HMAC signing secret, at least 32 characters.
APP_JWT_EXPIRATION_SECONDS No Access token lifetime; defaults to 3600 seconds.