- JDK 25
- Docker with Docker Compose
- Git
- x86-64 Docker host for a supported SQL Server Linux container
- Java: 25
- Quarkus: 3.33.3.1
- Build: Maven Wrapper (
./mvnw) - Database: Microsoft SQL Server 2022
- Active local database name:
wl_chat - Active app login:
wl_chat_app - Audit transport: RabbitMQ-backed delivery is optional; if the audit transport is not configured, the app falls back to local async persistence and still boots cleanly
- Original roadmap status: Milestones 0–9 complete; Milestone X production activation paused
- Production client-ingress decision: public HTTPS/WSS through one hardened NGINX edge; user authentication and server authorization are initially authoritative. The required post-X sequence adds IE-01 native per-installation trust, IE-02 mobile-authorized linked-browser protocol support, and IE-03 the official linked web companion
- Post-roadmap enhancements: tracked as Evolution Tracks in
docs/platform-evolution-specification.md - Post-production infrastructure requirements: tracked in
docs/infrastructure-evolution-specification.md
This repository currently standardizes three environments:
-
Local
- App runs from IDE/terminal (
./mvnw quarkus:dev) - App connects to SQL Server on
localhost:1433
- App runs from IDE/terminal (
-
DevDocker
- App and SQL Server run as containers on a dedicated Docker network
- SQL Server host port:
1434 - App host port: configurable, default
8081
- Production
- Future hosted target (not provisioned yet)
- Milestone 9 rehearsal: one NGINX HTTPS/WSS edge in front of one private ChatBackend instance, SQL
Server, and RabbitMQ using
deploy/compose.hardened.yaml - Milestone X targets a public, authenticated HTTPS/WSS edge under
docs/architecture/decision/ADR-0019-public-authenticated-edge-and-future-enrolled-client-trust.md; ChatBackend, SQL Server, RabbitMQ, administration, and Docker control remain private - Apache APISIX remains an optional later replacement if multi-service gateway or load-balancing needs justify it through a later architecture decision
- Deployment automation is intentionally deferred until a persistent remote environment exists
This repository now includes a Dockerized RabbitMQ service that can act as a shared remote queue endpoint for one or more app instances. The queue is optional infrastructure for the app's audit transport and is not required for the core identity flows to work. The application now includes an optional RabbitMQ-backed audit transport with local async persistence fallback, so the service can keep running when the queue is unavailable or disabled.
- Compose service name:
queue-dev - Standalone compose file:
compose.queue.yaml - AMQP port:
5672(configurable) - Management UI port:
15672(configurable) - Persistent queue data volume:
wl-chat-devdocker-rabbitmq-data
This is infrastructure-only setup for the optional RabbitMQ-backed audit transport. The application can still run in local mode when the queue is unavailable or disabled.
Queue topology is provisioned at broker startup from repository-managed definitions under config/rabbitmq/:
- Exchange:
audit.events - Dead-letter exchange:
audit.events.dlx - Queue:
audit.events - Dead-letter queue:
audit.events.dlq
Set these in scripts/config/local.secrets.env (or via WL_CHAT_SECRETS_FILE):
WL_CHAT_QUEUE_USERNAME=wl_chat_queue
WL_CHAT_QUEUE_PASSWORD=replace_with_queue_password
WL_CHAT_QUEUE_VHOST=/
WL_CHAT_QUEUE_PORT=5672
WL_CHAT_QUEUE_MGMT_PORT=15672
WL_CHAT_QUEUE_HOST_IP=0.0.0.0
WL_CHAT_QUEUE_MGMT_HOST_IP=127.0.0.1
# Optional RabbitMQ-backed audit transport
WL_CHAT_AUDIT_RABBITMQ_ENABLED=true
WL_CHAT_AUDIT_RABBITMQ_HOST=127.0.0.1
WL_CHAT_AUDIT_RABBITMQ_HOST_CANDIDATES=queue-dev,127.0.0.1,host.docker.internal
WL_CHAT_AUDIT_RABBITMQ_PORT=5672
WL_CHAT_AUDIT_RABBITMQ_USERNAME=wl_chat_queue
WL_CHAT_AUDIT_RABBITMQ_PASSWORD=replace_with_audit_passwordNotes:
WL_CHAT_QUEUE_HOST_IP=0.0.0.0exposes AMQP to other hosts that can reach this machine.- Keep
WL_CHAT_QUEUE_MGMT_HOST_IP=127.0.0.1unless remote UI access is explicitly required. WL_CHAT_AUDIT_RABBITMQ_HOST_CANDIDATESis an optional ordered fallback list.- With
queue-dev,127.0.0.1,host.docker.internal, the same config works for both host-local and DevDocker runs. - For a fully remote broker, set
WL_CHAT_AUDIT_RABBITMQ_HOSTand optionallyWL_CHAT_AUDIT_RABBITMQ_HOST_CANDIDATESto remote-only values.
./scripts/cicd/queue-up.sh
./scripts/cicd/queue-down.shBy default these scripts use compose.queue.yaml so you can run queue infrastructure independent of app and DB.
Optional override:
export WL_CHAT_QUEUE_COMPOSE_FILE=/absolute/path/to/compose.queue.yaml./scripts/cicd/devdocker-up.sh
./scripts/cicd/devdocker-down.shPrimary runtime defaults are defined in src/main/resources/application.properties:
- JDBC URL default:
jdbc:sqlserver://localhost:1433;databaseName=wl_chat;encrypt=true;trustServerCertificate=true - Dev Services: disabled (
quarkus.datasource.devservices.enabled=false) - Flyway startup migration: disabled by default (
quarkus.flyway.migrate-at-start=falseunless overridden)
The application also supports external runtime config files so values can be changed without rebuilding the jar.
- Default runtime override file:
config/application.properties - Optional override location:
WL_CHAT_CONFIG_FILE=/absolute/path/to/application.properties - Restart required: yes
- Rebuild required: no
Config precedence for local development is:
- Environment variables
scripts/config/local.secrets.envorWL_CHAT_SECRETS_FILEconfig/application.propertiesorWL_CHAT_CONFIG_FILEsrc/main/resources/application.properties
Use the external runtime file for values such as ports, health toggles, log levels, or environment-specific runtime overrides. Keep secrets in scripts/config/local.secrets.env or another file pointed to by WL_CHAT_SECRETS_FILE.
The repository uses a two-phase SQL setup model:
- Bootstrap (admin, one-time per environment)
- Flyway versioned scripts in
scripts/database/flyway/master - Responsibility: create
wl_chatdatabase if missing
- Flyway migrations (versioned, repeatable process)
- Bootstrap location (master DB):
scripts/database/flyway/master - Application schema location (wl_chat DB):
scripts/database/flyway/wl_chat V20260808110000__create_wl_chat_database.sql(master)V20260808110500__create_app_login_and_user.sql(wl_chat)V20260808111000__grant_app_permissions.sql(wl_chat)V20260808111500__create_logical_schemas.sql(wl_chat)- New migrations use
VYYYYMMDDHHMMSS__description_in_snake_case.sql.
Pick one environment path at a time.
Create a local secrets file once so you do not need to export passwords every run.
cp scripts/config/local.secrets.env.example scripts/config/local.secrets.envThen edit scripts/config/local.secrets.env with your real values (at minimum MSSQL_SA_PASSWORD).
Notes:
- Setup scripts auto-load
scripts/config/local.secrets.envif it exists. - Setup scripts also support
WL_CHAT_SECRETS_FILEfor alternate file paths (used by self-hosted runner deploys). - The application now also auto-loads
scripts/config/local.secrets.envduring startup, so both./scripts/cicd/run-quarkus-dev.shand plain./mvnw quarkus:devpick up the same local DB credentials. scripts/config/local.secrets.envis gitignored and should not be committed.
Use this when you want to change non-secret runtime config without rebuilding.
Default file location:
mkdir -p configEdit:
config/application.propertiesExample values:
quarkus.http.port=8080
quarkus.log.level=DEBUG
quarkus.datasource.health.enabled=trueAlternate file path:
export WL_CHAT_CONFIG_FILE=/absolute/path/to/application.propertiesAfter editing the file, restart the application. A rebuild is not required.
Use these scripts instead of remembering the full bootstrap and migration sequence.
./scripts/database/bootstrap-local.sh- Creates the local database if it does not already exist.
./scripts/database/migrate-local.sh- Applies schema migrations to the local
wl_chatdatabase.
- Applies schema migrations to the local
./scripts/database/init-local.sh- Convenience wrapper for local bootstrap + migrate.
- Set
WL_CHAT_RESET_DB=trueto resetwl_chatand bootstrap Flyway history before reapplying migrations (destructive).
./scripts/cicd/run-quarkus-dev.sh- Starts Quarkus dev mode, loads local secrets, and writes logs under
logs/chat_backend.
- Starts Quarkus dev mode, loads local secrets, and writes logs under
./scripts/database/bootstrap-devdocker.sh- Creates the DevDocker database if it does not already exist.
./scripts/database/migrate-devdocker.sh- Applies schema migrations to the DevDocker database.
./scripts/database/init-devdocker.sh- Convenience wrapper for DevDocker bootstrap + migrate.
- Set
WL_CHAT_RESET_DB=trueto resetwl_chatand bootstrap Flyway history before reapplying migrations (destructive).
./scripts/cicd/devdocker-up.sh- Starts the DevDocker stack and initializes the database.
./scripts/cicd/devdocker-down.sh- Stops the DevDocker stack.
Build and verify:
./mvnw clean verifyRun tests only:
./mvnw testRun application locally:
./mvnw quarkus:devFormat source:
./mvnw spotless:applyShutdown local app and infrastructure:
# Stop Quarkus dev mode with Ctrl+C in its terminal
./scripts/cicd/devdocker-down.shUse this for day-to-day coding when you run Quarkus directly from your machine.
Required env vars:
MSSQL_SA_PASSWORD(required)WL_CHAT_DB_PORT(optional, default1433)WL_CHAT_DB_NAME(optional, defaultwl_chat)WL_CHAT_DB_USERNAME(optional, defaultwl_chat_app)WL_CHAT_DB_PASSWORD(required)
You can provide these via scripts/config/local.secrets.env instead of exporting in terminal.
Script order:
- Start SQL Server for Local mode.
./scripts/database/bootstrap-local.sh
- One-time/admin step per environment: creates database if missing.
./scripts/database/migrate-local.sh
- Applies Flyway versioned migrations.
./mvnw -q -DskipTests compile./scripts/cicd/run-quarkus-dev.sh
- This startup script sets
WL_CHAT_LOG_DIRtologsbefore launching Quarkus. - This startup script sets
WL_CHAT_LOG_DIRtologs/<yyyy>/<MM>before launching Quarkus. - Active app log:
logs/<yyyy>/<MM>/chat_backend/chatback.log - Active HTTP/audit transport log:
logs/<yyyy>/<MM>/chat_backend/http-audit.log - Rolled app logs:
logs/<yyyy>/<MM>/chat_backend/chatback.log.<yyyy-MM-dd>.gz(intraday size rollover appends backup index) - Rolled HTTP/audit logs:
logs/<yyyy>/<MM>/chat_backend/http-audit.log.<yyyy-MM-dd>.gz(intraday size rollover appends backup index)
Direct startup is also supported:
./mvnw quarkus:dev- Useful from an IDE terminal when you do not need the wrapper script.
- Local DB credentials are still loaded from
scripts/config/local.secrets.env. - Runtime overrides are also loaded from
config/application.propertiesby default. - The wrapper script remains the preferred path when you want the log directory exported consistently.
Shortcut for steps 2 and 3:
./scripts/database/init-local.sh- Runs bootstrap then migrate in order.
Use this when you want a remote-like local environment.
Required env vars:
MSSQL_SA_PASSWORD(required)WL_CHAT_APP_PORT(optional, default8081)WL_CHAT_DB_USERNAME(optional, defaultwl_chat_app)WL_CHAT_DB_PASSWORD(required)
You can provide these via scripts/config/local.secrets.env instead of exporting in terminal.
Preferred script order:
./scripts/cicd/devdocker-up.sh
- Starts DevDocker SQL Server.
- Runs
./scripts/database/init-devdocker.sh(bootstrap + migrate). - Starts DevDocker app container.
Manual equivalent (if needed for troubleshooting):
./scripts/database/bootstrap-devdocker.sh./scripts/database/migrate-devdocker.sh./scripts/database/init-devdocker.sh(wrapper for the two above)
Stop DevDocker stack:
./scripts/cicd/devdocker-down.sh
Use these only if you want branch-based pre-push checks locally.
./scripts/cicd/install-git-hooks.sh
- Installs
.githooks/pre-pushas active hooks path.
scripts/cicd/local-trigger.sh <branch>
- For
main: runs local DB init + compile. - For
production: runs production deploy placeholder.
When app is running locally:
GET http://localhost:8080/q/health/liveGET http://localhost:8080/q/health/readyGET http://localhost:8080/q/health
Notes:
livecan beUPeven when DB credentials are wrong.readyand aggregatehealthreport DB connectivity and returnDOWNif DB auth fails.
Workflows in .github/workflows currently include both DB validation and a self-hosted Dev deployment path:
-
db-local-bootstrap-migrate.yml- Validates bootstrap + migration flow in an ephemeral SQL Server container inside GitHub Actions runner
-
db-remote-bootstrap-migrate.yml- Manual, environment-protected remote migration using only the dedicated migrator credential
- Kept as deferred guidance until a persistent hosted environment is available
-
flow-smoke-gate.yml- Trigger: pull requests and pushes to
mainfor backend/database/postman flow changes - Runner:
ubuntu-latest - Execution order: start DevDocker stack -> validate Postman artifacts -> run Newman
Run-all API smoke journey-> upload Newman artifacts -> stop stack - Queue transport is disabled for this gate (
WL_CHAT_ENABLE_QUEUE=false,WL_CHAT_AUDIT_RABBITMQ_ENABLED=false), but compose interpolation still requiresWL_CHAT_QUEUE_PASSWORD, so the workflow sets a non-secret dummy value - CI Flyway bootstrap/migrate scripts use CI-safe defaults (
sqlserver-dev:1433onwl-chat-devdocker_default) instead of relying onhost.docker.internal:1434
- Trigger: pull requests and pushes to
-
dev-self-hosted-build-migrate-deploy.yml- Trigger: push to
mainor manual dispatch - Runner:
self-hosted(must run on this Dev machine) - Execution order: build app image -> start/reuse Dev SQL container -> bootstrap DB (idempotent) -> run Flyway migrations -> roll app container -> health checks
- Default behavior preserves SQL volume and user data across deploys (migration-only updates)
- Optional manual reset: run with
workflow_dispatchinputreset_db=trueto wipe SQL volume before deploy (destructive) - Uses runner-local secrets file path from
WL_CHAT_SECRETS_FILE(default workflow value:/Users/x3phantonpx3/.wl-chat/local.secrets.env)
- Trigger: push to
For GitHub-triggered Dev deploys, place a secrets file on the runner host (outside repo), for example:
/Users/x3phantonpx3/.wl-chat/local.secrets.envTemplate file:
scripts/config/runner.local.secrets.env.example
Required entries:
MSSQL_SA_PASSWORDWL_CHAT_DB_USERNAME(recommended)WL_CHAT_DB_PASSWORD(recommended)WL_CHAT_APP_PORT(optional)
The deploy workflow exports WL_CHAT_SECRETS_FILE so scripts read this host-local file directly.
To mirror branch-based remote triggers locally, this repository includes a Git pre-push hook:
mainpush trigger:- Runs
./scripts/database/init-local.sh - Runs
./mvnw -q -DskipTests compile
- Runs
productionpush trigger:- Runs
./scripts/cicd/production-deploy-placeholder.sh - Intended to be replaced later with real AWS deployment steps
- Runs
Install local hooks once:
./scripts/cicd/install-git-hooks.shKey files:
.githooks/pre-pushscripts/cicd/local-trigger.shscripts/cicd/production-deploy-placeholder.sh
Temporarily skip local triggers for one push:
WL_CHAT_SKIP_LOCAL_TRIGGERS=1 git pushCurrent application development version: 0.9.0-SNAPSHOT. Application releases follow Semantic
Versioning; API generations and Flyway migration versions remain independent.
Milestone 3 status snapshot (2026-08-11): session schema, login/logout/filter behavior, and the administrative revoke-all-sessions API are implemented and validated.
Milestone 4 status snapshot (2026-08-13): conversation persistence, authenticated user discovery, direct and group conversation APIs, membership authorization, SQL-backed tests, and Postman coverage are implemented and validated under ADR-0013.
Milestone 5 status snapshot (2026-08-13): durable authenticated text messaging, sender-scoped idempotency, per-conversation sequence allocation, forward history pagination, editing, soft deletion, safe audit metadata, SQL Server rollback guarantees, and concurrency coverage are implemented and validated. Delivery/read acknowledgements and WebSockets remain assigned to later milestones.
Milestone 6 status snapshot (2026-08-13): explicit per-user monotonic delivery/read acknowledgements, derived unread counts, own-position queries, sender-only aggregate status, safe auditing, SQL Server concurrency coverage, and the executable reconnect-reconciliation journey are implemented under ADR-0014. Transport publication remains only a signal; WebSockets and per-device receipts remain deferred.
Milestone 7 status snapshot (2026-08-14): unified RFC 9457 problems, generated and committed OpenAPI, OpenAPI-to-Postman operation checks, strict request and pagination limits, cursor-paginated member traversal, replica-safe SQL-backed login throttling, trusted proxy resolution, structured JSON logs, and validated request/trace correlation are implemented under ADR-0015.
Milestone 8 status snapshot (2026-08-22): authenticated WebSocket signaling, multi-connection registration, active-member-only post-commit fan-out, message and delivery/read events, inbound delivery/read acknowledgements, heartbeat support, session-revocation disconnects, and durable REST reconciliation are implemented under ADR-0016. SQL Server remains authoritative; socket delivery is never treated as durable delivery proof.
Milestone 9 implementation snapshot (2026-08-27): security boundary controls, query redaction, hardened WebSocket policy, forward-only runtime database permissions, distinct database principals, verified SQL TLS configuration, a non-root image, private-network NGINX/SQL/RabbitMQ rehearsal, encrypted backup/isolated restore automation, SBOM/security gates, and a reproducible load harness are implemented and validated in the local hardened rehearsal. The encrypted restore proved application startup, authentication, durable message history, and delivery/read cursors; characterization and threshold-gated load runs passed; and proxy, audit privacy, privilege, outage/recovery, and container boundary checks passed. Git-filtered source, the rebuilt application image, RabbitMQ, unprivileged NGINX, and the repository-owned migration image pass the local High/Critical security gate. Microsoft SQL Server 2022 CU26 retains visible High findings in vendor helper binaries; the project owner accepted that narrowly scoped risk for a private local rehearsal through 2026-11-26 without suppressing it. The milestone's repository-owned implementation and local rehearsal are complete. Public hosting, off-host backup storage, external alert delivery, and production load/SLA evidence remain explicit production-activation prerequisites and are not claimed.
- Detailed implementation runbook:
docs/development-guide/milestone-0-sql-server-step-by-step.md
- Milestone 1 database foundation runbook:
docs/development-guide/milestone-1-database-foundation-step-by-step.md
- Milestone 2 identity and invitations runbook:
docs/development-guide/milestone-2-identity-and-invitations-step-by-step.md
- Milestone 3 sessions and authentication runbook:
docs/development-guide/milestone-3-sessions-step-by-step.md
- Milestone 4 conversations and membership authorization runbook:
docs/development-guide/milestone-4-conversations-step-by-step.md
- Milestone 4 conversation identity, membership, and discovery decision:
docs/architecture/decision/ADR-0013-define-conversation-identity-membership-and-discovery.md
- Milestone 5 durable messaging, history, and mutation runbook:
docs/development-guide/milestone-5-messaging-step-by-step.md
- Milestone 6 delivery/read state and reconciliation runbook:
docs/development-guide/milestone-6-delivery-and-read-state-step-by-step.md
- Milestone 6 per-user cursor and status-visibility decision:
docs/architecture/decision/ADR-0014-use-per-user-delivery-and-read-cursors.md
- Milestone 7 API hardening runbook:
docs/development-guide/milestone-7-api-hardening-step-by-step.md
- Milestone 7 HTTP contract and authentication-throttling decision:
docs/architecture/decision/ADR-0015-harden-http-contracts-and-authentication-throttling.md
- Milestone 8 WebSockets and real-time signaling runbook:
docs/development-guide/milestone-8-websockets-step-by-step.md
- Milestone 9 operational-hardening implementation plan:
docs/development-guide/milestone-9-operational-hardening-step-by-step.md
- Milestone 9 single-instance hardening decision and threat model:
docs/architecture/decision/ADR-0017-harden-single-instance-deployment.mddocs/security/threat-model.md
- Superseded trusted-network client-access decision:
docs/architecture/decision/ADR-0018-restrict-client-access-to-owner-controlled-networks.md
- Public authenticated edge and future enrolled-client decision:
docs/architecture/decision/ADR-0019-public-authenticated-edge-and-future-enrolled-client-trust.md
- Deferred production activation program (Milestone X):
- umbrella scope and shared decisions:
docs/development-guide/milestone-x-production-activation.md - X1 production infrastructure and recovery foundation:
docs/development-guide/milestone-x1-production-infrastructure-and-recovery.md - X2 monitoring, operational validation, and production acceptance:
docs/development-guide/milestone-x2-monitoring-and-production-acceptance.md
- umbrella scope and shared decisions:
- Canonical client responsibility, offline behavior, and recovery guide:
docs/client-integration/client-responsibility-and-recovery-guide.md
- Human-run two-participant WebSocket/Postman integration guide:
docs/client-integration/manual-websocket-postman-testing-guide.md
- Release history:
CHANGELOG.md
- Versioning and changelog policy:
docs/development-guide/versioning-and-changelog-policy.md
- System specification and architecture baseline:
docs/private-instant-messaging-platform-spec-v0.2-sql-server.md
- Platform evolution specification and Evolution Track register:
docs/platform-evolution-specification.md
- Infrastructure evolution specification and IE Track register:
docs/infrastructure-evolution-specification.md
- Platform Evolution product and customer-experience audit outcome:
docs/audit/platform-evolution-product-and-customer-experience-audit-2026-08-29.md
- Environment lifecycle and rollout plan:
docs/operations/environment-strategy-and-rollout-plan.md
- Hardened deployment, backup/restore, and load-test runbooks:
docs/operations/hardened-deployment-runbook.mddocs/operations/backup-and-restore-runbook.mddocs/operations/load-test-baseline.md
- SQL Server principal and permission baseline:
docs/database/sql-server-principals-and-permissions.md
- Postman artifact workflow:
postman/README.md
Postman artifacts are version-controlled and should be updated whenever API contracts change.
Authoritative contract direction used for Postman maintenance:
- Java resources and DTOs under
src/main/javageneratedocs/api/openapi.jsonanddocs/api/openapi.yaml; Postman discovery and validation consume that operation inventory
Committed artifacts:
postman/collections/chat-backend.postman_collection.jsonpostman/collections/chat-backend-user-flows.postman_collection.jsonpostman/environments/local.example.postman_environment.jsonpostman/environments/devdocker.example.postman_environment.jsonpostman/environments/harddocker.example.postman_environment.jsonpostman/environments/production.example.postman_environment.json
Local-only Postman Cloud config:
- copy
postman/config.properties.exampletopostman/config.properties - keep
postman/config.propertiesuntracked/ignored
Local validation (no cloud key required):
./scripts/postman/discover-postman.sh
./scripts/postman/validate-postman.shCloud synchronization:
./scripts/postman/inspect-postman.sh
./scripts/postman/sync-postman.sh --dry-run
./scripts/postman/sync-postman.sh
./scripts/postman/sync-postman.sh --check-driftCI and manual workflow behavior:
- PR validation workflow runs local Postman artifact checks.
- PR validation workflow runs strict cloud drift checks when POSTMAN_* secrets are configured in GitHub.
- Manual Postman cloud workflow is guarded and runs only when explicitly dispatched.
For full setup and Native Git/Desktop guidance, see postman/README.md.
export JAVA_HOME=$(/usr/libexec/java_home -v 25)
export PATH="$JAVA_HOME/bin:$PATH"
docker compose up -d --wait sqlserver
./scripts/database/init-local.sh
./mvnw -q -DskipTests compile
./scripts/cicd/run-quarkus-dev.shThen verify:
curl -i http://localhost:8080/q/health/liveShortest local script-driven path after secrets are configured:
./scripts/database/init-local.sh
./scripts/cicd/run-quarkus-dev.shexport WL_CHAT_APP_PORT=8080 # optional, default is 8081
./scripts/cicd/devdocker-up.shThen verify:
curl -i http://localhost:${WL_CHAT_APP_PORT:-8081}/q/health/live
curl -i http://localhost:${WL_CHAT_APP_PORT:-8081}/q/health/readyStop DevDocker stack:
./scripts/cicd/devdocker-down.sh