- migrate auth, manager, data, and agentic persistence to R2DBC
- hard cut pagination, facade, gateway, web, and CLI contracts
- remove legacy database and TSDB adapters and document validation gates
BREAKING CHANGE: platform persistence now requires PostgreSQL 18 with TimescaleDB and the new reactive API contracts.
- Spring Boot 4.0.7 -> 4.1.1, Spring Cloud 2025.1.2 -> 2025.1.3,
Spring AI 2.0.0 -> 2.0.1, springdoc 3.0.3 -> 3.1.0
- Migrate gRPC starters to the Boot-owned spring-boot-starter-grpc-client/server
line (org.springframework.grpc starter stops at 1.0.3 and mixes badly with the
spring-grpc-core 1.1.1 managed by the Boot 4.1 BOM), and move the
spring.grpc.channels.* YAML keys to the new spring.grpc.channel.* format
- Refresh driver protocol libraries (modbus4j 3.1.0, jSerialComm 2.11.4,
bacnet4j 6.1.1, gurux-dlms 4.0.96, j60870 1.8.0, snmp4j 3.13.1) and drop the
flow-control overrides removed from the modbus4j SerialPortWrapper interface
- Refresh jackson 2.x/3.x, protobuf, okhttp, micrometer, oshi, sqlite-jdbc,
swagger-core, instancio, mockito, logstash-logback-encoder 9.0 and the
graalvm native plugin; keep commons-io (broken timestamp-version candidate)
and j-interop 2.0.4 (legacy major) pinned
Co-Authored-By: Claude <noreply@anthropic.com>
dc3-common-jdbc was the family's core in disguise — MyBatis-Plus wiring,
the tenant-line handler, the databaseIdProvider, the jdbc profile. It now
lives as dc3-db/dc3-db-core, matching the dc3-mq-core / dc3-tsdb-core
shape: one aggregator, port first, adapters after, tck last. Artifact
renamed, packages deliberately untouched (same convention as the mq
family move); twelve poms rewired, the family aggregator puts core
first, and the db-tck now depends on the core explicitly instead of
riding transitives.
dc3-common-sql stays where it is on purpose: it is not platform dialect
plumbing but the base class of the four JDBC *device drivers*
(mysql/oracle/postgresql/sqlserver drivers that connect to external
databases being collected from) and depends on the driver SDK — under
dc3-db it would claim a meaning it does not have.
Gates: db-tck 24/24 (postgres + mysql + mariadb), data 274/274,
full-repo compile green.
R1 of docs/design/storage-abstraction.md §3 — zero behavior change:
Portable SQL rewrites (verified against a live PostgreSQL before landing):
- COUNT(*) FILTER (WHERE) x3 -> COALESCE(SUM(CASE WHEN ... THEN 1 ELSE 0
END), 0); the COALESCE keeps the empty-set result at 0 where bare SUM
would return NULL.
- dailyTrend's generate_series + date_trunc calendar spine -> a
RECURSIVE CTE day ladder (CAST(day + INTERVAL '1' DAY AS DATE) keeps
the column type stable on both engines — the bare date+interval form
widens to timestamp on PostgreSQL and fails the recursive term's type
check, caught live); day rendering via CONCAT instead of ::text.
- OAuthMcpMapper: '{} '::JSON literals -> '{}' (unknown literals coerce
to the JSON column on both engines), NULL::BIGINT -> NULL in the
UNION arm, #{riskLevel}::text parameter casts dropped (the text column
compares untyped parameters fine on both).
- The reserved-word alias AS key (a MySQL landmine hiding inside three
otherwise-portable statements) renamed to bucket_key / bucketKey
across both Dashboard mappers and BucketRow.
Module split: dc3-common-postgres -> dc3-common-jdbc (MyBatis-Plus
wiring, tenant-line handler, generator utils, the new dialect-neutral
jdbc profile carrying the shared mybatis-plus/hikari plumbing) + the
top-level dc3-db family's dc3-db-postgres (driver, timestamptz type
handler, postgres profile delta, and the pagination DbType bean the
neutral config now injects — defaulting to PostgreSQL so a bare
jdbc-only classpath behaves exactly as before). Packages deliberately
unchanged, mirroring the mq/tsdb family moves; all nine dependent poms
rewired; make deploy publishes the dc3-db family.
The jdbc module's interceptor integration test now pins an explicit
embedded H2 datasource — the module carries no driver on its main
classpath, so context inference would fail without it.
Gates: data/auth/manager/jdbc/db-postgres unit suites green (274 in
data), full-repo compile green, e2e 26/26.
Phase 1b of docs/design/tsdb-abstraction.md: every point-value read and
write now flows through the dc3-tsdb port, and dc3-common-repository is
deleted outright (no compat aliases).
Write path — new PointValueIngestService orchestration in dc3-common-data:
the stale-owner lease guard leaves the history INSERT's cross-schema join
and resolves the active owner per distinct device through the existing
DeviceFacade.getActiveOwner chain; a caffeine-backed ingest idempotency
window (dc3.data.ingest.*, marked only after both writes commit) absorbs
MQ redeliveries now that the message_id unique index is retired; the
batch lands via TsdbStore.append (natural series+time upsert, INGEST_ORDER
kept for the fenced dc3_point_latest upsert).
Read path — history via last(), page() resolves name/enable filters to
series keys through relational metadata (tenant-wide when unrestricted,
cursor offset emulation capped at 10k) with count() for totals; the alarm
window backend becomes TsdbWindowDataSource over aggregate()/history().
Dashboards — all nine data-side hypertable statements move to the S13
analytics facet (count/bucketedCount/countByDimension/latencyHistogram/
lastSeenPerSeries) plus the dc3_point_latest projection for latestStream;
the manager topology statement crosses into the data center via a new
ListSeriesVolumes RPC backed by the new S13-5 seriesCounts primitive (a
point shared by several devices needs per-series counts, which
single-dimension grouping cannot reconstruct); both cross-schema joins
are gone.
Port/adapter — seriesCounts added with a TCK case (23 total); series
filters compile to row-value IN lists chunked at 500 pairs; bootstrap
adds the quality column idempotently and retires uk_point_value_event so
existing deployments converge on the new upsert; the adapter binds the
application-provided tsdbDataSource bean (the history dynamic-datasource
entry) instead of the routing primary.
Timestamps — BO<->Instant conversion is pinned to
TimeConstant.DEFAULT_ZONEID (the platform canonical zone the latest
projection type handler already writes with); the design note's "lock
UTC" is amended accordingly, together with the lease-guard and S13-5
deviations recorded in §6.2.
Seed/deploy — 05-iot-dc3-history.sql gains the quality column and swaps
the unique index; compose carries DC3_TSDB_TYPE; make deploy publishes
dc3-tsdb.
Also fixed along the way: root pom never managed dc3-mq-core (latent,
masked by full-reactor builds); PointValueMapper ran unrouted on the
master datasource (now @DS("history")); latestStream name enrichment
looked up a Long-keyed map with String keys.
Gates: tsdb TCK 23/23, dc3-common-data 262/262, e2e 26/26 including the
unmodified PostgresHypertableIT; full reactor green except dc3-mq-tck's
kafka/pulsar container-startup flake, reproduced identically twice and
unrelated to this change.
The broker-selection family (port + six certified adapters + tck) is a
deployment selection, not shared plumbing, so it moves out of dc3-common
into a top-level dc3-mq aggregator beside dc3-api — the same standing as
the gRPC contract layer, and a template for future pluggable families
(storage is next on the design board).
- dc3-common-mq -> dc3-mq/dc3-mq-core (port: API + core runtime)
- dc3-common-mq-{rabbitmq,kafka,rocketmq,pulsar,activemq,mqtt,tck} ->
dc3-mq/dc3-mq-{...}; no compatibility aliases — every coordinate is
renamed everywhere in one commit (business poms, coverage, root
dependency management)
- dc3-common sheds eight modules back to plain shared plumbing; the
device-access dc3-common-mqtt stays by design (protocol stack, not a
broker selection)
- Java packages deliberately stay io.github.pnoker.common.mq.* — the
facade modules set the precedent that packages do not track module
homes, keeping this a pom-only, zero-source refactor
- make deploy now publishes dc3-api + dc3-common + dc3-mq (third-party
driver authors compile against the port transitively)
- docs/mq-brokers.md and the design's module layout follow the new home
Verified: full-repo test-compile green; constant/data/driver/manager
unit suites unchanged and green (255/144/291); the rabbitmq contract
suite passes 12/12 from the new coordinates against a live broker,
proving adapter wiring survived the move.
Phase 3 (4/4) and the final piece of the mq abstraction: every broker
named in the design is now a TCK-certified selection behind
dc3.mq.type. Pulsar suite 11 pass + 1 documented skip on the first run.
- topics map to persistent://public/default/dc3-<topic>, logical dead
topics to dc3-<topic>-dlq; LOAD_BALANCE rides a durable shared
subscription named after the consumer group (competing consumers,
retained while offline), BROADCAST rides an exclusive per-instance
subscription
- pulsar subscriptions start at the latest position natively, matching
the rabbit fresh-queue / kafka latest semantics with no seeding
- acknowledge(List<MessageId>) commits deliveries, negativeAcknowledge
requeues; reject(false) republishes to the -dlq topic and commits;
poison and exhausted batches dead-letter through the shared
synchronous bounded-retry semantics
- sends complete with the broker-issued message id (publisher
confirmation); batchReceive is the native batch (capability true);
arbitrary delays ride the port fallback like the other adapters
- tck harness against apachepulsar/pulsar standalone, or TCK_PULSAR_URL
for an externally managed broker
Phase 3 (3/4): RocketMQ adapter (classic client) for
dc3.mq.type=rocketmq, TCK 11 pass + 1 documented skip against a live
nameserver/broker pair.
The 5.x classic client has two behaviors that had blocked certification,
both now handled in the adapter:
- brand-new consumer groups replay the topic backlog regardless of
consumeFromWhere (LAST and TIMESTAMP both ignored), so fresh groups
are seeded explicitly: a short-lived pull consumer sets every queue
without a committed offset to the current max offset before the push
consumer starts, matching the rabbit fresh-queue / kafka latest
semantics; groups with a real offset trail are untouched
- subscribing to a topic that was never published to waits out the 30s
route refresh, so subscribe-time seeding also warms up missing topics
with a publish (the warm-up lands before the seeded offset, invisible
to every fresh group)
Further fixes surfaced by the suite: dead-letter republishes only the
standard envelope headers (RocketMQ system properties like
CONSUME_START_TIME are rejected on re-publish), and requeues request the
1s delay level so bounded retry exhaustion dead-letters within the
contract window instead of the 10s default.
Topics map to dc3-<topic> (no dots), dead letters to dc3-<topic>-dlq;
LOAD_BALANCE rides CLUSTERING consumer groups, BROADCASTING fans out per
instance; sync sends are the publisher confirmation; arbitrary delays go
through the port fallback (delay levels would quantize). The tck harness
is opt-in via TCK_ROCKETMQ_NAMESRV (testcontainers cannot manage the
nameserver/broker pair); a fresh-group isolation probe rides along in
the adapter module, also opt-in.
Phase 3 (2/4): MQTT 5 adapter (hivemq client) for dc3.mq.type=mqtt,
working against any MQTT 5 broker with shared subscriptions (EMQX,
HiveMQ, NanoMQ, VerneMQ). TCK 10 pass + 2 documented skips.
- topics map to dc3/<topic> (slash style), logical dead topics to
dc3/<topic>/dlq; LOAD_BALANCE rides $share/<group> shared
subscriptions, BROADCAST rides a plain filter, and every subscription
gets its own client session so broadcast instances are independent
- QoS 1 with manual acknowledgements: ack acknowledges the publish,
PUBACK doubles as the publisher confirmation (capability true)
- MQTT has no server nack: reject(true) is approximated by bounded
client-side redelivery, reject(false) republishes to the /dlq topic
and acknowledges; poison and exhausted messages dead-letter
- delays go through the port fallback and batches are synthesized
(capabilities false)
- the no-consumer durability case is disabled for this adapter with the
design §13.8 reference: MQTT 5 leaves retention for an offline shared
subscription to the broker (HiveMQ CE drops; EMQX-class brokers may
retain) — the capability matrix documents the variance
- tck harness against hivemq-ce, or TCK_MQTT_HOST/TCK_MQTT_PORT for an
externally managed broker
Phase 3 (1/4): ActiveMQ (Artemis / Classic, JMS 2.0) adapter for
dc3.mq.type=activemq, TCK 11 pass + 1 documented skip.
- live topics map to JMS topics: LOAD_BALANCE rides a shared durable
subscription named after the consumer group (competing consumers share
it, offline messages retained), BROADCAST rides a plain per-instance
consumer — one publish fans out to every subscription like an exchange
- dead-letter destinations are queues; reject(false) republishes to
dc3.<topic>.dlq and acknowledges, reject(true) recovers the session
- delays use JMS scheduled delivery natively (capability true); batches
are synthesized by draining the consumer with the shared synchronous
bounded-retry semantics; exhaustion dead-letters instead of dropping
- JMS property names must be java identifiers, so the dashed standard
headers ride underscored and are restored on read
- best-effort publisher confirmation (capability false): the synchronous
persistent send returning is the reported signal
- tck harness against apache/activemq-artemis, or TCK_ARTEMIS_URL for an
externally managed broker; subscriptionExpiry documented false
Phase 2 of the mq abstraction design: the acceptance bar (TCK) plus the
kafka adapter, both passing the full contract suite against live brokers.
dc3-common-mq-tck (contract suite, reusable by community adapters):
- abstract 12-case suite covering round-trip envelope fidelity, load
balance exactly-once across instances, broadcast fan-out, delay via the
port fallback, reject-to-dead-letter, reject-with-requeue redelivery,
sendAsync confirmation, 100-message burst, batch ack committing the
whole batch, retry exhaustion dead-lettering instead of dropping,
durability while no consumer runs, and per-instance subscription expiry
- rabbitmq and kafka harnesses on testcontainers 2.x, skipped gracefully
without a container runtime; kafka harness also honors TCK_KAFKA_BOOTSTRAP
for externally managed brokers (testcontainers 2.0.5 configures
apache/kafka 3.9.0 with a nonroutable advertised listener on some runtimes)
- per-run unique consumer groups plus post-subscription settle keep runs
isolated on log-based brokers with auto.offset.reset=latest
dc3-common-mq-kafka (adapter, dc3.mq.type=kafka):
- topics map to dc3.<topic>; logical dead topics map to dc3.<topic>.dlq so
rejects and dead-letter subscriptions land on the same topic
- partition key becomes the record key (per-key ordering); LOAD_BALANCE
rides consumer groups, BROADCAST uses per-instance group ids
- auto.offset.reset=latest mirrors the rabbit fresh-queue semantics: a new
group only sees messages published after it joins
- batch delivery with synchronous bounded retry and backoff mirroring the
rabbit stateless retry advice; exhaustion republishes the whole batch to
the dead-letter topic and commits instead of dropping silently (spring's
DefaultErrorHandler committed exhausted batches without publishing)
- non-poison failures on single deliveries nack for redelivery; poison
messages are republished to the dead-letter topic and acknowledged
rabbit adapter adjustments surfaced by the suite: delayedMessage capability
is now false (only the intrinsic TTL+DLX topics delay server-side; arbitrary
delays go through the port fallback), POINT_VALUE_DEAD is subscribable for
dead-letter auditing, spec instanceTtl overrides the configured queue
expiry, subscriptions with a named group get a group-suffixed copy of the
platform-shared queue (blank group keeps the pre-port names), and shared
topology moved to a descriptor table
Verified: RabbitMQ 12/12 and Kafka 11+1-skipped against live brokers via
podman; constant/data/driver/manager unit suites unchanged and green.
Complete phase 1 of the mq abstraction design: business code compiles
against the broker-neutral port with zero amqp classes, and the legacy
dc3-common-rabbitmq module is deleted.
- dc3-common-driver: 8 sender methods plus the sqlite outbox now publish
through MessageSender (outbox keeps durability; legacy physical routing
keys in pending rows are normalized on republish); metadata/command/
point-command receivers become @Dc3Listener subscriptions with
placeholder-driven per-instance queues; DriverTopicConfig dissolved into
adapter subscribe-time declarations
- dc3-common-data: command and point-command dispatch use sendConfirmed
with the correlation-id header; state timeout, device scan tick, notify
tasks and metadata events send through logical topics; all 13 receivers
including the batch point-value consumer migrate to @Dc3Listener;
DataTopicConfig, PointValueRabbitConfig and the duplicated batch
properties class move into the port/adapter (same config keys)
- dc3-common-manager / facade-local-manager: metadata fan-out via the port
- dead-letter consumers read the correlation id from the standardized
header the adapter mirrors onto the amqp property
- 14 test classes adapted to the new listener/sender shapes; module poms
swap dc3-common-rabbitmq for dc3-common-mq + dc3-common-mq-rabbitmq
Verified: unit suites green for constant (291 incl. boundary guard),
data (165), driver (144), manager (255); full-repo main and test compile
green. Container-backed E2E (RabbitDeliveryIT) intentionally not run here.
Introduce the pluggable message broker layer from the mq abstraction
design. Existing rabbitmq deployments keep their topology byte-for-byte.
dc3-common-mq (port, zero broker dependencies):
- MqTopic logical destinations, JSON envelope with standardized headers
(dc3-type, X-Request-Id via MDC/OpenTelemetry, correlation id)
- MessageSender send/sendAsync/sendConfirmed plus local-scheduler delay
fallback for brokers without native delayed delivery
- @Dc3Listener annotation processor: resolves payload types from method
signatures, resolves ${...} placeholders in keyPattern/group, restores
the request id into the MDC around every invocation
- SubscriptionSpec (mode, profile, delivery, keyPattern, group) and
BrokerCapabilities negotiation logged at startup
dc3-common-mq-rabbitmq (adapter, dc3.mq.type=rabbitmq, default):
- RabbitNames replicates the pre-port physical names exactly, including
the historical tag inconsistency between routing-key families
- RabbitTopology declares exchanges/queues/bindings programmatically with
identical TTL, dead-letter and binding-argument details; driver-side
per-instance queues are declared on subscribe with lease-coupled x-expires
- one listener container per subscription: latency 2/8/10, throughput
4/32/100, batch consumer replicated from the point-value factory
(prefetch >= batchSize, batch-level bounded retry, exhaustion dead-letters)
- stamps legacy __TypeId__ for rolling upgrades and mirrors the correlation
id onto the AMQP property for dead-letter consumers
Shared enums (MqTopic, SubscriptionMode, ConsumptionProfile, DeliveryMode,
OrderingGuarantee) live in dc3-common-constant per the module boundary
guard. The legacy dc3-common-rabbitmq module is retired in the next
commit; both coexist so this commit stays independently buildable.
- Replace obsolete nexus-staging-maven-plugin with central-publishing-
maven-plugin in dc3-api and dc3-common
- Remove 20 redundant version declarations from dc3-coverage dependencies
- Fix snmp4j version from non-existent 3.8.3 to available 3.7.4
## Common Foundation
- dc3-common-sql: AbstractJdbcDriverCustomService base class with HikariCP
pool management and JDBC template methods
## Serial & General-Purpose (3)
- Serial: RS232/RS485/RS422 with configurable frame parsing (CRC16/XOR)
- HTTP: REST Client using Spring WebClient with JSON path extraction
- TCP/UDP Raw: generic socket driver with pluggable frame protocol
## Database Drivers (4)
- MySQL, PostgreSQL, Oracle (SID/ServiceName), SQL Server
## IoT & Wireless Protocols (3)
- LwM2M: Eclipse Leshan 2.0.0-M14 with CoAP server and device observation
- Zigbee: Z-Smart Systems 1.4.16.1 with Telegesis dongle support
- BLE: Sputnikdev Bluetooth Manager 1.5.3 with TinyB transport
## Building Automation & Smart Metering (2)
- BACnet IP: BACnet4J 6.0.1 with ReadProperty/WriteProperty support
- DLMS/COSEM: Gurux DLMS 4.0.79 for smart metering (TCP/Serial transport)
## Industrial & Power Protocols (4)
- IEC 104: OpenMUC j60870 1.7.2 for power telecontrol
- SNMP: SNMP4J 3.7.4 for network device monitoring
- EtherNet/IP: CIP Data Table Read/Write for Rockwell AB PLCs
- FINS: Omron PLC memory area read/write over TCP
## Automotive & Fieldbus (1)
- CAN Bus: SocketCAN interface with standard/extended frame support
## Build
- Register all 17 driver modules and dc3-common-sql in parent POMs
- Add version properties and dependencyManagement entries
Maven dependencyManagement does not flow across the iot-dc3 root reactor
into dc3-common because dc3-common inherits from the externally
published dc3-parent. As a result, dc3-common-test could not resolve
JUnit 5 / Testcontainers / Instancio dependencies and dc3-e2e could not
resolve dc3-common-test itself.
Mirror the relevant slice of test-toolchain version management into
dc3-common/pom.xml (junit-bom + testcontainers-bom imports plus pinned
versions for AssertJ, Awaitility, Instancio, REST-assured and WireMock)
and add the missing dc3-common-test version entry to the iot-dc3 root
dependencyManagement so the e2e module can import it.
Verified locally with mvn -B clean compile -pl dc3-common/dc3-common-test -am,
which now resolves all 9 source files and produces
dc3-common-test-2026.5.5.jar.
Bootstrap dc3-common-test, a new infrastructure-only Maven module under
dc3-common that ships:
- Reusable Testcontainers wrappers for the production-aligned
timescale/timescaledb-ha:pg18 image, RabbitMQ with publisher confirms
and Eclipse Mosquitto MQTT broker.
- JUnit 5 support beans: a fixed Clock configuration, an in-process gRPC
extension, an Awaitility-backed Rabbit harness and JSON assertion
helpers.
- Reusable contract base classes for domain enum index round-trips and
for asserting that secret-bearing fields never leak through Lombok
toString() output.
- A test profile (application-test.yml) and logback config aligned with
the production RabbitMQ confirm/return semantics.
Module-specific fixtures that depend on business BO/VO/DO types are
deliberately deferred to their owning modules' src/test trees to avoid
introducing reverse dependencies into dc3-common-test.
This commit only adds the new module; no other module consumes it yet.
The test BOM and plugin wiring that exposes it as a test-scope artifact
to the rest of the tree lands in a follow-up commit.
- Move dc3-common-facade-api, dc3-common-facade-grpc, dc3-common-facade-local
under new dc3-common-facade aggregator pom
- Split dc3-common-facade-local into dc3-common-facade-local-auth and
dc3-common-facade-local-manager for cleaner dependency scoping
- Update root pom.xml and dc3-common/pom.xml dependency management
- Update dc3-center-auth to use dc3-common-facade-local-auth
- Update dc3-center-single facade-local dependency type to pom
Adds a startup-time registrar that scans the local WebFlux handler mappings
of each center service and reconciles the discovered endpoints against
dc3_api and dc3_resource (insert-if-missing, update-if-drifted, soft-delete-
if-orphaned), so the permission model is no longer hand-maintained.
Wiring:
- dc3-common-resource-registrar (new module): scanner, diff runner, Spring
Boot AutoConfiguration. Activates on ApplicationReadyEvent.
- dc3-common-facade-api: ResourceRegistryFacade + BOs define a transport-
neutral sync contract.
- dc3-common-facade-local / dc3-common-facade-grpc: two implementations
selected via dc3.facade.mode. center-auth/single use local; manager/data
call auth via gRPC.
- dc3-common-auth: biz-side ResourceRegistrySyncService performs the three-
way diff inside a transaction guarded by pg_advisory_xact_lock(hashtext
(serviceName)); exposes ResourceRegistryApi gRPC server.
- dc3-api-auth: new resource_registry.proto contract.
- ApiDO/BO/VO/Query gain a serviceName field so each service's endpoints
can be located with a single indexed lookup.
Deployment-visible changes:
- api_code format is the human-readable serviceName:METHOD:/path
- dc3_resource.resource_code format is api:serviceName:METHOD:/path
(prefixed namespace reserved for future resource types)
- center-auth application.yml sets dc3.facade.mode=local
- 4 center pom.xml files pull in the registrar (auth also gets facade-local)
Adds three new modules that let business code call center services
through protocol-neutral interfaces instead of @GrpcClient stubs:
- dc3-common-facade-api: Device/Driver/Point + Tenant/User/UserLogin/Token
facade interfaces plus facade-owned BO/Query/Page types
- dc3-common-facade-local: in-process implementations backed by the
auth/manager services; zero serialization cost in single deployments
- dc3-common-facade-grpc: gRPC implementations holding BlockingStubs;
default mode for distributed deployments
Implementation selection is driven by dc3.facade.mode={local|grpc} via
@ConditionalOnProperty, with grpc as the matchIfMissing default. Wire-up
for dc3-center-single (dc3.facade.mode=local + facade-local dependency)
is included so the single-deployment mode is runnable out of the box.
- Consolidate 19+ individual DC3 module version properties into single <dc3.version>
- Remove redundant <scope>compile</scope> from DC3 Api dependencyManagement entries
- Reorder elements: modules before properties, profiles after dependencyManagement
- Fix <scm> connection/developerConnection to use scm protocol prefix
- Fix <inceptionYear> from range '2016-2022' to correct single year '2016'
- Bump all module versions from 2025.11.1 to 2026.4.18.3
- Remove orphaned dc3-common-influx dependency and property from root pom.xml
- Standardize dependency comment style in dc3-common/pom.xml
- Merge gRPC dependency groups into single section in dc3-common-api
- Restructure Spring Integration MQTT and Eclipse Paho groups in dc3-common-mqtt
- Fix incorrect comment 'DC3 Common Exception' to 'DC3 Common Related' in dc3-common-postgres
- Add missing blank line before </dependencies> in dc3-common-driver
- Remove stray blank line in root pom.xml dependencyManagement