The server implements the owner-scoped v1 API for #218. It uses Quarkus 3.40.1 LTS, Java 21, H2 2.5.250, and its own schema version 2. The same ordinary Java domain/application-service sources are compiled by the standalone Maven reactor and the Eclipse build. The server has no Eclipse Platform, workspace, SWT, Mylyn, OSGi or JPA dependency.
The bundled web client is available at /web/; see web client documentation for usage and browser tests.
See client/server acceptance for the inspected merged-main Eclipse, browser and synchronization receipts. Final tagged artifacts and public p2 installation remain separate release gates.
./mvnw -B -ntp -f server/pom.xml clean verify
python -m pip install -r common/api/tests/requirements.txt
python server/scripts/acceptance.py
JUnit checks the shared core, real Quarkus/HTTP/H2 bootstrap, protocol limits,
and refusal of damaged/unknown schemas. The process suite runs the black-box
API contract cases against a fresh file database, then restarts in new
JVMs and verifies IDs, provider links, assigned labels, an open interval, durable
command replay, immediate forced termination after stop, token revocation,
long-poll delivery, import rollback, hierarchy conflicts, nanoseconds and both
DST transitions. Fixtures include paths with spaces and supplementary Unicode.
The runner uses generated test tokens and removes its own database/configuration
when finished. Logs and a credential-free receipt are under
server/target/acceptance/ and uploaded by CI.
For Docker on your own computer, follow the local Docker setup guide. It covers a source build, persistent storage, credentials and Eclipse connection settings.
For Synology Container Manager, use the complete Docker Compose deployment. It supplies two PostgreSQL-backed server replicas, one PostgreSQL instance using its official image, and HAProxy. Data lives in a separate host directory. The updater drains and replaces one server at a time, verifies readiness and restores the previous images on failure. Database upgrades are separate maintenance work.
Use a separate empty server database; the embedded Eclipse schema 3 and historical databases are unsupported. The server never copies or merges embedded data automatically. Follow account setup and migration to create the first administrator, claim existing owners explicitly, and issue personal Eclipse API tokens. The same guide describes password recovery and session lifetimes. Configure an explicit JDBC URL before starting the JVM.
The authenticated GET /api/v1/server reports this server’s build identity and
timestamps, which the web client displays in its footer. For a direct JVM
deployment, set TIMEKEEPER_DEPLOYED_AT to the actual UTC deployment timestamp
(for example, 2026-10-13T08:30:00Z) and retain that value in the service’s
environment across restarts. Without a recorded deployment timestamp, the web
client shows Not recorded; process-start time remains available separately.
Each account has a stable owner ID; usernames and display names can change.
All business data is private to that owner, including for administrators. New
owners receive a UTC profile and can set their IANA reporting zone through
PUT /api/v1/me with its ETag. API requests never select another owner.
Each account starts with the same eight labels as embedded Eclipse:
Production issue, Testing, Prototyping, Planning, Programming, Debugging,
Communication and Meeting, with their standard colors. Labels have separate
UUIDs for each owner. Server startup initializes an existing account only when
its label set is empty; any nonempty set, including customized labels, is kept
unchanged. Deleting all labels leaves the running account empty; restarting
restores the defaults, matching embedded initialization. New owners added while
running are initialized atomically on their first successful operation. Both
deployments use the shared catalog in common/timekeeper-domain.
The legacy token registry remains available during migration; new personal API tokens are managed under Account in the web client. An unset registry or an empty array is valid. A configured missing/malformed registry fails startup or readiness and private API requests return 503.
By default the server binds 127.0.0.1:8080. QUARKUS_HTTP_PORT changes the port;
QUARKUS_HTTP_HOST changes the bind address. Use TLS outside loopback and set
TIMEKEEPER_PUBLIC_ORIGIN when terminating HTTPS at a reverse proxy. There is no
cross-account sharing or anonymous local-owner fallback.
Optional JDBC credentials use TIMEKEEPER_SERVER_DB_USER (default sa) and
TIMEKEEPER_SERVER_DB_PASSWORD. The server database account requires schema
initialization and H2 database-administration rights. Permitted URL settings are
IFEXISTS, DB_CLOSE_ON_EXIT, AUTO_SERVER, AUTO_SERVER_PORT and
LOCK_TIMEOUT; arbitrary startup SQL, credentials in URLs, read-only mode and
persistent JDBC settings are rejected before opening storage. Named memory
storage is suitable for tests; production uses durable file/server storage.
GET /api/v1/openapi.json serves the canonical public contract. All data routes
require the session or token’s read/write permission and bind repository operations to its
owner. Database foreign keys include owner/type/UUID; external identities are
unique per owner and only one interval may be open per owner. Resource updates
use both strong opaque ETags and SQL version predicates. An owner row lock
serializes compound tracking operations; different owners have separate locks.
Start, stop, events and command receipt commit together. Receipts and committed
changes currently remain indefinitely (at least the contract’s seven-day retry
window); no maintenance task silently removes history.
The server validates table/column/key/index/check definitions and the READY
version marker before accepting existing storage. Unknown tables/views,
non-public schemas, user sequences/domains, incomplete initialization and missing
ownership constraints fail without schema/data repair. H2 DDL commits during
initialization, so interrupted creation retains INITIALIZING and requires an
operator to select new storage or restore a known valid backup. The canonical
server schema 1, 2 or 3 upgrades to schema 4 as described in the account guide;
no historical or embedded-schema migration is provided.
After schema validation, the server sets
WRITE_DELAY=0
so acknowledged commits survive the tested immediate JVM termination. Startup
settings cannot weaken this. The forced-restart acceptance preserves the exact
stopped interval and the original response/ETag, not a newly executed stop.
Readiness is /q/health/ready; it checks connections, schema and registry.
Liveness is /q/health/live. Monitoring responses expose no tokens/owner data.
API errors are stable problem responses; they do not expose SQL or configuration
contents. HTTP requests are limited to 20 MiB, with typed 413 responses before
JSON processing. Portable import/export also allows at most 10,000 records per
type. Provider lookup URLs allow the percent-encoded forms of the declared Unicode
identifier bounds. Larger exports fail as a whole, and failed imports roll back
all records, events and receipts. Imports always allocate fresh UUIDs and never
change the owner’s zone or overwrite records.
For a file backup, stop the server, copy its H2 file, and restart. To restore, stop it, preserve the current file, replace it with a verified server-schema-1 backup, and reopen the same configuration. A JSON export is current-model interchange, not a physical backup or legacy migration. Protect the registry separately; tokens are never included in data export. Keep the server version, source commit and distribution checksum with operational records.
Work Sessions use the server’s existing generic SQL schema 1, while portable JSON/CSV export uses domain-v2 to retain sessions and optional activity links. Older exports remain readable. Older server binaries do not preserve this new domain model during writes or export, even though the SQL tables are unchanged. The first-upgrade procedure therefore requires pausing writes until every replica supports Work Sessions. Keep compatible server builds for subsequent image rollback; a downgrade to the previous domain model requires a matching pre-upgrade backup.
The Build workflow’s server-standalone artifact contains the Java 21 server
distribution timekeeper-server.zip and its SHA-256 checksum. The ZIP includes
the bundled web client and source provenance. It is separate from the Eclipse
p2 repository and the DSM installer. For Synology, download synology-installer
from the Server containers workflow instead; that artifact contains the .spk,
its checksum and installation metadata.
CI runs the process suite from the extracted ZIP, verifying its checksum and
actual runtime layout. Packaging requires the exact clean committed source.
Package the built source with:
python server/scripts/package_server.py --output server/target/distribution \
--commit <full-source-commit>
For release packaging, additionally supply --tag <actual-tag>; the tool verifies
that the tag resolves to the recorded source commit. Untagged CI builds are
explicitly marked as candidates.
Release publication must build this from the accepted tag and publish the server archive alongside the tested Eclipse/web deliverables. A CI artifact is a candidate, not a published 2.0 release. See the repository’s release checkpoint.