Commit Graph
1116 Commits
Author SHA1 Message Date
pnoker a558490b95 fix(test): adapt TokenController test to httpOnly cookie auth 2026-08-08 23:40:42 +08:00
pnoker a73ba1267a refactor(web,auth): httpOnly cookie auth + CSP + dedup + type debt
- token: httpOnly+Secure+SameSite cookie (backend Set/Clear + filter Cookie-first read), frontend axios drops X-Auth-Token, auth store uses sessionStorage flag, router guard checks flag
- security: CSP + nosniff + Referrer-Policy in index.html; delete dead getCookies/setCookies/removeCookies; remove Base64 obfuscation from storageUtil
- fix: 24 double-notification .catch failMessage removed (interceptor handles); storageUtil boolean get/set asymmetry fixed
- types: DeviceDetail/profile-detail/device-edit {} as any -> Partial<DeviceRecord>/DriverRecord/ProfileRecord
- dedup: API CRUD factory (11 modules), i18n confirmDelete interpolation (54 lines removed), CardShell unified + shared form-width mixin

Verification: vue-tsc green / 158 unit tests pass / mvn compile green
2026-08-08 18:40:58 +08:00
Henry ZhangandClaude Fable 5 98d8eb80b1 refactor(api): type OAuth grant_type as proto enum (#198)
grant_type in GrpcMcpIntrospectDTO was a free-form string. Introduce
GrpcOAuthGrantType (GRPC_OAUTH_GRANT_TYPE_UNSPECIFIED / AUTHORIZATION_CODE
/ CLIENT_CREDENTIALS / REFRESH_TOKEN). Enum names are upper-case (Java
enum constants must be); the boundary converts to/from the lowercase
OAuth spec form (authorization_code) via toUpperCase / toLowerCase.
BO, DB and OAuth form parameter stay lowercase string.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 19:03:50 +08:00
Henry ZhangandClaude Fable 5 3f78487357 refactor(api): type MCP audit status as proto enum (#197)
audit status in GrpcMcpAuditCommand was a free-form string. Introduce
GrpcMcpAuditStatus (MCP_AUDIT_STATUS_UNSPECIFIED / SUCCESS / DENIED /
POLICY_DENIED / ERROR / UNKNOWN) — names match McpAuditStatusEnum values.
Server maps proto->DTO via name(); facade maps BO string->proto via
toGrpcAuditStatus. BO and DB stay string.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 18:21:20 +08:00
Henry ZhangandClaude Fable 5 4a69185d97 refactor(api): type MCP principal_type as proto enum (#196)
principal_type was a free-form string in GrpcMcpIntrospectDTO and
GrpcMcpAuditCommand. Introduce GrpcMcpPrincipalType
(MCP_PRINCIPAL_TYPE_UNSPECIFIED / USER / SERVICE_ACCOUNT / SYSTEM) —
names match PrincipalTypeEnum values, so the mapping is a direct
valueOf / name(). Server + facade convert at the proto boundary; BO,
gateway and HTTP header layer stay string.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 18:00:45 +08:00
Henry ZhangandClaude Fable 5 3a03962600 refactor(api): type MCP risk_level as proto enum (#195)
risk_level was a free-form string across GrpcMcpToolMetadataDTO,
GrpcMcpToolResolveDTO, GrpcMcpToolAuthorizeDTO and GrpcMcpAuditCommand.
Introduce GrpcMcpRiskLevel (MCP_RISK_LEVEL_UNSPECIFIED / LOW / MEDIUM /
HIGH) — names match McpRiskLevelEnum values, so the mapping is a direct
valueOf / name(). Server + facade convert at the proto boundary; the BO
and DB layer stay string.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 17:24:18 +08:00
Henry ZhangandClaude Fable 5 7c643a8e80 fix(api): dc3-api contract overhaul (auth JWT, history, presence, decision enum) (#193)
* fix(api): correct inverted enable_flag comment and document time unit

- tenant.proto enable_flag comment said "1 enabled, 0 disabled" but the
  actual EnableFlagEnum is ENABLE=0, DISABLE=1 — callers reading the
  comment would invert the flag. Correct it.
- base.proto create_time/operate_time are epoch milliseconds
  (LocalDateTimeUtil/Instant.toEpochMilli); document the unit so callers
  don't guess seconds vs millis.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(api): carry timestamp in point-value history; explicit bool presence

#5 Point-value history: the whole chain (proto -> gRPC server ->
PointValueService -> repository -> facades -> controller -> agentic tool)
returned List<String> and dropped create_time even though the DB row
already carried it. Switch to PointValueBO / FacadePointValueBO end to
end so callers receive each value with its timestamp.

#6 Field presence: GrpcR.ok and McpIntrospectDTO.active are now optional
bool, so "unset" is distinguishable from false on the wire.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(auth): unify JWT signing key, drop salt/password from token contract

The JWT signing key was per-principal — securityKey + ":" + salt, where
salt was the credential salt also carried through the gateway and the
token RPC. That makes the JWT key weak and widens salt exposure to every
gateway hop. Sign with the single configured securityKey (HS256) instead
and remove salt from the JWT path entirely:

- KeyUtil.generateToken/parserToken drop the salt parameter; the HMAC
  key is now just securityKey (must be >= 32 bytes for HS256).
- TokenService.generateToken/checkValid drop the salt parameter.
- token.proto GrpcLoginQuery drops salt and password — CheckValid only
  ever needed tenant, name and token.
- gateway FilterService, TokenGrpcFacade, TokenController adapted; the
  request header no longer feeds salt into validation.

The login-handshake salt (POST /token/salt, used to salt the password
client-side before verifyPassword) is unchanged — only the JWT signing
salt is removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(api): type MCP authorize decision as proto enum

The authorize-tool-call decision was a free-form string, so callers
could only compare it against literals with no compile-time check.
Introduce GrpcMcpDecision (MCP_DECISION_UNSPECIFIED / AUTHORIZED /
CONFIRM_REQUIRED / REJECTED) and type GrpcMcpToolAuthorizeDTO.decision
with it. Enum names match the existing auth-side literals, so the
mapping is a direct valueOf / name().

- McpRuntimeServer builds the enum via toGrpcDecision (unknown -> UNSPECIFIED).
- McpRuntimeGrpcFacade maps enum -> BO string via name().
- gateway unchanged: it receives the BO (string decision) through the facade.

The other string MCP fields (risk_level, status, grant_type,
principal_type) stay strings for now — their value sets are wider and
partly lowercase (OAuth grant_type), so they are a follow-up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(facade): align TokenLocalFacade with 3-arg checkValid (CI compile fix)

TokenLocalFacade (local impl) was missed when TokenFacade.checkValid
dropped salt; CI compiles facade-local-auth independently and caught
it. Align it + its test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 16:36:35 +08:00
Henry ZhangandClaude Fable 5 73ff48bcb9 style: reformat codebase (backend java/xml, docs, web) (#175)
* style(backend): reformat and rearrange java/xml sources

Apply code cleanup across dc3-common and dc3-driver: whitespace and
indent normalization, import sorting, member rearrangement, and javadoc
normalization. No semantic changes; compilation verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* style(docs): reformat vitepress vue diagram components

Expand compact svg templates and normalize formatting across diagram
components, the seo module, and the theme stylesheet. No behavior
changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* style(docs): reformat markdown pages

Normalize markdown formatting. Restore the <script setup> component
imports that an earlier unused-import pass had wrongly stripped; every
<Diagram> tag now resolves to a backing import again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* style: reformat point view and trim pom whitespace

Normalize whitespace in the point view and drop trailing whitespace in
pom.xml. No behavior changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 12:13:36 +08:00
pnoker 056bd9ae21 Merge remote-tracking branch 'origin/develop' into chore/promote-develop-main-3 2026-08-03 21:57:03 +08:00
Henry Zhang 00c67406b0 refactor(quality): fix unused-param/confusing-sig/local-temp/js-comparison (12) (#163)
- unused-parameter (7 private/non-override): drop unused params in
  Snmp getConnector/buildTarget, Sl651 handleSl651Message,
  PointCommandValidator.validateWriteValue, TypedValueConverter
  finiteFloat/finiteDouble (+ cascade callers). 3 interface default
  methods kept (contract).
- confusing-method-signature (1): AuthenticGatewayFilterFactory
  <Object> → dedicated Config type; apply(Object)→apply(Config)
- local-temp-file-info-disclosure (1): FileUtil creates temp dirs
  with owner-only rwx------ via PosixFilePermissions (Windows fallback)
- js/comparison-between-incompatible-types (1): isNull drop redundant
  val === undefined (== null loose already covers it)

Behavior-preserving. Compile + test-compile clean.
2026-08-03 21:55:13 +08:00
Henry Zhang 4e2c5bc770 refactor(quality): fix 27 medium-risk CodeQL alerts (null/exception/boundary/exposure) (#162)
- non-null-boxed (7): GroupServiceImpl extract Byte→byte; DashboardServiceImpl
  Long→long for primitive id fields
- uncaught-number-format (7): try-catch parse failures in FINS/EthernetIP/BACnet/
  Dashboard (fall back to 0 / skip, matching existing pattern); remove dead
  unreachable outer catch in BACnet
- dereferenced-null (4): DeviceMetadata expand MapUtils.isEmpty to explicit
  null check for short-circuit clarity
- ignored-error-status (4): ConcurrentLinkedQueue.offer→add (unbounded, offer
  always true; add's boolean is "modified", not error)
- index-out-of-bounds (2): orderedMap(Object...) guard odd-length → IAE
- internal-rep-exposure (3): CoverageGapVO/Pages/DriverMetadata return
  unmodifiable views + addX/removeX mutators; migrate all callers + tests

Behavior-preserving. Compile clean (except bacnet4j pre-existing mirror miss).
2026-08-03 21:49:22 +08:00
Henry Zhang 8531e3b872 refactor(quality): migrate 23 deprecated API calls (#161)
- commons-lang3 3.20: StringUtils.equals/equalsIgnoreCase/contains/
  startsWith/removeEnd → Strings.CS/CI (16 calls)
- Jackson 2.19+: JsonNode.fields() → properties() (4, McpOpenApiAggregator)
- Spring AI 2.0: ToolCallAdvisor → ToolCallingAdvisor;
  toolCallbacks(provider) → tools(provider) (3, + tests)

Behavior-preserving. Compile clean.
2026-08-03 21:49:08 +08:00
Henry Zhang 852f0682d3 refactor(quality): fix 21 low-risk CodeQL quality alerts (#160)
- local-variable-is-never-read (3): dead host/port/database locals in
  AbstractJdbcDriverCustomService (subclasses read config themselves)
- unused-container (2): unused `valid` set in AlarmRuleTriggerServiceImpl;
  unused driverSenderService field/ctor param in CanDriver (+ test)
- unknown-javadoc-parameter (12): dangling ctor Javadoc on
  @RequiredArgsConstructor classes / stale @param
- call-to-object-tostring (3): @ToString on MessageHeader (root cause);
  field-log MetadataEventDTO instead of hash
- constant-comparison (1): DriverInitRunner == → >= (defensive)

No behavior change. Compile clean (agentic/can/data/auth/mqtt/driver/sql).
2026-08-03 21:49:03 +08:00
pnoker 4cd16d23d1 Merge remote-tracking branch 'origin/develop' into chore/promote-develop-main-2 2026-08-03 20:24:41 +08:00
Henry Zhang fa1cd49bac fix(security): harden log-injection + CAN command injection (#158)
* fix(security): sanitize agentic assistant HTML with DOMPurify (XSS)

RenderedAssistantMessage rendered model output via v-html after a
hand-rolled regex sanitizer that CodeQL flagged 5 ways: bad-tag-filter,
incomplete-multi-character-sanitization (on* attributes, javascript:),
incomplete-url-scheme-check (data:/vbscript:). Replace with DOMPurify,
which covers all these plus mutation XSS. Fixes CodeQL #2146-2150.

* fix(security): harden log-injection + CAN command injection

log-injection (7): pass user-derived log args (conversationId, model,
candidate/fallback) through LogSanitizer.sanitize in AgenticChatServiceImpl,
ChatClientFactory, AgenticChatRequestPreparer — strips CR/LF that could
forge log lines.

relative-path-command / command injection (2, CanDriver): executeCommand
runs `sh -c` with a command built from driver config (interfaceName) and
request data (canId/frame), so add a CAN_COMMAND_PATTERN whitelist
(^[A-Za-z0-9 _#,.=%/-]+$) rejecting shell metacharacters, and validate
interfaceName against ^[A-Za-z0-9_]+$ at all 3 entry points. Fixes
CodeQL #2173,#2172,#2120,#1514,#1513,#1022,#1017,#1016,#1014.

Verified: mvn compile agentic+can clean.
2026-08-03 19:46:42 +08:00
Henry Zhang 5e0003f019 build(deps): bump mybatis-plus 3.5.16 → 3.5.17 + adapt IService/ServiceImpl imports (#154)
mybatis-plus 3.5.17 fixes the JDK 9+ split-package conflict (#7027) by
relocating service classes from com.baomidou.mybatisplus.extension.service
to com.baomidou.mybatisplus.spring.service. Verified via the 3.5.17 jar:
only IService and ServiceImpl moved — Page, JacksonTypeHandler, chain
wrappers, Db, interceptors all stay in extension. Updated 112 imports.
Supersedes dependabot #141 (which failed compile on the same move).

Verified: mvn compile clean across every IService module (bacnet4j driver
excluded only due to a local mirror cache miss, unrelated to this change).
2026-08-03 13:31:22 +08:00
pnoker a1876727d1 refactor(data): remove PointValueJob, hand ingestion to buffer
Point-value ingestion is now driven by PointValueIngestBuffer workers, so the Quartz 5s tick job is removed; ScheduleForDataServiceImpl only registers the hourly maintenance job; HourlyJobForData test migrated to its own file.
2026-07-27 01:34:34 +08:00
pnoker 6293bbdd19 refactor(data): route point value ingestion through bounded buffer
PointValueReceiver offers every message to PointValueIngestBuffer (ack on accept, nack-requeue when full) and switches to the high-throughput listener container factory; drops the speed-threshold dual path.
2026-07-27 01:34:34 +08:00
pnoker f8ddcf5877 feat(data): add PointValueIngestBuffer with bounded queue and backpressure
Bounded ArrayBlockingQueue plus worker threads draining on a size-or-time trigger; offer returns false when full so the receiver can nack-requeue; a failed save re-queues the batch for retry. PointValueServiceImpl.savePointValuesToRepository wraps failures into RepositoryException so the buffer can re-queue instead of silently dropping.
2026-07-27 01:34:33 +08:00
pnoker c02fc3b3fb refactor(data): extend PointBatchProperties for bounded ingest buffer
Replace speed/interval threshold with queueCapacity, batchSize, flushIntervalMillis and workerCount for the new bounded ingest buffer.
2026-07-27 01:34:32 +08:00
pnoker 18eac7871a test(driver): add point value buffer unit tests
PointValueBufferTest covers CRUD/eviction with temp SQLite; BufferServiceImplTest mocks RabbitTemplate for offer/republish/backoff/disabled
2026-07-26 00:13:31 +08:00
pnoker 9f574d9099 feat(driver): wire send-failure buffering and quartz republish
DriverSenderServiceImpl catch writes buffer and ConfirmCallback re-queues on NACK; BufferRepublishScheduleJob periodic republish; DriverScheduleServiceImpl registers republish job; DriverInitRunner initializes buffer table before registration
2026-07-26 00:13:30 +08:00
pnoker 58d47179a5 feat(driver): add point value local buffer DAO and service
BufferedPointValue row mapping; PointValueCorrelation carries payload/routingKey/attempt; PointValueBuffer SQLite (WAL, HikariCP) DAO; BufferService/Impl offer/republish/capacity eviction/backoff
2026-07-26 00:13:30 +08:00
pnoker f019e2066b feat(driver): introduce sqlite-jdbc dependency and buffer config properties
Add sqlite-jdbc 3.53.2.0 to parent pom dependencyManagement; add sqlite-jdbc and HikariCP to dc3-common-driver pom; add BufferProperties nested group to DriverProperties; add BUFFER_REPUBLISH_SCHEDULE_JOB constant to ScheduleConstant
2026-07-26 00:13:29 +08:00
pnoker 41c43b359a feat(observability): integrate opentelemetry tracing into request-id mechanism
Unify request-id and OpenTelemetry trace context across all transport layers
(HTTP, gRPC, RabbitMQ) using a three-tier priority: X-Request-Id header, OTel
Trace ID, UUID fallback. Add traceId/spanId to the logback pattern for
log-trace correlation. Configure OTLP export, sampling, and B3/W3C propagation
in application-web.yml.
2026-07-23 23:20:58 +08:00
pnoker 91ccd25a59 style(gateway): align mcp controller javadoc param descriptions 2026-07-23 23:20:24 +08:00
pnoker db14f0f089 build(deps): add opentelemetry bom and tracing dependencies
Replace micrometer-tracing-bridge-brave with the full OpenTelemetry stack
(bridge-otel, OTLP exporter, SDK, trace SDK, propagators, API, context).
Add OTel BOM and semconv to the parent POM for centralized version control.
Add OTel API dependencies to dc3-common-rabbitmq and dc3-common-facade-grpc
for trace context propagation.
2026-07-23 23:19:48 +08:00
pnokerandClaude 741ad7cc44 feat(security): redact identifiers and model names in logs
Add LogSanitizer and apply it to agentic conversationId/model and the listening-virtual netty deviceName so they are not emitted verbatim in log output.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-16 20:03:59 +08:00
pnokerandClaude 3f083e7ee8 fix: guard numeric parsing against NumberFormatException
Wrap unchecked Integer/Long/Byte.parse* calls in topic/dashboard/oauth/facade and the BACnet-IP, Ethernet-IP, FINS, SNMP drivers plus the agentic action payload, so malformed values fall back to a safe default instead of aborting.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-16 20:03:42 +08:00
pnokerandClaude 9bd4dd303f refactor(bo): annotate inherited Lombok getters with @Override and add @ToString
Mark @Getter with onMethod_={@Override} on BOs/enums whose accessors override a base-class getter, and add @ToString to the ChatCompletion VOs and Pages.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-16 20:03:41 +08:00
pnokerandClaude d4bd33eefa docs(driver): document dc3-common-driver public APIs, fields and constants
Add Javadoc to hand-written public methods/constructors (with @param/@return), injected fields, @Override methods, constants and nested types across dc3-common-driver. Also fix PointClient#getById @return type (PointDTO -> PointBO) and reorder TypedValueConverter#convert Javadoc above its @SuppressWarnings annotation. No code logic changes.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-16 19:45:16 +08:00
pnoker c8d1a0bf0d docs(manager): document driver device grpc server helpers
driverInTenant (tenant ownership check), getDeviceAttachDTO (device +
points + config assembly)
2026-07-15 12:12:02 +08:00
pnoker e3633a9717 docs(manager): document driver point grpc server helpers
selectDriverScopedPage (driver-scoped in-memory pagination),
resolveDriverProfileIds (device/profile resolution), driverHasPoint
2026-07-15 12:10:12 +08:00
pnoker 78168fc14b docs(auth): document tenant membership, token, denylist and user helpers
TenantMembershipServiceImpl.fuzzyQuery, TokenServiceImpl.markPrincipalLogin,
TokenDenylistCache.buildKey, UserServiceImpl.selectByKey
2026-07-15 12:08:21 +08:00
pnoker 4e8dd8d042 docs(auth): document resource sync builders and grouping helpers
buildApiDO, buildLeafResourceDO, buildApiExt, buildContent, parseContent,
equalsContent, resolveMenuParentResourceId, needsGroupingNodeUpdate,
applyGroupingNodeUpdates
2026-07-15 12:04:18 +08:00
pnoker da11d8874a docs(auth): document role and resource tree helpers
RoleServiceImpl.sortRecursive, ResourceServiceImpl.assembleTree
(flat-to-tree by parent id + sort) and sortRecursive
2026-07-15 12:01:10 +08:00
pnoker 3693d81c29 docs(auth): document mcp runtime grpc server conversion helpers
Six toGrpc overloads (introspect, tool definition, annotations,
metadata, resolve, authorize), toDTO (audit command), scopes parser
2026-07-15 11:58:25 +08:00
pnoker 7675e39ba2 docs(agentic): document action service impl helpers
getPending (status+expiry validation), claimPending (optimistic
PENDING-guarded transition), fillCreateAudit, scopedWrapper
2026-07-15 11:35:43 +08:00
pnoker b31a4f6a92 docs(agentic): document model provider service impl helpers
validate, apply (api-key conditional retention), fillCreateAudit,
fillOperateAudit, normalizeDefault
2026-07-15 11:32:07 +08:00
pnoker e3b356b829 docs(agentic): document attachment service impl helpers
resolveFilePath (traversal-safe path), assertContentLength, deleteFile
(best-effort cleanup), safePathPart (sanitize), fillCreateAudit
2026-07-15 11:22:15 +08:00
pnoker c97b9eb3b1 docs(auth): document local credential service impl helpers
fuzzyQuery (tenant membership join), prepareForCreate (password hash),
prepareForUpdate (conditional re-hash), checkDuplicate (login+principal
dual check), existsDuplicate, getDOById, normalize
2026-07-15 11:14:43 +08:00
pnoker 61e1e6a873 docs(agentic): document model config service impl private helpers
enabledConfigs, validate (model/provider/range checks), apply (field
copy with defaults), fillCreateAudit/fillOperateAudit, normalizeDefault
(single-default invariant), fillProviderName, resolveProviderName
2026-07-15 11:05:53 +08:00
pnoker 92af0af239 docs(auth): document role principal bind service impl helpers 2026-07-15 10:30:58 +08:00
pnoker 2662eb2db5 docs(auth): document service account service impl helpers
fuzzyQuery, prepareForCreate (required-field validation), prepareForUpdate
(field backfill), buildPrincipal, buildMembership, checkDuplicate,
getDOById, principalName
2026-07-15 10:08:12 +08:00
pnoker d5914ffe68 docs(driver,public): document sdk job lock converter and util helpers
- DriverInitRunner: registerWithRetry (exponential backoff)
- DeviceLockManager: acquire/release (ref-counted lock)
- DriverReadScheduleJob: isReadableDevice, readPoint (error-isolated)
- DeviceHealthScheduleJob: reportDeviceHealth, reportDeviceState
- DriverHealthScheduleJob: resolveDriverHealth (fault fallback)
- TypedValueConverter: convert (type dispatch), linearValue (mx+b)
- KeyUtil: getSecurityKey (env/property resolution)
- DecodeUtil: stripLeadingZero (BigInteger sign-byte removal)
2026-07-14 21:46:04 +08:00
pnoker 78ca24d4d8 docs(facade): document guardOrThrow across grpc facades
Document the shared guardOrThrow helper (NOT_FOUND = empty outcome,
other error = service exception) on the nine grpc facade classes,
matching the two that already documented it.
2026-07-14 18:01:50 +08:00
pnoker e61e829f10 docs(dal): document group and label entity-type validators
- GroupServiceImpl: validateGroupType, isGroupable, validateParent
  (root defaulting and level derivation)
- LabelServiceImpl: validateEntityType, isSupportedEntityType
2026-07-14 17:56:12 +08:00
pnoker 10dd261e2d docs(data): document notify and rule state service impl helpers
- NotifyChannelBindServiceImpl: fuzzyQuery, checkDuplicate,
  requireReferences, getDOById
- NotifyChannelServiceImpl: fuzzyQuery, checkDuplicate, getDOById
- NotifyHistoryServiceImpl: fuzzyQuery, getDOById
- RuleStateServiceImpl: fuzzyQuery, checkDuplicate (rule+type+entity+
  fingerprint), getDOById
2026-07-14 17:52:39 +08:00
pnoker 239b2bc000 docs(data): document scanner, state-flip and notify adapter helpers
- EntityStateExpiryScanner: document scanExpiredDevices,
  buildOfflineAlarm, completeExpiredDevice
- DeviceStateServiceImpl/DriverStateServiceImpl: document isFlip and
  online (ONLINE+MAINTAIN count as the online side)
- FeishuBotNotifyChannelAdapter: document buildFeishuMessage
  (type dispatch) and sign (HMAC-SHA256)
- MessageRenderServiceImpl: document selectTemplate and missingVariables
2026-07-14 17:48:04 +08:00
pnoker 3a2de55f4b docs(data): document alarm engine private methods
- ConditionEvaluator: document evaluateNumeric/evaluateText/isNumericOperator
  operator-dispatch helpers
- RuleNotificationServiceImpl: document persistRuleState (state-machine
  transition), loadState, fingerprint (dedup key resolution)
- NotifyWorker: document dispatch and loadChannel
- RuleAlarmPersistenceServiceImpl: document persistEntityAlarm and
  getFiringAlarmId
- WindowedRuleEvaluator: document evaluate/evaluateAggregate/evaluateFold
  window-mode dispatch
2026-07-14 17:44:13 +08:00