personal-progress is a Java 17 / Spring Boot platform kernel for reviewed, trusted PF4J plugins. It contains no current Body implementation: the tested retired route GET /api/v1/body-metrics falls through to an exact HTTP 404.
| Module | Responsibility |
|---|---|
progress-bom |
Platform and internal dependency versions. |
progress-plugin-api |
Spring-free plugin contracts. |
progress-core |
Platform persistence, policy, audit, and database registry. |
progress-plugin-runtime |
PF4J runtime, child contexts, lifecycle, dispatch, and resource governance. |
progress-app |
Executable Spring Boot application and HTTP API. |
Run from the repository root in PowerShell:
./mvnw.cmd clean test
./mvnw.cmd -pl progress-app -am package -DskipTests
java -jar .\progress-app\target\progress-app-0.1.0-SNAPSHOT.jarThe last command starts the packaged application; set the runtime variables below first. The package command is the build path verified by this repository's documentation update. The normal test suite covers static, unit, and non-database tests.
The real end-to-end acceptance test is separate. It starts PostgreSQL through Testcontainers and needs Docker, but no user database credentials:
./mvnw.cmd --% -pl progress-app -am test -Dtest=PluginPlatformEndToEndIT -Dsurefire.failIfNoSpecifiedTests=falseThis is intentionally not represented as passing in the current environment: Docker is unavailable, so Testcontainers discovers the two E2E tests but skips them. Phase 2 is therefore not accepted as complete.
Never commit credentials or tokens. Set these only in the environment that starts the application:
| Variable | Purpose |
|---|---|
PROGRESS_ADMIN_TOKEN |
Required non-blank bootstrap bearer token for every /api/v1/platform/** request. |
DB_URL, DB_USERNAME, DB_PASSWORD |
Low-privilege platform connection. DB_PASSWORD is required and kept outside source control. |
DB_PROVISIONING_URL, DB_PROVISIONING_USERNAME, DB_PROVISIONING_PASSWORD |
Privileged connection used only to create/drop plugin schemas and roles; the URL falls back to DB_URL. |
PROGRESS_PLUGINS_DIR, PROGRESS_DATA_DIR |
Optional managed plugin-artifact and plugin-data directories. |
Native PostgreSQL integration tests require a dedicated disposable test database, not the runtime database:
| Variable | Purpose |
|---|---|
DB_TEST_URL, DB_TEST_USERNAME, DB_TEST_PASSWORD |
Dedicated PostgreSQL database used by native database integration tests. |
DB_TEST_ALLOW_DROP=true |
Explicit destructive-test opt-in; permits resetting only that dedicated test database. |
DB_PROVISIONING_URL, DB_PROVISIONING_USERNAME, DB_PROVISIONING_PASSWORD |
Additional privileged credentials for tests that create/drop the test plugin schemas and roles. |
Testcontainers E2E uses its own PostgreSQL container and needs a reachable Docker daemon; it does not use DB_TEST_* or user-supplied database secrets.
| Surface | Route | Access and response contract |
|---|---|---|
| Artifact review | /api/v1/platform/plugins/artifacts |
Admin token. Upload returns 201 Created; approve/reject return 200 OK; artifact reads return 200 OK. |
| Plugin management | /api/v1/platform/plugins |
Admin token. Reads return 200 OK; lifecycle mutations return 202 Accepted, an operationId, and Location: /api/v1/platform/operations/{operationId}. |
| Operation status | /api/v1/platform/operations/{operationId} |
Admin token; read returns 200 OK. |
| Plugin business dispatch | /api/v1/plugins/{pluginId}/** |
Dispatches only to a started plugin endpoint through the explicit request contract. |
| Health | /actuator/health |
Public health endpoint. |
Lifecycle mutations are install, load, start, stop, unload, normal uninstall, and purge. They require Idempotency-Key; purge additionally requires exact plugin ID/version confirmation. Artifact upload and review are synchronous and are not operation resources.
The platform accepts a caller's X-Correlation-Id only when it matches the safe correlation format; when it is missing or invalid, the platform generates one. On an error, the trusted response header X-Correlation-Id and the RFC 9457 ProblemDetail.correlationId are the same value. Dispatcher audit events reuse that value. A plugin's response cannot forge or replace the platform correlation header, and sensitive upstream headers (including authorization and cookies) are not forwarded to plugins.
Plugins declare a positive PluginResourceRequest; PluginPolicyEvaluator rejects a declaration over the platform maximum. The current application configures the maximum as PluginResourceRequest.defaults(), so the default and hard cap are intentionally identical today.
| Field | Default | Current platform hard cap | Meaning |
|---|---|---|---|
maxEndpoints |
32 | 32 | Registered HTTP endpoints. |
maxConcurrentRequests |
8 | 8 | In-flight plugin requests. |
maxQueuedRequests |
32 | 32 | Queued plugin requests. |
maxRequestBodyBytes |
1,048,576 (1 MiB) | 1,048,576 (1 MiB) | Accepted plugin request body size. |
requestTimeoutMillis |
10,000 (10 s) | 10,000 (10 s) | Invocation timeout. |
maxScheduledTasks |
4 | 4 | Scheduler tasks. |
databasePoolSize |
4 | 4 | Plugin JDBC-pool connection limit. |
statementTimeoutMillis |
30,000 (30 s) | 30,000 (30 s) | PostgreSQL statement timeout. |
storageQuotaBytes |
104,857,600 (100 MiB) | 104,857,600 (100 MiB) | Plugin storage quota. |
- This is a trusted-plugin runtime, not a security sandbox. PF4J classloading and capability restriction do not protect against malicious code in the same JVM; only reviewed artifacts may be admitted.
- The runtime uses PF4J Core only—there is no
pf4j-spring. Each plugin receives an independently managed Spring child context with explicit capabilities, never the root application context or root data sources. - Dispatch uses immutable endpoint snapshots and invocation guards. Scheduler, storage, and audit capabilities apply bounded, observable in-process limits; these are governance controls, not a hard isolation boundary.
- The runtime is single-node. Lifecycle linearization, operation recovery, in-memory endpoint snapshots, and per-process resource accounting are not clustered or distributed locks.
- Core Flyway migrations create only the platform schema/tables. Plugin JARs are forbidden from dynamically running Flyway migrations. The platform provisions and registers each plugin's PostgreSQL schema and role.
- Before a started database plugin opens its pool, the platform generates a transient credential, rotates it through
ALTER ROLE ... LOGIN, then opens/probes the bounded pool. Stop closes the pool before switching the role toNOLOGIN; normal uninstall retains the schema and role inNOLOGINstate for rebind/reinstall. Purge is destructive: after exact confirmation it drops only the registered schema and role.
Audit is executable rather than aspirational. The dispatcher creates audit rows only for permission rejection, oversized body, capacity/resource rejection, and timeout; successful dispatches, routing failures, and generic handler exceptions are sanitized problems plus metrics, not full dispatcher audit rows. Sensitive metadata (including authorization, token, password, secret, request body, and response body fields) is redacted before persistence; audit failures are isolated so they do not replace the primary operation result.
The code, static checks, and non-database tests are ready for Phase 2. The real Testcontainers PostgreSQL/PF4J acceptance scenario has been authored and is detected by Maven, but Docker is unavailable in the current environment and its two tests are skipped. Do not claim Phase 2 complete until that E2E gate runs successfully against real PostgreSQL.