Deployment¶
The application is split across several repositories. Each one publishes its own
artifact; the template-docker
repository assembles them in a single docker-compose.yml deployed by Dokploy.
| Repository | Published artifact | Workflow |
|---|---|---|
template-java-api |
ghcr.io/tiogars/template-java-api image |
Docker Publish |
template-react-backend |
ghcr.io/tiogars/template-react-backend image |
Build and publish Docker image |
template-flutter |
GitHub Release with Android, Linux, Windows builds | Flutter releases (on v* tags) |
template-docs-mkdocs |
Documentation on GitHub Pages | Build and deploy docs |
template-presentation |
Slides on GitHub Pages | Publish presentation |
Images are tagged latest (default branch), sha-<commit> and, for v* tags,
with the version.
Services¶
docker-compose.yml declares three services and publishes no host port:
postgres: PostgreSQL 17 with the persistentpostgres-datavolume. On the first start of an empty volume, it runspostgres/initdb/01-task-domains.sql, a copy oftemplate-java-api/src/main/resources/db/manual/task-domains.sql.api: Spring Boot API on container port8080; healthy once/actuator/healthanswersUP.backend: web console served by Nginx on container port8080. It starts after the API is healthy.
Deploy with Dokploy¶
- Create a Docker Compose service with the GitHub provider, repository
tiogars/template-docker, branchmainand compose path./docker-compose.yml. - In Environment, set the variables listed below (see
.env.example). - In Domains, assign one domain to
backend(port8080) and one toapi(port8080), with HTTPS. - Deploy. Dokploy pulls the images from GHCR; they must be public, otherwise
register
ghcr.iocredentials (token withread:packages) in Dokploy.
To deploy a new image, rerun the deployment (or enable auto-deploy). Pin
API_IMAGE_TAG and BACKEND_IMAGE_TAG to sha-<commit> or a version for
reproducible deployments.
| Variable | Required | Purpose |
|---|---|---|
POSTGRES_PASSWORD |
Yes | Database password. |
POSTGRES_DB, POSTGRES_USER |
No | Database name and user; default template. |
APP_ADMIN_USERNAME |
No | Forced administrator username; defaults to admin. |
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. |
APP_CORS_ALLOWED_ORIGINS |
Yes | Comma-separated console origins, e.g. https://console.example.com. |
API_BASE_URL |
Yes | Public API URL used by the console, e.g. https://api.example.com. |
DOCS_BASE_URL |
No | Documentation URL shown in the console. |
GITHUB_BASE_URL |
No | Repository URL shown in the console. |
API_IMAGE_TAG, BACKEND_IMAGE_TAG |
No | Image tags; default latest. |
Compose refuses to start when a required variable is missing.
Console runtime configuration¶
The console image serves /config.js, generated at container start from
API_BASE_URL, DOCS_BASE_URL and GITHUB_BASE_URL. The same image can
therefore target any environment without being rebuilt. An empty value falls
back to the VITE_* value compiled into the bundle.
docker run --rm -p 5173:8080 -e API_BASE_URL=https://api.example.com \
ghcr.io/tiogars/template-react-backend:latest
curl http://localhost:5173/config.js
# window.__APP_CONFIG__ = { apiBaseUrl: "https://api.example.com", docsBaseUrl: "", githubBaseUrl: "" };
Local Test of the Stack¶
cd template-docker
cp .env.example .env
docker compose -f docker-compose.yml -f compose.local.yml up -d --wait
compose.local.yml publishes the API on http://localhost:8989 and the console
on http://localhost:5173, and sets the matching URLs. Dokploy only uses
docker-compose.yml.
Persistence Behavior¶
The API persists tasks, reusable tags, and hierarchical nomenclatures. 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, but automatic schema updates do not replace
the task-domain migration, migrate legacy business data, or remove obsolete
schema objects. The init script only runs on an empty volume: apply
task-domains.sql manually on an existing database before upgrading. Follow
the migration instructions.
Reset the Demo Database¶
Reset the volume when you want to remove all demo data and obsolete tables. This operation is destructive: it removes all task, taxonomy, authentication, and settings data; it is not an upgrade procedure.
docker compose down --volumes
docker compose up -d --wait
The init script recreates the task-domain schema on the new volume. In Dokploy,
stop the service and delete the postgres-data volume before redeploying.
Publish the Flutter Applications¶
The console download page (/downloads) lists the files served from
/releases/, described by /releases/manifest.json (version, size, SHA-256,
default API URL). Missing platforms are shown as unavailable.
- In
template-flutter, set theAPI_BASE_URLActions variable to the public HTTPS API URL compiled into the applications (users can still change it). - Push a
v*tag. TheFlutter releasesworkflow builds Android and Linux on Ubuntu and Windows on a Windows runner, then publishes a GitHub Release with the packages andbuild-info-<platform>.jsonfiles. - Rerun the
template-react-backendimage workflow. It downloads the latesttemplate-flutterrelease, generates the manifest, and embeds the files in the image. Without any release, the image is published without downloads. - Redeploy in Dokploy.
Android release builds block clear-text HTTP traffic: use an HTTPS API URL for
the APK. The APK is signed with the debug key until a release signing
configuration is added to android/app/build.gradle.kts.
Build Documentation and Slides¶
The documentation (template-docs sources, template-docs-mkdocs configuration)
and the presentation (template-presentation) are published on GitHub Pages by
their own workflows; they are not part of the Compose stack. Set DOCS_BASE_URL
to the published documentation URL.
Production Considerations¶
Keep the API, database, console, and documentation as independently deployable
units. Replace ddl-auto: update with versioned migrations, provide credentials
through the Dokploy environment, terminate TLS at the platform edge, and back up
the postgres-data volume.