3427 Commits
Author SHA1 Message Date
pnoker 50fb953aa2 fix(web): normalize spacing and radii to the dc3 token scale
- Move the login page spacing and radii onto the 4/8/12/16/24/32 token
  scale (shell paddings, form gaps, input radii, mobile breakpoints)
- Align shared form containers: edit-card margins, card-footer gap,
  matrix toolbar footer, breadcrumb strip, dropdown identity row
- Normalize card internals to tokens: StatCard row gap, DashboardCard
  title bar, AlertList group padding, home widgets, NavMenu items,
  things-dialog body, MCP/role/user assign views, point value card
2026-09-02 03:14:01 +08:00
pnoker d4d98ad8a2 fix(web): align card and block spacing on the 8px grid
- Use the 8px page gutter (--dc3-space-2) for home row rhythm, the stat
  grid gap, and the SLA strip margin so vertical spacing matches the
  horizontal card gutters
- Normalize the home banner internals to the token scale: 16px body
  padding and area gap, 8x16 clock box, 8x12 service chips
- Normalize the SLA strip padding/radius and chip spacing to tokens
- Align things-card vertical margin with its documented 8px rhythm so
  settings grids match the horizontal gutter
- Unify the two 12px form gutters and the breadcrumb strip padding on
  the same scale
2026-09-02 02:37:26 +08:00
pnoker d43a6c4d0f chore(web): add dev:mock script for static demo mode 2026-09-02 02:22:15 +08:00
pnoker 86a9ae1399 feat(web): unify brand lockup, capsules, and account menu
- Extract a shared BrandLockup (logo, gradient wordmark, AGENTIC tag,
  signal line) used by both the header brand capsule and the login page
- Add a shared glass-capsule SCSS recipe so the header capsules and the
  login brand pill keep identical geometry and glass decoration
- Align the login page with the workspace font stack
- Reduce the account trigger to an avatar and move the username into a
  themed identity dropdown with divider; style the popper with dc3
  tokens so light and dark themes both follow the system theme
- Point the About action at the live site domain (https://dc3.site)
2026-09-02 02:22:02 +08:00
pnoker 51edc7c198 refactor(common): rename resource registrar module 2026-09-01 23:42:00 +08:00
pnoker 6591982b8a test: run broker and database contracts as integration tests 2026-09-01 23:41:40 +08:00
pnoker 0c10f71951 build: eliminate Maven package warnings 2026-09-01 23:41:21 +08:00
pnoker eae86b58fc refactor(storage)!: unify platform persistence on reactive postgresql
- 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.
2026-09-01 22:03:16 +08:00
pnoker 39ab556f6e test(gateway): cover oauth bearer ticket resolution in auth filter 2026-09-01 22:03:15 +08:00
pnoker 436c979fe9 feat(cli): agentic session lifecycle and action approval commands
dc3 session (list/get/messages/rename/delete) over the conversation
routes and dc3 action (pending/confirm/reject) for the high-risk
tool-call approval loop, closing the last P0 coverage gap from the
2026-08-27 audit. Six suites assert path shaping, query encoding and
method selection.
2026-09-01 22:03:15 +08:00
pnoker d9c7730da3 docs(cli): document analytics and alert deep-analysis commands 2026-09-01 22:03:15 +08:00
pnoker 1b6903cdfb feat(cli): analytics group and alert deep-analysis surface
- dc3 analytics run <op> --args posts to the nine /api/v3/data/analytics
  operations (S19 agent face); analytics list prints the catalog
- dc3 alert gains activity/storm-sources/flapping/correlation/
  peer-deviation/aging/mtta/change-impact (GET), latency, silent-sources,
  coverage-gap and bulk-confirm, with snake_case param mapping and
  generic k=v passthrough
- seven new suites cover path shaping, param mapping, passthrough,
  bulk body verbatim and op validation
2026-09-01 22:03:15 +08:00
pnoker 16733c806b docs(design): close /mcp verification debt; greenlight oauth gateway flag 2026-09-01 22:03:15 +08:00
pnoker 865e6352f0 feat(gateway): expose oauth flag via compose; keep legacy header ctor
- gateway container env passes DC3_GATEWAY_OAUTH_ENABLED/JWKS_URL so
  deployments can turn RS256 verification on without image changes
- PrincipalHeader regains a 7-arg constructor delegating scopes=null,
  keeping ~15 existing call sites compiling against the new field
2026-09-01 22:03:15 +08:00
pnoker d4302a541f build: declare mybatis-plus-spring and add cli ci workflow
- dc3-common-auth imports com.baomidou.mybatisplus.spring.service
  directly since the 3.5.17 split but never declared the artifact;
  out-of-reactor consumers hit FileNotFoundException at boot. Manage
  it in the root BOM alongside the existing entry.
- ci-cli.yml gates dc3-cli (lint, test, build, help smoke) on PRs
  touching dc3-cli/**
- adapt AuthenticGatewayFilterTest to the extended constructor
2026-09-01 22:03:15 +08:00
pnoker 31e278c005 fix(cli): restore login against cookie-based token contract
- generate responses now acknowledge with data:"ok" and deliver the
  ticket via the dc3-token cookie; extractTicket prefers a JWT-shaped
  body (June-era builds) and falls back to the cookie
- setProfile validated an empty template instead of the merged value,
  crashing every config write on profiles lacking username; validate
  the merge instead. Live-verified end to end against auth+gateway
2026-09-01 22:03:15 +08:00
pnoker 81d4fe2c37 docs(design): record live regression results for token unification 2026-09-01 22:03:14 +08:00
pnoker 0cc4635f2a docs(design): note first phase-3 slice in cli dual transport 2026-09-01 22:03:14 +08:00
pnoker cff9af8764 feat(cli): dual-transport tools command group over /mcp
First Phase-3 slice: dc3 tools list/call speak JSON-RPC to POST /mcp
with the same Bearer ticket as REST, reading the live tool catalog
instead of hard-coded paths. Requires an oauth-type login; classic
tickets get a clean exit-code-3 auth error. Five unit suites cover
request shaping, scope rejection, rpc errors and the 401 challenge.
2026-09-01 22:03:14 +08:00
pnoker 61db55da6c docs(design): record phase 2 partial landing (projection + ttl ladder) 2026-09-01 22:03:14 +08:00
pnoker d1ccd51cbb feat(auth): derive oauth scopes from rbac and lengthen read-only ttl
Phase 2 of token-unification-mcp-first-cli.md:

- capScopesByRbac narrows requested scopes at authorization time to
  what the principal's bound resources cover via the tool catalog
  (additive per risk class; never widens). principals with no
  bindings degrade to legacy behaviour so incomplete RBAC setups
  cannot silently zero out clients; toggle dc3.oauth.rbac-scoped-scopes
- risk-ladder lifetime: call-capable tickets keep the 15m default,
  list/read-only tickets get a new readOnlyAccessTokenTtl of 1h
2026-09-01 22:03:14 +08:00
pnoker 2d2654dddf docs(design): mark phase 1 of token unification implemented 2026-09-01 22:03:14 +08:00
pnoker fe251825fe feat(cli): add hidden oauth client_credentials login
dc3 auth login --oauth exchanges a registered MCP client id/secret
for an RS256 access ticket at /oauth2/token and stores it as an
oauth-type state whose requests travel as Authorization: Bearer.
Renewal is intentionally not attempted without a stored secret;
expiry surfaces a clean auth error. Option is hidden from help until
gateway-side RS256 verification is enabled in deployments.
2026-09-01 22:03:14 +08:00
pnoker 270dfb9112 feat(gateway): accept oauth rs256 tickets alongside login tickets
Phase 1 of token-unification-mcp-first-cli.md:

- shared OAuthJwtVerifier in dc3-common-public; auth center's
  parseAccessToken now delegates to it
- gateway TokenResolver chain: optional OAuthTokenResolver verifies
  bearer tickets against a cached JWKS (unknown kid forces one
  refresh) and projects claims onto the extended PrincipalHeader
  (new scopes field); behind dc3.gateway.oauth.enabled, default off
- platform login-token lifetime configurable via DC3_TOKEN_TTL_HOURS /
  dc3.token.ttl-hours; denylist cache follows ttl+1h so revocation
  keeps outliving tokens
2026-09-01 22:03:14 +08:00
pnoker 6c16dfd5f8 docs(design): fix scope projection and consistency gaps in token unification
- projection is additive per risk class: a mixed LOW/HIGH principal
  keeps tools_call; MEDIUM (hidden-until-enabled) now accounted
- qualify high-risk 'no standing grant' to the default path so it no
  longer contradicts the approved --approve-window escape hatch
- note phase-1 ordering: --oauth login can land before the gateway
  resolver chain, behind a flag until REST accepts RS256
2026-09-01 22:03:14 +08:00
pnoker 35e625de9a docs(design): plan console cli onboarding; restore dc3-cli package name
Revert the premature McpServer.vue change (implementation was not
requested). Record the onboarding UX contract in
token-unification-mcp-first-cli.md §4.1 instead, and rename the CLI
package back to dc3-cli per review.
2026-09-01 22:03:14 +08:00
pnoker df42cb9e4c Revert "feat(web): add cli onboarding card to mcp service page"
This reverts commit d253fc8aa9c0f4baaf7e9d47fd8ba0390069c737.
2026-09-01 22:03:14 +08:00
pnoker 65729c4ef2 feat(web): add cli onboarding card to mcp service page
Ready-to-copy shell block (install, set gateway to the current
origin, interactive login) next to the existing agent config
snippets, plus en/zh i18n keys for the new card.
2026-09-01 22:03:14 +08:00
pnoker d5e993bdd7 docs(design): record phase-0 decisions on token unification
Q1-Q4 resolved 2026-08-27: scope vocabulary kept as RBAC projection,
step-up via all three channels (web approval default, CLI tty,
explicit approve-window), cached-JWKS gateway verification, web
retains cookie sessions. Q5 threshold documented as proposed.
2026-09-01 22:03:14 +08:00
pnoker 3d65e0949d docs(design): propose token unification and mcp-first cli rebuild
Add design draft covering:
- verified state of the two parallel auth systems (HS256 login vs
  RS256 OAuth/MCP) and their incompatible verdict points
- gateway TokenResolver chain over an extended X_AUTH_PRINCIPAL so
  both tickets converge on one RBAC-backed permission model
- scope-as-projection of dc3_resource bindings, risk-layered TTLs
  with step-up for high-risk calls
- CLI rebuild around the MCP/OAuth credential mechanism (supersedes
  dc3-client-sdk.md Phase 4) with five open decision questions
2026-09-01 22:03:14 +08:00
pnoker b828719d38 feat(cli): adopt dc3-cli into the repository as a standalone module
Move the previously untracked TypeScript CLI into iot-dc3 as an
independently managed module next to dc3-web:

- pnpm workspace (pnpm@11.24.0) with esbuild build approval,
  package renamed to iot-dc3-cli, npm lockfile dropped
- add eslint flat config; lint now runs green after removing
  unused imports/vars and adding switch-case breaks in config.ts
- document CLI conventions and commands in AGENTS.md
2026-09-01 22:03:13 +08:00
pnoker 987c96d501 docs(deployment): correct factual errors in DEPLOYMENT.md and USAGE.md
- 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
2026-08-28 23:56:08 +08:00
pnoker 843ee444ca docs: translate design and selection documents to Chinese
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.
2026-08-28 02:07:45 +08:00
pnoker 8be0bbc73d docs(design): add relational R2DBC access layer design
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.
2026-08-28 01:19:20 +08:00
pnokerandClaude df35851f3b feat(auth): page mcp tool catalog and audit queries
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>
2026-08-28 00:25:10 +08:00
pnokerandClaude 6bc8b67847 fix(auth): fold mcp catalog optional filters into dynamic predicates
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>
2026-08-28 00:21:52 +08:00
pnokerandClaude d33863cee3 fix(data): widen history datasource search path to public
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>
2026-08-27 09:44:14 +08:00
pnokerandClaude 2085bd17d7 chore(web): ignore local claude settings
Keep .claude/settings.local.json out of version control inside the
frontend workspace.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-27 09:41:18 +08:00
pnokerandClaude fe9384864a feat(web): add theme and language preferences to console and login
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>
2026-08-27 09:40:59 +08:00
pnokerandClaude 691f6c8798 build(web): refresh frontend dependencies
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>
2026-08-27 09:40:41 +08:00
pnokerandClaude 5bcd40b3ac fix(manager): drop invalid affectData attribute from mapper inserts
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>
2026-08-27 09:40:22 +08:00
pnokerandClaude e35a2a301f fix(gateway): answer 503 when the routed backend is unreachable
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>
2026-08-27 09:40:00 +08:00
pnokerandClaude 4e4d62b651 fix(mq): correct the environment post-processor key for spring boot 4
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>
2026-08-27 09:39:45 +08:00
pnokerandClaude c18077d7e2 fix(data): restore transaction management with the tsdb datasource
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>
2026-08-27 09:39:31 +08:00
pnokerandClaude 5c08be18a0 build(wrapper): bump maven wrapper to 3.9.16
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>
2026-08-27 09:39:11 +08:00
pnokerandClaude fb97274691 build(deps): bump spring boot to 4.1.1 and refresh dependency stack
- 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>
2026-08-27 07:47:23 +08:00
pnoker 01ff3a0b38 fix(web): initialize mock before router navigation 2026-08-26 09:44:06 +08:00
pnoker ec2310fa9b feat(web): unify responsive console experience 2026-08-26 09:43:45 +08:00
pnoker a7ca489b9b style(repo): reformat java, xml, yaml, markdown and frontend sources 2026-08-25 21:27:49 +08:00
pnoker 56169842eb docs(design): record three-terminal v5 revision 2026-08-25 21:02:04 +08:00