P0: Replace content JSON-string with sealed PointCommandPayload + record DTOs.
P0: Accept write() boolean return, suppress echo on failure.
P1: Return commandId from POST endpoints, add RESTful GET /{commandId}.
P1: Add driver-online check via EntityStateMapper, PointCommandValidator.
P2: Add DeviceLockManager for per-device serialized command execution.
P3: Add POST /list API with pagination, commandId idempotency support.
- Replace two duplicate enums with single EntityStatusEnum (same index/code)
- Rename DB columns: state_flag→entity_state_flag, state_ext→entity_state_ext
- Add stateDescription field to DeviceStateDTO/DriverStateDTO for diagnostics
- Add description field to DeviceHealthState/DriverHealthState
- UPSERT SQL now writes stateDescription into entity_state_ext on heartbeat
- Remove EntityStateStatus interface (no longer needed with single enum)
- Update MQ layer, heartbeat services, status queries, gRPC, and all tests
Replace local Caffeine cache as the source of truth for driver and
device online status with dc3_entity_state, a persistent state lease
table backed by PostgreSQL.
- Add EntityStateDO/Mapper/Manager persistence stack.
- Add EntityStateExpiryScanner that scans expire_time every 15 seconds
with lease_version recheck to avoid stale alarm writes.
- Dual-write heartbeat path: DriverStateServiceImpl and
DeviceStateServiceImpl now write dc3_entity_state first, then local
cache.
- All status queries (controllers, gRPC server, local facade,
SystemHealthServiceImpl) read from dc3_entity_state. Rows missing or
past expire_time return offline.
- OfflineExpiryListener gains a DB dedup check to skip expiry events
already handled by the scanner.
- Add @EnableScheduling to DataApplication.
- Add design doc docs/design/entity-state.md with full DDL.
This resolves restart state loss, multi-instance inconsistency, and
races between expiry checks and fresh heartbeats.