Full Changelog 4.0.1

Released 2026-09-04 · v7.1.2.a · 1 fix

The complete record: every commit in the release, grouped by type, including work that never reaches a customer-facing note. The external changelog is the readable summary of the same release.

Jira References

No Jira references found.

Bug Fixes

  • Reduce .env.mysql/.env.oracle to root-layer variables only

    Both vendor templates were still monolithic: their headers claimed to hold 'all environment variables needed for running the Provision Portal stack', and they bundled PORT, HTTPS_PORT, FT_PROV_API_JAVA_RAM, the UI host ports and other values that the root/provision-api/provision-portal .env split already moved out of the shared file. The root .env comment tells operators to 'take the corresponding block from .env.mysql', so a MySQL operator following it copied variables spanning two layers.

    Reduced both files to the same shape as docker/.env — SPRING_PROFILES_ACTIVE, TZ, DATA_FOLDER, the seven compose-interpolated values, NORTHBOUND_API_URL and the database block — so they differ from .env, and from each other, only in the vendor-specific database block. Updated each header to describe the file as a root-layer vendor-selection template instead of a full stack config, and pointed at provision-api/.env and provision-portal/.env for per-service settings.

Documentation

  • Add changelog for release 4.0.0

  • Update antora version to 4.0.1 (dev)

  • Regenerate changelog for release 4.0.0

  • Bring the documentation from docs/install-restructure

    Documentation only — the build.gradle and test changes that also live on that branch are deliberately left out.

  • Route the Spring Boot log to the mounted directory

    application.log is a separate stream from the provisioning trace files: logback resolves ${LOG_PATH:-logs} relative to the image WORKDIR, so it was written to /app/logs while only /app/Log is bind-mounted, and never reached the host. Set LOG_PATH in the compose example and split the two streams in the Logs section — the CustomLog_*/DebugLog_* files are created lazily, on the first provisioning operation, so an empty directory right after a deployment is expected rather than a fault.

  • Add third-party versions and the env-layer rule

    Adds a Third-Party Components table naming the source of every value: build.gradle and Dockerfile for what this repository pins, ext-components.adoc for the external minimums it does not.

    Replaces the deferred database minimums with the platform figures, MySQL 8.4 and Oracle 21c. MySQL8Dialect in application.yml establishes that the schema is an 8.x one, which is not the same as saying 8.0 is supported.

    Documents why seven variables stay in the root .env even though several of them configure one container only: compose.yml references them as ${…​}, and Compose does not interpolate env_file values. A port moved into a per-service file falls back to its default and the stack starts on the wrong one, with no warning.

  • Record the external component versions of release 4.0.0

    The generated changelogs cannot carry this: they are derived from commit messages, so a dependency that did not move during the sprint leaves no trace even though the release was verified against it.

    Goes in the hand-written release index only. all.adoc, qa.adoc and external.adoc are rewritten in full by Finalize-Sprint on every run.

  • Document where external component versions belong

    The changelog index was a bare release list with no guidance on the hand-maintained External components in this release section that each release page already carries, and no warning that qa.adoc, external.adoc and all.adoc are regenerated in full by the Finalize-Sprint pipeline. The sibling FT services (ft-qoe-web, TR-069 Emulator, IoT Emulator) all state this; provision-portal did not, despite being the repository that actually has the generated files someone could mistakenly hand-edit.

  • Fix stale env summary table, document vendor templates

    The two-layer summary table’s <service>/.env row still claimed host ports and JVM settings live per-service; both moved to the root .env when the split landed, and the IMPORTANT admonition twelve lines below already says so. Reworded both rows to match the detailed per-file tables further down.

    Also document docker/.env.mysql and docker/.env.oracle: the guide never mentioned them, which is how their drift from the root .env went unnoticed.

  • Reconcile vendor-selection rule across three passages

    The source-checkout vendor-template paragraph added in 9092623 told readers to run "cp docker/.env.oracle docker/.env" to pick a database vendor. Two pre-existing, unqualified passages said the opposite: one claiming there is no per-vendor file at all, the other stating vendor selection is always a variable change, never a file swap.

    Scope each rule explicitly: at runtime there is exactly one root .env, with a one-time exception for a source-repository checkout’s initial vendor-template copy; once that root .env exists (from FT_DISK or from the copy), switching vendors is a variable change inside it, not a further file swap.

  • Fix the FT_DISK link and name the docker/ subfolder

    The three ProvAPI links used the long Forms/AllItems.aspx?ga=1&id=…​ form and open the root of the folder, but compose.yml, compose.debug.yml and the .env templates the guide asks for are one level down, in docker/. Following the guide literally ends with "the files are not there".

    Replaces all three with the short :f:/r/ form and says outright where those files sit; the XML package really is at the root, so that row is unchanged apart from the link.

  • Link the third-party versions to FT Version Control

    The portal now publishes FT Version Control: a per-release record of what every FT service and every infrastructure component was built against, plus the upgrade steps between releases.

    Both places that carry third-party versions point at it and state the division of labour — the tables here describe this branch and this component, that page is the platform-wide record across services and releases.

  • Document split API/UI hosts, repoint FT_DISK links

    Three changes, all around how Provision Portal is packaged and where its two containers can run.

    Split deployment. The shipped compose.yml puts provision-api and provision-portal on one host, but the two are joined by a single runtime link: the UI nginx proxies to FT_PROV_API_URL, and browsers never reach the backend directly. A new Split Deployment section under Deployment gives a compose file per host, the trimmed root .env the UI host actually needs, the firewall and TLS consequences of moving that hop off the Docker bridge, and the start-up order once depends_on is gone. It says outright that FT_PROV_API_URL has to be set in the environment: block and not in provision-portal/.env: environment: wins over env_file:, so editing the per-service file fails silently, with a working login page and a 502 behind every call.

    FT_DISK links. The ProvAPI folder was renamed to "Provision Portal API and UI", which broke the path-based ProvAPI link and the sharing link for provision-portal alike. All four links now point at the merged folder, and the labels read "Provision Portal API" / "Provision Portal UI" rather than the container names.

    The docker/ subfolder. 87a5dc5 added the claim that compose.yml, its debug override and the .env templates sit one level down, in docker/. That is no longer true of the merged folder: it has no docker/ subfolder at all, and everything except ssl/ is at the root. Mentions of docker/ in the source repository are left alone — that directory still exists there.

  • Rewrite the guide around the standalone API bundle

    API and UI now ship as two separate, self-contained FT_DISK bundles, each unpacked into its own service directory and run from there. The guide (xml/, config/, logs/), a single .env, and the FT_DISK links repointed at the new folders.

    "Split Deployment" is gone as a special case — with separate Compose projects the UI always reaches the backend over its published port, so the section became "Connecting the UI", covering both topologies as one setting. Wording that assumed two services in one stack (depends_on, "both containers", UI ports and endpoint checks) is corrected or handed off to the UI guide.

    Also: JWT_SECRET now ships as a placeholder rather than being absent, so the checklist asks for a replacement instead of an addition; and the superseded docker-compose-deployment page is reduced to a pointer — it still carried 570 lines of two-service instructions contradicting both guides.

  • Deploy from the platform stack, two-layer env like NBI

    Provision Portal API is documented the way Northbound API is: compose.yml and the shared root .env come from the FT System <vendor> Stack folder, the FT_DISK folder carries only provision-api/.env, xml/ and config/. The environment table lists the variables the application reads (MYSQL_*, ORACLE_*, FLOWABLE_*, JWT_*); DB_* appear only as the anchor source. The per-service .env follows docker/provision-api/.env plus HikariCP and the log level. Cross-references to the web interface are reduced to Overview, Connecting the UI and Related Documentation.

  • Ship a single-service compose.yml like Northbound API

    The FT_DISK folder carries a single-service compose.yml in the platform layout (two env layers, x-db-env / x-flowable-env anchors, provision-api/ mounts) plus compose.debug.yml, the way the Northbound API folder does. The guide shows that file in Docker Compose, documents the missing depends_on for a standalone host, and notes that the full FT System stack already carries the same block.

  • Align the guide with the shipped FT_DISK folder

    Northbound API is reached on 9880 (NBI_HOST_PORT) across hosts — 8080 is the container port on the shared bridge — in the dependency, network and outbound tables, the startup wait loop and the production checklist. extra_hosts exists only in the single-service compose.yml; the stack block does not carry it, so the "identical" note says so. The docker run variant mounts with $PWD, lists the FLOWABLE_MYSQL_* names, and warns that --env-file neither expands ${DB_HOST} nor strips inline comments (verified on Docker 29). Log level default when unset is DEBUG (logback-spring.xml); one image is pulled, not two. The superseded deployment page says "folders", not "bundles".

  • Update antora version to 4.0.1

  • Add changelog for release 4.0.1

Chores

  • Add a coverage ratchet, and the dashboard that explains it

    The build measured coverage but never checked it: there was no jacocoTestCoverageVerification, so coverage could slip and nothing would say so. Add one at 0.81 instructions / 0.66 branches — just under the current 81.6% / 66.4%, so an honest refactor still builds while a silent regression does not. Verified both ways: raising the minimum to 0.99 fails the build with the expected message.

    Also turn the XML report back on. CI and SonarQube read the XML, not the HTML, and with xml.required = false there was nothing for them to read — this report had to be generated through a side task to get at the numbers at all.

    The dashboard in docs/ is generated from that XML and the JUnit results: 820 tests, 0 failures, coverage by domain and by package, and the gaps stated plainly — config at 7.3%, no integration tests against a live database or ACS (Testcontainers is unused, @SpringBootTest appears in two files), no E2E. For an integration layer, that last one is the gap worth planning around.

  • Give the coverage ratchet some slack

    The minimums were set flush against the current numbers — 0.81 against 81.6% of instructions, 0.66 against 66.4% of branches. That leaves half a point of head- happened to add it.

    A gate that fires on ordinary work does not survive its first deadline; it gets switched off, and then it protects nothing. Drop the minimums to 0.78 / 0.63 so the build fails when coverage drops meaningfully — tests deleted, a sizeable untested chunk merged — and stays out of the way otherwise.

    Also fix the dashboard, which still said the gate did not exist and the XML report was off. Both were true when it was written and false by the time it was committed — in the same commit that changed them.

  • Give each service its own .env file

    compose.yml handed the same .env to both containers while installation.adoc documented a two-layer model with provision-api/.env and provision-portal/.env, and the FT_DISK bundle ships those two files. The repository was the odd one out.

    The split follows the boundary the file already had in its section comments, with one correction on top: the seven variables compose.yml references as ${…​} stay in the root .env whichever service they configure. Compose interpolates the compose file from the shell environment and the project-directory .env only, so a published port moved into a per-service file would have silently fallen back to its default.

    Drops .env.bak.mysql and .env.bak.oracle, untouched backups from 2026-04-09, and fixes the doubled scheme in NORTHBOUND_API_URL.

  • Add deployment.yaml contract for Deployment Manager

    Deployment Manager reads this file from the tip of this branch to know the service’s image, ports, volumes, clustering pattern and the variables an operator must fill in. It was previously vendored in ft-internal-tools (deployment-manager/catalogue/contracts/provision-api.yaml); this repository now owns it.

  • Add the deployment/ config tree Deployment Manager mounts

    These are the application config files a generated Compose bundle mounts into this service’s container. They were vendored in ft-internal-tools (deployment-manager/catalogue/services/); this repository now owns them, and Deployment Manager reads them from the tip of this branch.

    Private key material is deliberately NOT here: keys and keystores stay in the one place they already live and are laid over this tree at generation time, so the same private key does not gain a copy per repository.

  • Bump version to 4.0.1

Refactoring

  • Split the config mount and align the API port

    Mount the backend configuration as two directories — ./provision-api/xml and ./provision-api/config — instead of one ./provision-api-conf, matching the layout the platform deployment guide already used, and move SPRING_CONFIG_ADDITIONAL_LOCATION to file:/etc/app/config/ so an application*.yml override still lands next to encrypted-parameters.txt.

    Change the published port fallback from 8085 to 8091. On a shared /usr/local/ft-system host 8085 is the Service API port, so the old default collided with it; 8091 is what the platform assigns to Provision API and what the documentation has always instructed operators to set.

    Drop the obsolete version: key, which Compose v2 warns about on every invocation, and ignore the local stack’s runtime data (XML, config, logs, TLS material) so a git add -A cannot commit the private key.

Tests

  • Cover ProvisionDeviceBuilder, ProvisionEntity and encrypted parameters

    Adds unit tests for the classes that had no coverage at all:

    • ProvisionDeviceBuilder (was 0%): merging of params.xml/objects.xml templates with stored provisions, device identity, general flags, device info, domain, objects, sub-objects and services.

    • ProvisionEntity (was 43%): MAC normalisation, DES/Base64 encryption of sensitive values, getValueForSaving branches and toDto mapping.

    • EncryptedParametersManager / EncryptedParametersHolder (were 0%).

    • ProvisionService: create, getDeviceBySerialNumber, getDeviceByMacAddress, getSerialNumberByMac and the delete operations.

    • ProvisionController: the paths behind MetricsUtils.doWithMetrics, which the existing mock never executed (callProcessAndGetResponse, startProcessAsync, getProvisionValues, faultVisible wrapping).

      Also extends NbiRestConnectorTest beyond updateDeviceInfo to getDeviceInfo, findDeviceByMac, removeProvisionDataFromCpe and sendAsyncRebootRequest, including the ACS error branches and the JSON request bodies. The RestClient chain is stubbed with explicit mocks instead of deep stubs, because a deep stub counts the navigational body() call as an invocation and breaks verify().

      Coverage: 63% → 70% instructions, 44% → 52% branches (596 → 693 tests). provision and nbi classes are now at 97-100%.

  • Cover ProvController, ServerController and DeviceController

    The ui package was at 2% instruction coverage: ProvController (24 methods), ServerController and DeviceController had no tests at all.

    • ProvControllerTest: getDevice (serial/MAC lookup, ACS OUI resolution and its failure paths, DB fallback), startProvisioning, deleteProvisionData, startReplaceCpeProcess, getStatuses, uploadFile, startMultipleProvisioning and deactivateServices, including the XML building and escaping. The metrics wrapper is stubbed to actually run the supplier it is given, otherwise none of the endpoint bodies would execute.

    • ServerControllerTest: version, configuration and log file categorisation.

    • DeviceControllerTest: domain listing.

      Coverage: 70% → 75% instructions, 52% → 56% branches (693 → 734 tests). ui classes are now at 90-100%.

  • Cover value resolution, converter and history row mapping

    • VParameterServiceValuesTest: the value-resolution pipeline that was largely untested - turning objects.xml templates into LIKE patterns (including the underscore escaping), resolving values from the prov, cpe_provision and cpe_provision_history tables, and the source precedence between them (PARAMS_XML < PROV < CPE_PROVISION_HISTORY < CPE_PROVISION). Also covers assigning object and sub-object parameters to their service, and dropping parameters that end up without a service or without a value.

    • ValuedDeviceConverterTest: device → VDevice structure conversion (was 0%).

    • ProvisionHistoryRowTest: the native-query row mapping, including the Clob → String conversion needed on Oracle (was 0%).

      Coverage: 75% → 79% instructions, 56% → 63% branches (734 → 773 tests). VParameterService 48% → 92%, ValuedDeviceConverter and ProvisionHistoryRow 100%.

  • Cover parameter enrichment, XML byte parsing and the small utilities

    • DeviceParameterEnricherTest (was 2%): attaching the friendlyName from params.xml, which is what later decides whether a value gets encrypted. Covers the caching of params.xml and the swallowed read failure.

    • DeviceXmlMapperBytesTest (was 56%): parsing uploaded XML from a byte array, skipping devices with invalid general attributes while keeping the valid ones, the strict 0/1 validation for single devices versus the relaxed 0/1/true/false one for multi-device files, ampersand escaping, the $$ clear marker, and marshalling booleans back as 1/0.

    • MacAddressUtilsTest, ApiExceptionTest, LocalDateTimeAdapterTest and BaseMainResponseMapperTest for the remaining uncovered utilities.

      Coverage: 79% → 81% instructions, 63% → 66% branches (773 → 820 tests). The project is now above the 80% instruction threshold.

Docker Images

provision-portal

Image

hub.friendly-tech.com/api/provision-portal:v4.0.1-b0.0.1

SHA256

sha256:5c5254596955a807e8fb39649448fd5fe96fbfefb5eb360a1ca12899cf59b14b

Pull from Registry

docker pull hub.friendly-tech.com/api/provision-portal:v4.0.1-b0.0.1

Download for Offline Use

docker pull hub.friendly-tech.com/api/provision-portal:v4.0.1-b0.0.1
docker save hub.friendly-tech.com/api/provision-portal:v4.0.1-b0.0.1 -o provision-portal-v4.0.1-b0.0.1.tar

gzip provision-portal-v4.0.1-b0.0.1.tar

Load on Closed Network

gunzip provision-portal-v4.0.1-b0.0.1.tar.gz
docker load -i provision-portal-v4.0.1-b0.0.1.tar

Dependencies

  • ACS → FT Configs Service v1.0.2-b0.0.1

  • UI Backend → ACS v7.1.2-b0.0.1

  • UI Portals → UI Backend v7.1.2-b0.0.1

  • FT Device Network → ACS v7.1.2-b0.0.1

  • UI AI Agent → UI Backend v7.1.2-b0.0.1

  • UI AI Agent → FT Device Network v1.0.3-b0.0.1