diff --git a/dc3-common/dc3-common-constant/src/main/java/io/github/pnoker/common/enums/TimeoutSourceFlagEnum.java b/dc3-common/dc3-common-constant/src/main/java/io/github/pnoker/common/enums/TimeoutSourceFlagEnum.java
new file mode 100644
index 000000000..22e1f721f
--- /dev/null
+++ b/dc3-common/dc3-common-constant/src/main/java/io/github/pnoker/common/enums/TimeoutSourceFlagEnum.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package io.github.pnoker.common.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+/**
+ * Enumeration of timeout source flags.
+ *
+ * @author pnoker
+ * @version 2026.5.22
+ * @since 2026.5.22
+ */
+@Getter
+@AllArgsConstructor
+public enum TimeoutSourceFlagEnum {
+
+ /**
+ * System
+ */
+ SYSTEM((byte) 0, "system", "System"),
+
+ /**
+ * Driver
+ */
+ DRIVER((byte) 1, "driver", "Driver"),
+
+ /**
+ * Device
+ */
+ DEVICE((byte) 2, "device", "Device"),
+
+ /**
+ * Profile
+ */
+ PROFILE((byte) 3, "profile", "Profile"),
+ ;
+
+ @EnumValue
+ private final Byte index;
+
+ private final String code;
+
+ private final String remark;
+
+ public static TimeoutSourceFlagEnum ofIndex(Byte index) {
+ Optional any = Arrays.stream(TimeoutSourceFlagEnum.values())
+ .filter(type -> type.getIndex().equals(index))
+ .findFirst();
+ return any.orElse(null);
+ }
+
+ public static TimeoutSourceFlagEnum ofCode(String code) {
+ Optional any = Arrays.stream(TimeoutSourceFlagEnum.values())
+ .filter(type -> type.getCode().equals(code))
+ .findFirst();
+ return any.orElse(null);
+ }
+
+ public static TimeoutSourceFlagEnum ofName(String name) {
+ try {
+ return valueOf(name);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+
+}
diff --git a/dc3-common/dc3-common-data/src/main/java/io/github/pnoker/common/data/entity/model/EntityStateDO.java b/dc3-common/dc3-common-data/src/main/java/io/github/pnoker/common/data/entity/model/EntityStateDO.java
index b1066560d..f006df0fc 100644
--- a/dc3-common/dc3-common-data/src/main/java/io/github/pnoker/common/data/entity/model/EntityStateDO.java
+++ b/dc3-common/dc3-common-data/src/main/java/io/github/pnoker/common/data/entity/model/EntityStateDO.java
@@ -22,6 +22,8 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import io.github.pnoker.common.entity.ext.JsonExt;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@@ -38,13 +40,13 @@ import java.time.LocalDateTime;
* query services read this table as the authoritative source of truth.
*
* @author pnoker
- * @version 2026.5.21
+ * @version 2026.5.22
* @since 2026.5.21
*/
@Getter
@Setter
@ToString
-@TableName("dc3_entity_state")
+@TableName(value = "dc3_entity_state", autoResultMap = true)
public class EntityStateDO implements Serializable {
@Serial
@@ -66,10 +68,10 @@ public class EntityStateDO implements Serializable {
private Long entityId;
/**
- * Driver ID. For driver entries same as entity_id; for device entries the owning driver.
+ * Parent entity ID. For driver entries same as entity_id; for device entries the owning driver.
*/
- @TableField("driver_id")
- private Long driverId;
+ @TableField("parent_entity_id")
+ private Long parentEntityId;
/**
* Current status index (DriverStatusEnum / DeviceStatusEnum index)
@@ -77,6 +79,12 @@ public class EntityStateDO implements Serializable {
@TableField("state_flag")
private Byte stateFlag;
+ /**
+ * Last state flag, default OFFLINE (1)
+ */
+ @TableField("last_state_flag")
+ private Byte lastStateFlag;
+
/**
* Monotonic version incremented on each heartbeat renewal
*/
@@ -90,10 +98,34 @@ public class EntityStateDO implements Serializable {
private LocalDateTime expireTime;
/**
- * TTL in seconds used for this entry
+ * Timeout in seconds used for this entry
*/
- @TableField("ttl_seconds")
- private Integer ttlSeconds;
+ @TableField("timeout_seconds")
+ private Integer timeoutSeconds;
+
+ /**
+ * Latest heartbeat time
+ */
+ @TableField("last_heartbeat_time")
+ private LocalDateTime lastHeartbeatTime;
+
+ /**
+ * Latest alarm ID, default 0
+ */
+ @TableField("last_alarm_id")
+ private Long lastAlarmId;
+
+ /**
+ * Timeout source (TimeoutSourceFlagEnum), default 0
+ */
+ @TableField("timeout_source_flag")
+ private Byte timeoutSourceFlag;
+
+ /**
+ * JSON extension payload
+ */
+ @TableField(value = "state_ext", typeHandler = JacksonTypeHandler.class)
+ private JsonExt stateExt;
@TableField("tenant_id")
private Long tenantId;