- driver replicas are per-instance nodes with their own RabbitMQ
command queues (group=dc3.driver.client, key service.node), not
workers over shared queues; FAQ now also states Compose/Swarm keep
protocol drivers at 1 replica (shared driver_data / SQLite outbox)
- fail-fast gate covers AUTH_HMAC_SECRET only; DC3_SECURITY_KEY is
non-empty-checked, so a weak default still boots
- 6271 is intended as the device UDP channel but every publish site
omits /udp / protocol: UDP and actually publishes TCP - say so
- k8s scaling note: scaled driver pods are independent nodes, not one
shared worker pool
- swarm runbook: pushing dependency images is a multi-node requirement,
a local build is fine on a single node
- USAGE.md: NODE_ENV bullet narrowed to weak AUTH_HMAC_SECRET rejected
Translate the seven remaining English documents under docs/ in place,
preserving all technical content, code blocks, identifiers, links, and
decision IDs (D1-D19, F1-F15, P0-P5). Add a categorized Chinese
navigation index (docs/README.md) with per-document summaries, the
storage supersession chain, and task-based reading paths.
Approved design for replacing MyBatis-Plus + JDBC with Spring Data R2DBC,
auth center as the pilot. Records the verified fact base (F1-F15), the
D1-D19 decision checklist (per-dialect repository modules, TCK discipline,
compile-time tenant scoping, facade/gRPC blocking edge, timestamptz codec,
workerId allocation rule), and the P0-P5 phased plan with the P2-P3
go/no-go gate. Supersedes storage-abstraction.md section 3 (relational
half); its TSDB half was already superseded.
Replace limit-truncated listing with real server-side paging
(LIMIT/OFFSET plus a shared count query) behind Page envelopes:
tool/list accepts a nested Pages block and audit/list takes
current/size params, both keeping the legacy limit as a compatibility
page size. The frontend configs forward pager state and consume
{records, total} instead of faking a single page; the assignment
drawer keeps its full-catalog semantics with one 500-row page (the
service cap). Adds a mapper XML grammar gate and audit page/count
symmetry tests.
Co-Authored-By: Claude <noreply@anthropic.com>
The "(? IS NULL OR ? = '' OR ...)" filter shape breaks on Postgres with
stringtype=unspecified: a bare bind parameter in an IS NULL context has
no inferable type, so opening the MCP tool page with a blank risk-level
filter failed with "could not determine data type of parameter $1". The
dynamic <if> form drops the dead branches entirely and is
dialect-neutral, so the mysql/mariadb forks of the statement are gone.
Co-Authored-By: Claude <noreply@anthropic.com>
The history JDBC url sets only currentSchema=dc3_history, so any
object the history connection must resolve outside its own schema
(extension functions, shared types, public tables) fails with the
default search_path stripped to a single entry. Append public to the
currentSchema list across the dev/pre/pro/test profiles so unqualified
names in the history route resolve against dc3_history first and fall
back to public, matching standard PostgreSQL search-path semantics.
Co-Authored-By: Claude <noreply@anthropic.com>
Extract the header language switch into a reusable AppPreferences
component and add a light/system/dark theme toggle beside it, backed by
the persisted app store theme mode. Use the component in both the
console header (compact) and the login page (surface variant) so the
public page obeys the same theme contract as the workspace.
Tokenize the login page palette in theme.scss with dark-mode twins,
switch the login validation rules to computed form rules so messages
follow locale changes, and extend the layout component test and the
login/responsive e2e specs for the new controls.
Co-Authored-By: Claude <noreply@anthropic.com>
Bump pnpm to 11.24.0 and refresh element-plus, axios, dayjs, dompurify,
marked, pinia, vue-i18n, playwright, typescript-eslint, eslint, sass,
vite and vitest within their minor lines, and widen the pnpm-workspace
onlyBuiltDependencies ranges accordingly.
Keep typescript on ~6.0.3, vue on ^3.5.40 and happy-dom on ^20.11.0:
typescript 7 drops the ./lib/tsc subpath vue-tsc still resolves, vue
3.5.41 makes compiler-sfc require filesystem access for imported prop
types under the vitest environment, and happy-dom 20.11.6 changes the
execCommand clipboard behaviour the utils suites assert on.
Co-Authored-By: Claude <noreply@anthropic.com>
affectData is not declared for insert by the MyBatis mapper DTD, so
the attribute only surfaces as a startup error after the affected
module deploys. Remove it from every upsertLeaseState variant and
document that the atomically advanced assignment version is re-selected
in the same transaction rather than returned.
Add ManagerMapperXmlGrammarTest to parse every mapping/*.xml against
the bundled DTD so future invalid attributes fail the build instead of
application startup.
Co-Authored-By: Claude <noreply@anthropic.com>
The auth filter sits in front of the routing chain, so TCP connect
refusals and timeouts propagate through it and masquerade as an
authentication failure answered with 500. Classify ConnectException
and ConnectTimeoutException (including wrapped causes) as downstream
unavailability and answer 503 Service Unavailable instead.
Co-Authored-By: Claude <noreply@anthropic.com>
Spring Boot 4 moved EnvironmentPostProcessor from
org.springframework.boot.env to org.springframework.boot, so the
spring.factories registration under the old key no longer loads
ActiveRabbitProfileConfig and RabbitEnvironmentConfig and the
rabbit profile defaults silently disappear.
Co-Authored-By: Claude <noreply@anthropic.com>
The tsdbDataSource bean breaks by-type injection: the dynamic routing
dataSource carries no @Primary, so a candidate-eligible second
DataSource throws NoUniqueBeanDefinitionException in consumers that
cannot take a qualifier (MyBatis-Plus sqlSessionFactory, Quartz, the
health check). Mark it defaultCandidate = false so those consumers see
exactly one candidate again while the TSDB adapter keeps resolving it
through @Qualifier("tsdbDataSource").
The same second bean makes @ConditionalOnSingleCandidate(DataSource)
fail, so DataSourceTransactionManagerAutoConfiguration silently backs
off and no TransactionTemplate is auto-configured. Declare the
DataSourceTransactionManager explicitly, bound to the routing
datasource with local-transaction semantics: switching routes inside
an open transaction does not take effect.
Co-Authored-By: Claude <noreply@anthropic.com>
Refresh the wrapper scripts to wrapperVersion 3.3.4 (only-script
distribution) and move distributionUrl from 3.9.11 to 3.9.16, the
newest 3.9.x release. Pin line endings for mvnw, mvnw.cmd and the
wrapper properties in .gitattributes so the scripts stay executable
across platforms.
Co-Authored-By: Claude <noreply@anthropic.com>
- 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>
- include dc3-db in the make deploy artifact set alongside common/mq/tsdb
- sample DC3_DB_TYPE/DC3_TSDB_TYPE and external-store ports in .env.example
- expose mysql/mariadb/tdengine/influxdb/iotdb/jaeger in the compose stacks
- update AGENTS.md module map and module-ownership guidance
- add the missing AGPL header to the oracle driver service
- let TSDB failures propagate in the alarm window data source: swallowing
them made an outage read as no-data and silently missed alarms
- dedupe ingest batches by natural key before store upserts (same-row
writes poison timescale ON CONFLICT batches)
- turn unsupported countByDimension into a structured refusal (analytics)
or capability-honest empty panel (dashboard) instead of a raw 500
- pin LocalDateTime.now to DEFAULT_ZONEID on the tsdb read paths
- adapter fixes: influxdb/iotdb/tdengine/timescale store and auto-config
corrections, iotdb system properties, capability declarations on
TsdbStore, new timescale store unit tests
- derive pagination DbType from the selected dc3-db adapter with a fail-fast
when a non-default dc3.db.type lacks its adapter jar
- skip postgres profile activation for mariadb, not just mysql
- fork OAuthMcpMapper/AlertMapper statements for mysql and mariadb
(CAST AS JSON, ::text casts, ODKU value references)
- honor GET_LOCK verdict in resource registry sync instead of assuming
acquisition on every engine
- pg2mysql_seed.py: convert partial unique indexes to stored generated guard
columns instead of dropping them; add 99-iot-dc3-grants.sql
- add DC3_DB_URL/DC3_DB_HISTORY_URL per-service overrides in center configs
- cover the new mapper forks in the db TCK; fix AGPL headers in spring
metadata files
- add KeyMatcher/KeyRoutes: client-side topic router for brokers without
binding-level key filtering, with wildcard unit tests in dc3-mq-core
- stamp a dc3-partition-key header mirror for brokers with no native key
field (mqtt user property, jms string property)
- drop the unused RetryPolicy; batch redelivery is governed by the batch
consumer retry settings
- align adapter configurations, error messages, and the Pulsar contract
test with the dc3-mq-* module names
- add the canonical AGPL header to the six agentic application yml files and the two python scripts that lacked one
- add the header to all 79 kustomize, helm, and grafana yaml files, including the k8s driver template which regenerates the 36 driver manifests
- verified: the k8s yaml files parse (multi-document aware), the python scripts compile, and the regenerated drivers differ only by the header
- translate the banner template documentation and protocol-mesh comments in the eight localized banners, the template, and the social preview
- keep the localized tagline copy inside the comment blocks (it documents the LANGS table values)
- verified: all nine svg files parse as xml and the template placeholders remain intact
- add JSDoc to useEntityListPage, useEntityNames, usePagedList, and the four Pinia stores
- add JSDoc to 39 utils exports across thingModelFormat, formRule, validation, date, json, pointFormat, and searchParam utilities
- verified: pnpm check and pnpm lint:check pass
- fill the missing Javadoc on public methods, records, and types across the dc3-common, dc3-mq, and dc3-tsdb core modules
- document about 350 public constants and enum constants in dc3-common-constant, including the MCP, RabbitMQ, agentic, manager, auth, and data surfaces
- document exception constructors and replace the lombok @RequiredArgsConstructor with explicit documented constructors in ThreadPoolConfig and QuartzService
- translate the remaining non-English section comments in the TSDB store adapters
- verified: check_documentation.py passes, javadoc doclint=all reports zero warnings across all aggregators, and the touched modules compile
- add READMEs for the dc3-mq core, six broker adapters, and the contract suite
- add READMEs for the dc3-tsdb core, four store adapters, and the contract suite
- add READMEs for the dc3-db core, three dialect adapters, and the contract suite
- add ble, can, dlt645, dnp3, iec61850, kafka, knx, lorawan, mbus, redis, and zigbee to the k8s driver list, kustomization, helm values, and compose service stacks
- regenerate k8s driver deployments and preserve the listening-virtual ports in the generator
- replace the per-driver named volumes with one shared driver_data volume isolated by mount path, matching the scale/swarm stacks
- correct scaling docs: compose scale/swarm drivers stay at one replica because replicas would share one SQLite outbox file
Follow-up review of the comment pass found three spots where new
javadoc landed next to pre-existing blocks:
- AnalyticsModel: SeriesSelector/TimeRange/HistoryPoint carried the same
doc twice (the batch injector did not notice the originals).
- MybatisPlusConfig: an orphaned copy of the old mybatisPlusInterceptor
doc sat above databaseIdProvider's own javadoc.
- EntityStateMapper: the parameter javadoc of the retired
claimExpiredDevices method was left dangling above
selectExpiredForClaim's doc.
All three removed; the original mybatisPlusInterceptor doc survives
(the one-line summary I added earlier was replaced by restoring the
full contract note in place). Verified by a repository-wide scan for
adjacent javadoc pairs — now zero. data suite green, compile green.
A comment-health audit driven by an AST scanner (regex scanners kept
false-positiving on annotation-separated javadoc; the AST pass with
constructor and @Override-implementation exemptions is what produced a
trustworthy worklist) ended with a much smaller true gap than the raw
numbers suggested: class-level javadoc is already at 100% repository-wide.
What actually gets filled here:
- AnalyticsModel: all 30 nested records of the S19 analytics facet get
maintainer-voice javadoc (the @Schema descriptions serve the API side;
these serve code readers).
- The whole entity/ext family (29 files, 47 nested classes): every
Content/Ui/Validation/Security/AppliesTo/Template/Dedup/... schema
class states what it actually holds — read from the fields, not
templated.
- Adapter families: the @Bean methods of all six MQ adapters, all four
TSDB adapters and the three DB dialect adapters get one-line
maintainer docs (what binds to what, what is overridable).
- Nested support types across data/agentic/constant/public/facade:
NotifyBindKey, CacheTuning, Credential, dashboard VOs' Item/BucketVO,
ExpireListener (plus its null-doc placeholder javadoc replaced with a
real contract), agentic chat/stream VOs' choice/delta/usage shapes,
tool-context records, RequestHeader envelopes, FleetSummary,
visualization Type/Scale codes.
- PointValueSampleConverter's boundary methods now state the port-side
contract (quality default injection point, batch order preservation).
Comment drift fixed: the class javadoc of the can/mqtt/opc-da driver
skeletons claimed "see TODO markers in method bodies" — those markers
do not exist; the claims are corrected to plain work-in-progress notes.
The genuine TODOs (zigbee API verification, lwm2m lookup, ethernet-ip
CIP framing, CAN JNI) stay: they mark real unimplemented behavior.
Vendored-code boundary: the opc-da module carries a ported
org.openscada library (46 files, package org.openscada.*). Its trivial
accessors stay bare on purpose — filler comments on get/set pairs are
exactly the kind of noise this pass exists to remove — but the
non-obvious JIStruct wire-decoder methods (getStruct/fromStruct
FILETIME + three DO wrappers) now document the COM bridge shape.
Gates: full-repo compile green; data/model/constant/agentic/public
test suites green.
Apply queryTimeout as a statement timeout instead of a connection timeout, validate point queries against the point read/write flag, close all connection pools on driver metadata events, and remove the unused DriverSenderService dependency. Rename the module unit test so surefire executes it (26 tests) instead of excluding it via the Abstract* pattern.
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.
dc3-db-mariadb brings MariaDB 10.6+ behind dc3.db.type=mariadb with the
official mariadb-java-client and the same dual-dialect contract suite.
MariaDB shares the MySQL seed wholesale (utf8mb4_unicode_ci — the 0900
collation is MySQL-8-only and MariaDB rejects it outright, so the seed
translator and the hand-written 05 both moved to the portably-supported
collation, re-verified against mysql:8.4).
The mapper forks differ from the mysql twins in exactly one dimension,
verified against a live 10.11 container first: MariaDB never adopted
the AS-new ODKU row alias (syntax error on 10.11), so its 15 twins
reference VALUES(col) instead — everything else (GET_LOCK/RELEASE_LOCK,
FOR UPDATE SKIP LOCKED, recursive CTEs, INTERVAL ? SECOND, the
JSON_UNQUOTE(JSON_EXTRACT(...)) double-hop, REGEXP_REPLACE without the
g flag, DAYOFWEEK/HOUR units) proved compatible and rides the same
statement bodies.
Scope decision recorded in docs/db-dialects.md: DB2, H2 and HSQLDB are
explicitly out (dialect cost with zero demand; embedded test databases
unfit for multi-service concurrent IoT writes), SQLite equally unfit
for the multi-service shape (database-level write lock, no network
listener). Oracle and SQL Server stay on the roadmap with their real
obstacles spelled out (MERGE-heavy rewrite; no ARM64 mssql image for
local certification on Apple Silicon) — not started without a demand
signal.
Gates: db-tck 24/24 (postgres + mysql + mariadb, 8 each),
data/auth/manager suites green (274 in data), full-repo compile green.
R2c of docs/design/storage-abstraction.md §3. dc3-db-tck runs one set of
mapper-level assertions against both engines with the real mapper XML —
the databaseIdProvider routing is part of what gets certified, not just
the SQL: the fenced latest-value upsert's three-level tiebreak (fencing
token, then time, then sequence, then message id), the state upsert +
same-transaction re-select shape, the three-step expired-lease claim
(lock-and-read FOR UPDATE SKIP LOCKED, flip offline, derive the
post-update view), the lease upserts' row-local increments (token moves
only on ownership change), the row-level revision triggers (insert and
meaningful update bump, trivial update does not), and the tool-catalog
query's encoded-JSON double-hop.
Harness notes worth keeping: one SqlSessionFactory per database mirrors
the production @DS wiring (state/latest/leases/catalog span four
databases with unqualified table names); the mapper XML loads through
XMLMapperBuilder with the affectData mybatis-plus DTD extension
stripped; postgres registers the timestamptz type handler. Both
harnesses learned to distrust podman: log-following never fires, so
mysql waits on the listening TCP port and postgres polls a real JDBC
handshake (the port opens during initdb's local-only phase and closes
again for the restart). The postgres harness mounts seed files 01..07
individually — 00's age/pgvector extensions exist only in the
production base image — with 05 trimmed at runtime to the
dc3_point_latest projection (the hypertable half needs the base
image's TimescaleDB function set; the dialect contract doesn't touch
it).
The catalog fixture plants its api row through a parameterized insert:
the escaped-JSON value must not travel through SQL text (MySQL's
default backslash escapes eat the \" the value depends on) nor bind
uniformly (PG rejects varchar->json, MySQL rejects the binary
Types.OTHER binding) — the fixture branches on the engine.
Selection guide published at docs/db-dialects.md (dialect matrix,
swap procedure, the semantic decisions the suite locks); the storage
design's status header moves to Implemented with an R1/R2 closeout
note.
Gates: db-tck 16/16 (8 postgres + 8 mysql), data/auth/manager suites
green (274 in data), e2e 26/26, full-repo compile green.
Remove the unused highlight.js plugin and four dead dependencies, switch Element Plus styles to per-component imports, split marked/dompurify/vue-element-plus-x into a lazy agentic-vendor chunk, and restore the 500 kB chunk warning limit.