diff --git a/.gitignore b/.gitignore
index de4b16b..fb01baf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,4 +20,7 @@ shared/
 
 # MQTT ignored files (무시할 파일들)
 fems-mqtt/data/
-fems-mqtt/log/
\ No newline at end of file
+fems-mqtt/log/
+
+fems-realtime-api/node_modules/
+fems-realtime-api/logs/*
\ No newline at end of file
diff --git a/fems-api/src/controllers/app/device/device.controller.js b/fems-api/src/controllers/app/device/device.controller.js
new file mode 100644
index 0000000..10c6294
--- /dev/null
+++ b/fems-api/src/controllers/app/device/device.controller.js
@@ -0,0 +1,194 @@
+// src/controllers/app/device/device.controller.js
+const express = require("express");
+const router = express.Router();
+const authMiddleware = require("../../../middleware/auth.middleware");
+const roleCheck = require("../../../middleware/roleCheck.middleware");
+const deviceService = require("../../../services/device.service");
+const logger = require("../../../config/logger");
+const { body, query } = require("express-validator");
+const validate = require("../../../middleware/validator.middleware");
+
+// 모든 라우트에 인증 미들웨어 적용
+router.use(authMiddleware);
+router.use(roleCheck(["super_admin", "company_admin", "branch_admin", "user"]));
+
+// 데이터 포인트 유효성 검사 규칙
+const dataPointValidationRules = [
+  body("DataPoints.*.tag_name").notEmpty().withMessage("Tag name is required"),
+  body("DataPoints.*.data_type")
+    .isIn([
+      "BOOL",
+      "INT16",
+      "UINT16",
+      "INT32",
+      "UINT32",
+      "FLOAT",
+      "DOUBLE",
+      "STRING",
+    ])
+    .withMessage("Valid data type is required"),
+  body("DataPoints.*.address").notEmpty().withMessage("Address is required"),
+  body("DataPoints.*.register_type")
+    .optional()
+    .isIn(["COIL", "DISCRETE_INPUT", "HOLDING_REGISTER", "INPUT_REGISTER"]),
+  body("DataPoints.*.scan_rate")
+    .isInt({ min: 100 })
+    .withMessage("Scan rate must be at least 100ms"),
+  body("DataPoints.*.scale_factor").optional().isFloat(),
+  body("DataPoints.*.offset").optional().isFloat(),
+];
+
+// 디바이스 등록 (데이터 포인트 포함)
+router.post(
+  "/",
+  [
+    // 디바이스 기본 정보 validation
+    body("device_type").notEmpty().withMessage("Device type is required"),
+    body("device_name").notEmpty().withMessage("Device name is required"),
+    body("location").optional().isString(),
+    body("manufacturer").optional().isString(),
+    body("model").optional().isString(),
+
+    // 연결 설정 validation
+    body("DeviceConnection")
+      .isObject()
+      .withMessage("Connection settings are required"),
+    body("DeviceConnection.protocol")
+      .isIn(["MODBUS_TCP", "MODBUS_RTU", "OPC_UA", "MQTT", "BACNET"])
+      .withMessage("Valid protocol is required"),
+    body("DeviceConnection.ip_address")
+      .if(body("DeviceConnection.protocol").equals("MODBUS_TCP"))
+      .isIP()
+      .withMessage("Valid IP address is required for Modbus TCP"),
+    body("DeviceConnection.port")
+      .if(body("DeviceConnection.protocol").equals("MODBUS_TCP"))
+      .isInt({ min: 1, max: 65535 })
+      .withMessage("Valid port number is required"),
+
+    // 데이터 포인트 validation
+    ...dataPointValidationRules,
+
+    validate,
+  ],
+  async (req, res, next) => {
+    try {
+      const deviceData = {
+        ...req.body,
+        status: "ACTIVE",
+      };
+
+      const device = await deviceService.createDevice(deviceData);
+      res.status(201).json(device);
+    } catch (error) {
+      logger.error("Failed to create device:", error);
+      next(error);
+    }
+  }
+);
+
+// 디바이스 수정 (데이터 포인트 포함)
+router.put(
+  "/:id",
+  [
+    // 디바이스 기본 정보 validation
+    body("device_name").optional().isString(),
+    body("location").optional().isString(),
+    body("status")
+      .optional()
+      .isIn(["ACTIVE", "INACTIVE", "MAINTENANCE", "ERROR"]),
+
+    // 연결 설정 validation (수정 시)
+    body("DeviceConnection").optional().isObject(),
+    body("DeviceConnection.protocol")
+      .optional()
+      .isIn(["MODBUS_TCP", "MODBUS_RTU", "OPC_UA", "MQTT", "BACNET"]),
+
+    // 데이터 포인트 validation
+    ...dataPointValidationRules,
+
+    validate,
+  ],
+  async (req, res, next) => {
+    try {
+      const deviceId = req.params.id;
+      const updateData = req.body;
+
+      const updated = await deviceService.updateDevice(deviceId, updateData);
+
+      if (!updated) {
+        return res.status(404).json({
+          message: "Device not found",
+        });
+      }
+
+      res.json(updated);
+    } catch (error) {
+      logger.error("Failed to update device:", error);
+      next(error);
+    }
+  }
+);
+
+// 디바이스 목록 조회
+router.get(
+  "/",
+  [
+    query("device_type").optional().isString(),
+    query("status")
+      .optional()
+      .isIn(["ACTIVE", "INACTIVE", "MAINTENANCE", "ERROR"]),
+    validate,
+  ],
+  async (req, res, next) => {
+    try {
+      const filters = req.query;
+      const devices = await deviceService.getDevices(filters);
+      res.json(devices);
+    } catch (error) {
+      logger.error("Failed to get devices:", error);
+      next(error);
+    }
+  }
+);
+
+// 디바이스 상세 조회
+router.get("/:id", async (req, res, next) => {
+  try {
+    const deviceId = req.params.id;
+    const device = await deviceService.getDeviceDetail(deviceId);
+
+    if (!device) {
+      return res.status(404).json({
+        message: "Device not found",
+      });
+    }
+
+    res.json(device);
+  } catch (error) {
+    logger.error("Failed to get device detail:", error);
+    next(error);
+  }
+});
+
+// 디바이스 삭제
+router.delete("/:id", async (req, res, next) => {
+  try {
+    const deviceId = req.params.id;
+    const result = await deviceService.deleteDevice(deviceId);
+
+    if (!result) {
+      return res.status(404).json({
+        message: "Device not found",
+      });
+    }
+
+    res.status(200).json({
+      message: "Device deleted successfully",
+    });
+  } catch (error) {
+    logger.error("Failed to delete device:", error);
+    next(error);
+  }
+});
+
+module.exports = router;
diff --git a/fems-api/src/models/DataPoint.js b/fems-api/src/models/DataPoint.js
new file mode 100644
index 0000000..dc34273
--- /dev/null
+++ b/fems-api/src/models/DataPoint.js
@@ -0,0 +1,94 @@
+// src/models/DataPoint.js
+const { Model, DataTypes } = require("sequelize");
+
+class DataPoint extends Model {
+  static init(sequelize) {
+    super.init(
+      {
+        id: {
+          type: DataTypes.UUID,
+          defaultValue: DataTypes.UUIDV4,
+          primaryKey: true,
+        },
+        tag_name: {
+          type: DataTypes.STRING(100),
+          allowNull: false,
+          comment: "데이터 포인트 태그명",
+        },
+        description: {
+          type: DataTypes.STRING(200),
+          comment: "설명",
+        },
+        data_type: {
+          type: DataTypes.ENUM(
+            "BOOL",
+            "INT16",
+            "UINT16",
+            "INT32",
+            "UINT32",
+            "FLOAT",
+            "DOUBLE",
+            "STRING"
+          ),
+          allowNull: false,
+          comment: "데이터 타입",
+        },
+        address: {
+          type: DataTypes.STRING(50),
+          allowNull: false,
+          comment: "메모리 주소 또는 레지스터 번호",
+        },
+        register_type: {
+          type: DataTypes.ENUM(
+            "COIL",
+            "DISCRETE_INPUT",
+            "HOLDING_REGISTER",
+            "INPUT_REGISTER"
+          ),
+          comment: "Modbus 레지스터 타입",
+        },
+        scan_rate: {
+          type: DataTypes.INTEGER,
+          defaultValue: 1000,
+          comment: "스캔 주기 (ms)",
+        },
+        scale_factor: {
+          type: DataTypes.FLOAT,
+          defaultValue: 1,
+          comment: "스케일 팩터",
+        },
+        offset: {
+          type: DataTypes.FLOAT,
+          defaultValue: 0,
+          comment: "오프셋",
+        },
+        unit: {
+          type: DataTypes.STRING(20),
+          comment: "단위",
+        },
+        is_active: {
+          type: DataTypes.BOOLEAN,
+          defaultValue: true,
+          comment: "활성화 여부",
+        },
+        created_at: DataTypes.DATE,
+        updated_at: DataTypes.DATE,
+      },
+      {
+        sequelize,
+        modelName: "DataPoint",
+        tableName: "data_points",
+        timestamps: true,
+        updatedAt: "updated_at",
+        createdAt: "created_at",
+      }
+    );
+    return this;
+  }
+
+  static associate(models) {
+    this.belongsTo(models.Device, { foreignKey: "deviceId" });
+  }
+}
+
+module.exports = DataPoint;
diff --git a/fems-api/src/models/Device.js b/fems-api/src/models/Device.js
new file mode 100644
index 0000000..8158db6
--- /dev/null
+++ b/fems-api/src/models/Device.js
@@ -0,0 +1,86 @@
+// src/models/Device.js
+const { Model, DataTypes } = require("sequelize");
+
+class Device extends Model {
+  static init(sequelize) {
+    return super.init(
+      {
+        id: {
+          type: DataTypes.UUID,
+          defaultValue: DataTypes.UUIDV4,
+          primaryKey: true,
+        },
+        device_type: {
+          type: DataTypes.STRING(50),
+          allowNull: false,
+          comment: "디바이스 유형 (PLC, PowerMeter, Sensor 등)",
+        },
+        device_name: {
+          type: DataTypes.STRING(100),
+          allowNull: false,
+          comment: "디바이스 표시 이름",
+        },
+        manufacturer: {
+          type: DataTypes.STRING(100),
+          comment: "제조사",
+        },
+        model: {
+          type: DataTypes.STRING(100),
+          comment: "모델명",
+        },
+        serial_number: {
+          type: DataTypes.STRING(100),
+          comment: "시리얼 번호",
+        },
+        location: {
+          type: DataTypes.STRING(100),
+          comment: "설치 위치",
+        },
+        description: {
+          type: DataTypes.TEXT,
+          comment: "설명",
+        },
+        status: {
+          type: DataTypes.ENUM("ACTIVE", "INACTIVE", "MAINTENANCE", "ERROR"),
+          defaultValue: "ACTIVE",
+          comment: "디바이스 상태",
+        },
+        created_at: {
+          type: DataTypes.DATE,
+          defaultValue: DataTypes.NOW,
+        },
+        updated_at: {
+          type: DataTypes.DATE,
+          defaultValue: DataTypes.NOW,
+        },
+        // 새로 추가할 필드들
+        companyId: {
+          type: DataTypes.UUID,
+          comment: "회사 ID",
+        },
+        branchId: {
+          type: DataTypes.UUID,
+          comment: "지점 ID",
+        },
+      },
+      {
+        sequelize,
+        modelName: "Device",
+        tableName: "devices",
+        timestamps: true,
+        updatedAt: "updated_at",
+        createdAt: "created_at",
+      }
+    );
+  }
+
+  static associate(models) {
+    this.belongsTo(models.Company, { foreignKey: "companyId" });
+    this.belongsTo(models.Branch, { foreignKey: "branchId" });
+    this.hasOne(models.DeviceConnection, { foreignKey: "deviceId" });
+    this.hasMany(models.DataPoint, { foreignKey: "deviceId" });
+    this.hasMany(models.DeviceStatus, { foreignKey: "deviceId" });
+  }
+}
+
+module.exports = Device;
diff --git a/fems-api/src/models/DeviceConnection.js b/fems-api/src/models/DeviceConnection.js
new file mode 100644
index 0000000..4a88fb3
--- /dev/null
+++ b/fems-api/src/models/DeviceConnection.js
@@ -0,0 +1,70 @@
+// src/models/DeviceConnection.js
+const { Model, DataTypes } = require("sequelize");
+
+class DeviceConnection extends Model {
+  static init(sequelize) {
+    super.init(
+      {
+        id: {
+          type: DataTypes.UUID,
+          defaultValue: DataTypes.UUIDV4,
+          primaryKey: true,
+        },
+        protocol: {
+          type: DataTypes.ENUM(
+            "MODBUS_TCP",
+            "MODBUS_RTU",
+            "OPC_UA",
+            "MQTT",
+            "BACNET"
+          ),
+          allowNull: false,
+          comment: "통신 프로토콜",
+        },
+        ip_address: {
+          type: DataTypes.STRING(45),
+          comment: "IP 주소",
+        },
+        port: {
+          type: DataTypes.INTEGER,
+          comment: "포트 번호",
+        },
+        unit_id: {
+          type: DataTypes.INTEGER,
+          comment: "Modbus Unit ID",
+        },
+        connection_timeout: {
+          type: DataTypes.INTEGER,
+          defaultValue: 1000,
+          comment: "연결 타임아웃 (ms)",
+        },
+        retry_interval: {
+          type: DataTypes.INTEGER,
+          defaultValue: 5000,
+          comment: "재시도 간격 (ms)",
+        },
+        protocol_settings: {
+          type: DataTypes.JSONB,
+          comment: "프로토콜별 추가 설정",
+        },
+        created_at: DataTypes.DATE,
+        updated_at: DataTypes.DATE,
+      },
+      {
+        sequelize,
+        modelName: "DeviceConnection",
+        tableName: "device_connections",
+        timestamps: true,
+        updatedAt: "updated_at",
+        createdAt: "created_at",
+      }
+    );
+    return this;
+  }
+
+  static associate(models) {
+    this.belongsTo(models.Device, { foreignKey: "deviceId" });
+  }
+}
+
+module.exports = DeviceConnection;
diff --git a/fems-api/src/models/DeviceStatus.js b/fems-api/src/models/DeviceStatus.js
new file mode 100644
index 0000000..c769d30
--- /dev/null
+++ b/fems-api/src/models/DeviceStatus.js
@@ -0,0 +1,35 @@
+// src/models/DeviceStatus.js
+const { Model, DataTypes } = require("sequelize");
+
+class DeviceStatus extends Model {
+  static init(sequelize) {
+    super.init(
+      {
+        time: {
+          type: DataTypes.DATE,
+          allowNull: false,
+        },
+        status: {
+          type: DataTypes.STRING(20),
+          allowNull: false,
+        },
+        status_detail: {
+          type: DataTypes.JSONB,
+        },
+      },
+      {
+        sequelize,
+        modelName: "DeviceStatus",
+        tableName: "device_status",
+        timestamps: false,
+      }
+    );
+    return this;
+  }
+
+  static associate(models) {
+    this.belongsTo(models.Device, { foreignKey: "deviceId" });
+  }
+}
+
+module.exports = DeviceStatus;
diff --git a/fems-api/src/routes/app.js b/fems-api/src/routes/app.js
index 8407ccb..323cc7e 100644
--- a/fems-api/src/routes/app.js
+++ b/fems-api/src/routes/app.js
@@ -15,6 +15,7 @@ const equipmentPartsController = require("../controllers/app/equipmentParts/equi
 const departmentController = require("../controllers/app/department/department.controller");
 const healthController = require("../controllers/app/health/health.controller");
 const companiesController = require("../controllers/admin/companies/companies.controller");
+const deviceController = require("../controllers/app/device/device.controller");
 
 router.use("/health", healthController);
 router.use("/auth", authController);
@@ -29,5 +30,6 @@ router.use("/parts", partsController);
 router.use("/equipment-parts", equipmentPartsController);
 router.use("/department", departmentController);
 router.use("/companies", companiesController);
+router.use("/devices", deviceController);
 
 module.exports = router;
diff --git a/fems-api/src/services/device.service.js b/fems-api/src/services/device.service.js
new file mode 100644
index 0000000..0b00bb3
--- /dev/null
+++ b/fems-api/src/services/device.service.js
@@ -0,0 +1,396 @@
+// src/services/device.service.js
+const {
+  Device,
+  DeviceConnection,
+  DataPoint,
+  DeviceStatus,
+} = require("../models");
+const alertService = require("./alert.service");
+const logger = require("../config/logger");
+
+class DeviceService {
+  // 디바이스 생성 (데이터 포인트 포함)
+  async createDevice(data) {
+    const transaction = await Device.sequelize.transaction();
+
+    try {
+      // 1. 디바이스 생성
+      const device = await Device.create(
+        {
+          device_type: data.device_type,
+          device_name: data.device_name,
+          manufacturer: data.manufacturer,
+          model: data.model,
+          serial_number: data.serial_number || null, // null 처리 추가
+          location: data.location,
+          description: data.description,
+          status: data.status,
+        },
+        { transaction }
+      );
+
+      // 2. 연결 정보 생성
+      if (data.DeviceConnection) {
+        // deviceId는 방금 생성한 device.id를 사용
+        const connectionData = {
+          ...data.DeviceConnection,
+          deviceId: device.id, // 명시적으로 deviceId 설정
+          protocol_settings: data.DeviceConnection.protocol_settings || {}, // 기본값 처리
+        };
+
+        await DeviceConnection.create(connectionData, { transaction });
+      }
+
+      // 3. 데이터 포인트 생성
+      if (data.DataPoints && Array.isArray(data.DataPoints)) {
+        await Promise.all(
+          data.DataPoints.map((point) =>
+            DataPoint.create(
+              {
+                ...point,
+                deviceId: device.id, // 명시적으로 deviceId 설정
+                is_active: true,
+              },
+              { transaction }
+            )
+          )
+        );
+      }
+
+      await alertService.createAlert({
+        type: "DEVICE_CREATED",
+        message: `Device created: ${device.device_name}`,
+        companyId: device.companyId,
+        transaction,
+      });
+
+      await transaction.commit();
+
+      // 생성된 디바이스 상세 정보 조회
+      return this.getDeviceDetail(device.id);
+    } catch (error) {
+      await transaction.rollback();
+      logger.error("Failed to create device:", error);
+      throw error;
+    }
+  }
+
+  async updateDevice(id, data) {
+    let transaction;
+
+    try {
+      transaction = await Device.sequelize.transaction();
+
+      // 1. 디바이스 존재 확인
+      const device = await Device.findByPk(id, {
+        include: [
+          {
+            model: DataPoint,
+          },
+        ],
+        transaction,
+      });
+
+      if (!device) {
+        if (transaction) await transaction.rollback();
+        return null;
+      }
+
+      // 2. 디바이스 정보 업데이트
+      await device.update(
+        {
+          device_type: data.device_type,
+          device_name: data.device_name,
+          manufacturer: data.manufacturer,
+          model: data.model,
+          serial_number: data.serial_number,
+          location: data.location,
+          description: data.description,
+          status: data.status,
+        },
+        { transaction }
+      );
+
+      // 3. 연결 정보 업데이트
+      if (data.DeviceConnection) {
+        await DeviceConnection.update(data.DeviceConnection, {
+          where: { deviceId: id },
+          transaction,
+        });
+      }
+
+      // 4. 데이터 포인트 처리
+      if (data.DataPoints && Array.isArray(data.DataPoints)) {
+        await this.processDataPoints(
+          id,
+          device.DataPoints,
+          data.DataPoints,
+          transaction
+        );
+      }
+
+      await alertService.createAlert({
+        type: "DEVICE_UPDATED",
+        message: `Device updated: ${device.device_name}`,
+        companyId: device.companyId,
+        transaction,
+      });
+
+      // 트랜잭션 커밋
+      await transaction.commit();
+      transaction = null; // 커밋 후 트랜잭션 참조 제거
+
+      // // MQTT 메시지 발행
+      // try {
+      //   await this.publishDeviceUpdate(id, "updated");
+      // } catch (mqttError) {
+      //   logger.error("Failed to publish MQTT message:", mqttError);
+      //   // MQTT 발행 실패는 전체 업데이트를 실패로 처리하지 않음
+      // }
+
+      logger.info("Device updated:", { id });
+
+      // 업데이트된 디바이스 상세 정보 조회
+      return this.getDeviceDetail(id);
+    } catch (error) {
+      logger.error("Failed to update device:", {
+        id,
+        error: error.message,
+        stack: error.stack,
+      });
+
+      // 트랜잭션이 존재하고 아직 완료되지 않았다면 롤백
+      if (transaction && !transaction.finished) {
+        try {
+          await transaction.rollback();
+        } catch (rollbackError) {
+          logger.error("Rollback failed:", rollbackError);
+        }
+      }
+
+      throw error;
+    }
+  }
+
+  // processDataPoints 메서드 개선
+  async processDataPoints(deviceId, existingPoints, newPoints, transaction) {
+    try {
+      // 1. 기존 포인트와 새로운 포인트 매핑
+      const existingPointMap = new Map(
+        existingPoints.map((point) => [point.id, point])
+      );
+
+      const newPointMap = new Map(
+        newPoints.filter((point) => point.id).map((point) => [point.id, point])
+      );
+
+      // 2. 삭제할 포인트 처리
+      const pointsToDelete = existingPoints.filter(
+        (point) => !newPointMap.has(point.id)
+      );
+
+      if (pointsToDelete.length > 0) {
+        await DataPoint.update(
+          { is_active: false },
+          {
+            where: {
+              id: pointsToDelete.map((p) => p.id),
+              deviceId: deviceId,
+            },
+            transaction,
+          }
+        );
+      }
+
+      // 3. 추가할 포인트 처리
+      const pointsToAdd = newPoints.filter(
+        (point) => !point.id || !existingPointMap.has(point.id)
+      );
+
+      if (pointsToAdd.length > 0) {
+        await Promise.all(
+          pointsToAdd.map((point) => {
+            const { id, ...pointData } = point;
+            return DataPoint.create(
+              {
+                ...pointData,
+                deviceId: deviceId,
+              },
+              { transaction }
+            );
+          })
+        );
+      }
+
+      // 4. 수정할 포인트 처리
+      const pointsToUpdate = newPoints.filter(
+        (point) => point.id && existingPointMap.has(point.id)
+      );
+
+      await Promise.all(
+        pointsToUpdate.map((point) => {
+          const { id, ...updateData } = point;
+          return DataPoint.update(updateData, {
+            where: {
+              id: id,
+              deviceId: deviceId,
+            },
+            transaction,
+          });
+        })
+      );
+
+      logger.info("Data points processed:", {
+        deviceId,
+        deleted: pointsToDelete.length,
+        added: pointsToAdd.length,
+        updated: pointsToUpdate.length,
+      });
+    } catch (error) {
+      logger.error("Failed to process data points:", {
+        deviceId,
+        error: error.message,
+        stack: error.stack,
+      });
+      throw error;
+    }
+  }
+
+  // 디바이스 목록 조회
+  async getDevices(filters = {}) {
+    try {
+      const where = {};
+      if (filters.device_type) where.device_type = filters.device_type;
+      if (filters.status) where.status = filters.status;
+
+      const devices = await Device.findAll({
+        where,
+        include: [
+          {
+            model: DeviceConnection,
+            attributes: { exclude: ["protocol_settings"] },
+          },
+          {
+            model: DataPoint,
+            where: { is_active: true },
+            required: false,
+          },
+        ],
+        order: [["created_at", "DESC"]],
+      });
+
+      return devices;
+    } catch (error) {
+      logger.error("Failed to get devices:", error);
+      throw error;
+    }
+  }
+
+  // 디바이스 상세 조회
+  async getDeviceDetail(id) {
+    try {
+      const device = await Device.findByPk(id, {
+        include: [
+          {
+            model: DeviceConnection,
+            attributes: { exclude: ["protocol_settings"] },
+          },
+          {
+            model: DataPoint,
+            where: { is_active: true },
+            required: false,
+          },
+          {
+            model: DeviceStatus,
+            limit: 1,
+            order: [["time", "DESC"]],
+            required: false,
+          },
+        ],
+      });
+
+      return device;
+    } catch (error) {
+      logger.error("Failed to get device detail:", error);
+      throw error;
+    }
+  }
+
+  async deleteDevice(id) {
+    const transaction = await Device.sequelize.transaction();
+
+    try {
+      // 1. 디바이스 존재 확인
+      const device = await Device.findByPk(id, { transaction });
+
+      if (!device) {
+        await transaction.rollback();
+        return false;
+      }
+
+      // 2. 순차적으로 관련 데이터 모두 삭제
+      try {
+        // 데이터 포인트 삭제
+        await DataPoint.destroy({
+          where: { deviceId: id },
+          transaction,
+        });
+
+        // 디바이스 연결 정보 삭제
+        await DeviceConnection.destroy({
+          where: { deviceId: id },
+          transaction,
+        });
+
+        // 디바이스 상태 이력 삭제
+        await DeviceStatus.destroy({
+          where: { deviceId: id },
+          transaction,
+        });
+
+        // 디바이스 삭제
+        await device.destroy({ transaction });
+
+        await alertService.createAlert({
+          type: "DEVICE_DELETED",
+          message: `Device deleted: ${device.device_name}`,
+          companyId: device.companyId,
+          transaction,
+        });
+
+        // 트랜잭션 커밋
+        await transaction.commit();
+
+        logger.info("Device deleted successfully:", { id });
+
+        return true;
+      } catch (error) {
+        logger.error(`Error during delete operation: ${error.message}`);
+        await transaction.rollback();
+        throw error;
+      }
+    } catch (error) {
+      // 트랜잭션이 아직 active 상태인 경우에만 롤백
+      if (transaction && !transaction.finished) {
+        await transaction.rollback();
+      }
+      logger.error("Failed to delete device:", {
+        id,
+        error: error.message,
+        stack: error.stack,
+      });
+      throw error;
+    }
+  }
+
+  // 로깅 헬퍼 메서드 추가
+  async logDeleteOperation(id, step, success = true, error = null) {
+    logger.info(`Delete operation step [${step}]`, {
+      deviceId: id,
+      success,
+      error: error ? error.message : null,
+    });
+  }
+}
+
+module.exports = new DeviceService();
diff --git a/fems-api/src/utils/initialSetup/dataSetup.js b/fems-api/src/utils/initialSetup/dataSetup.js
index 17e5fb1..5d4652b 100644
--- a/fems-api/src/utils/initialSetup/dataSetup.js
+++ b/fems-api/src/utils/initialSetup/dataSetup.js
@@ -15,6 +15,7 @@ const {
   maintenanceLogDefinitions,
   equipmentDataTemplate,
 } = require("./setupData");
+const { initializeDevices } = require("./deviceInitializer");
 const logger = require("../../config/logger");
 const { createMaintenanceData } = require("./maintenanceSetup");
 
@@ -32,6 +33,9 @@ async function createInitialData(companyId, branchId) {
     // 정비 관련 데이터 생성 추가
     await createMaintenanceData(companyId, branchId);
 
+    // 3. 디바이스 관련 데이터 생성
+    await initializeDevices(companyId, branchId);
+
     logger.info("Initial development data created successfully");
   } catch (error) {
     logger.error("Error creating initial data:", error);
diff --git a/fems-api/src/utils/initialSetup/deviceInitializer.js b/fems-api/src/utils/initialSetup/deviceInitializer.js
new file mode 100644
index 0000000..74dc01b
--- /dev/null
+++ b/fems-api/src/utils/initialSetup/deviceInitializer.js
@@ -0,0 +1,263 @@
+// src/utils/initialSetup/deviceInitializer.js
+const logger = require("../config/logger");
+const { Device, DeviceConnection, DataPoint } = require("../models");
+
+const initializeDevices = async () => {
+  try {
+    // 전력계 초기 데이터
+    const powerMeter = {
+      device: {
+        device_type: "PowerMeter",
+        device_name: "power_meter_001",
+        manufacturer: "PowerTech",
+        model: "PM-2133",
+        location: "전기실 1",
+        description: "전력계 1 주요 전력 사용량 측정",
+        status: "ACTIVE",
+        companyId,
+        branchId,
+      },
+      connection: {
+        protocol: "MODBUS_TCP",
+        ip_address: "192.168.0.3",
+        port: 1502,
+        unit_id: 1,
+        connection_timeout: 1000,
+        retry_interval: 2000,
+      },
+      dataPoints: [
+        {
+          tag_name: "instant_power",
+          description: "순시 전력",
+          data_type: "FLOAT",
+          address: "1000",
+          register_type: "HOLDING_REGISTER",
+          scan_rate: 1000,
+          unit: "kW",
+        },
+        {
+          tag_name: "cumulative_power",
+          description: "적산 전력량",
+          data_type: "FLOAT",
+          address: "1002",
+          register_type: "HOLDING_REGISTER",
+          scan_rate: 1000,
+          unit: "kWh",
+        },
+        {
+          tag_name: "voltage",
+          description: "전압",
+          data_type: "FLOAT",
+          address: "1004",
+          register_type: "HOLDING_REGISTER",
+          scan_rate: 1000,
+          unit: "V",
+        },
+        {
+          tag_name: "current",
+          description: "전류",
+          data_type: "FLOAT",
+          address: "1006",
+          register_type: "HOLDING_REGISTER",
+          scan_rate: 1000,
+          unit: "A",
+        },
+        {
+          tag_name: "power_factor",
+          description: "역률",
+          data_type: "FLOAT",
+          address: "1008",
+          register_type: "HOLDING_REGISTER",
+          scan_rate: 1000,
+          unit: "PF",
+        },
+      ],
+    };
+
+    // PLC 초기 데이터
+    const plc = {
+      device: {
+        device_type: "PLC",
+        device_name: "PLC0001",
+        manufacturer: "LSIS",
+        model: "XGB-DN32H",
+        location: "생산동 1층",
+        description: "생산라인 PLC 메인 생산라인 제어",
+        status: "ACTIVE",
+        companyId,
+        branchId,
+      },
+      connection: {
+        protocol: "MODBUS_TCP",
+        ip_address: "192.168.0.8",
+        port: 2004,
+        unit_id: 1,
+        connection_timeout: 1000,
+        retry_interval: 2000,
+      },
+      dataPoints: [
+        // 공정 변수
+        {
+          tag_name: "temperature",
+          description: "공정 온도",
+          data_type: "FLOAT",
+          address: "100",
+          register_type: "HOLDING_REGISTER",
+          scan_rate: 1000,
+          scale_factor: 0.1,
+          unit: "°C",
+        },
+        {
+          tag_name: "pressure",
+          description: "공정 압력",
+          data_type: "FLOAT",
+          address: "102",
+          register_type: "HOLDING_REGISTER",
+          scan_rate: 1000,
+          scale_factor: 0.01,
+          unit: "bar",
+        },
+        {
+          tag_name: "flow_rate",
+          description: "유량",
+          data_type: "FLOAT",
+          address: "104",
+          register_type: "HOLDING_REGISTER",
+          scan_rate: 1000,
+          scale_factor: 0.1,
+          unit: "L/min",
+        },
+        {
+          tag_name: "motor_speed",
+          description: "모터 속도",
+          data_type: "UINT16",
+          address: "106",
+          register_type: "HOLDING_REGISTER",
+          scan_rate: 1000,
+          unit: "RPM",
+        },
+        // 생산 카운터
+        {
+          tag_name: "total_production",
+          description: "총 생산량",
+          data_type: "UINT32",
+          address: "200",
+          register_type: "HOLDING_REGISTER",
+          scan_rate: 1000,
+        },
+        {
+          tag_name: "daily_production",
+          description: "일일 생산량",
+          data_type: "UINT32",
+          address: "202",
+          register_type: "HOLDING_REGISTER",
+          scan_rate: 1000,
+        },
+        {
+          tag_name: "defect_count",
+          description: "불량 수량",
+          data_type: "UINT32",
+          address: "204",
+          register_type: "HOLDING_REGISTER",
+          scan_rate: 1000,
+        },
+        {
+          tag_name: "operation_time",
+          description: "운전 시간",
+          data_type: "UINT32",
+          address: "206",
+          register_type: "HOLDING_REGISTER",
+          scan_rate: 1000,
+          unit: "min",
+        },
+        // 상태 비트
+        {
+          tag_name: "running",
+          description: "운전 상태",
+          data_type: "BOOL",
+          address: "0",
+          register_type: "COIL",
+          scan_rate: 1000,
+        },
+        {
+          tag_name: "auto_mode",
+          description: "자동 모드",
+          data_type: "BOOL",
+          address: "1",
+          register_type: "COIL",
+          scan_rate: 1000,
+        },
+        {
+          tag_name: "error_state",
+          description: "에러 상태",
+          data_type: "BOOL",
+          address: "2",
+          register_type: "COIL",
+          scan_rate: 1000,
+        },
+        {
+          tag_name: "emergency_stop",
+          description: "비상 정지",
+          data_type: "BOOL",
+          address: "3",
+          register_type: "COIL",
+          scan_rate: 1000,
+        },
+        {
+          tag_name: "maintenance_mode",
+          description: "유지보수 모드",
+          data_type: "BOOL",
+          address: "4",
+          register_type: "COIL",
+          scan_rate: 1000,
+        },
+      ],
+    };
+
+    // 디바이스 생성 함수
+    const createDeviceWithDetails = async (deviceData) => {
+      try {
+        // 디바이스 생성
+        const device = await Device.create(deviceData.device);
+        logger.info(
+          `Created device: ${device.id} for company: ${companyId}, branch: ${branchId}`
+        );
+
+        // 연결 정보 생성
+        await DeviceConnection.create({
+          deviceId: device.id,
+          ...deviceData.connection,
+        });
+        logger.info(`Created connection for device: ${device.id}`);
+
+        // 데이터 포인트 생성
+        const dataPointPromises = deviceData.dataPoints.map((point) =>
+          DataPoint.create({
+            deviceId: device.id,
+            ...point,
+          })
+        );
+        await Promise.all(dataPointPromises);
+
+        logger.info(`Created data points for device: ${device.id}`);
+        return device;
+      } catch (error) {
+        logger.error(`Failed to create device details: ${error.message}`);
+        throw error;
+      }
+    };
+
+    // 디바이스 생성 실행
+    await createDeviceWithDetails(powerMeter);
+    await createDeviceWithDetails(plc);
+
+    logger.info("Device initialization completed successfully");
+  } catch (error) {
+    logger.error("Failed to initialize devices:", error);
+    throw error;
+  }
+};
+
+module.exports = {
+  initializeDevices,
+};
diff --git a/fems-app/src/app/(equipment)/devices/[id]/page.tsx b/fems-app/src/app/(equipment)/devices/[id]/page.tsx
new file mode 100644
index 0000000..c72bac4
--- /dev/null
+++ b/fems-app/src/app/(equipment)/devices/[id]/page.tsx
@@ -0,0 +1,102 @@
+// src/app/devices/list/[id]/page.tsx
+"use client";
+
+import React from "react";
+import { useQuery } from "@tanstack/react-query";
+import { useRouter } from "next/navigation";
+import { DeviceForm } from "../components/DeviceForm";
+import { api } from "@/lib/api";
+import { DataPoint, Device } from "@/types/device";
+import { Alert, AlertDescription } from "@/components/ui/alert";
+import { AlertCircle } from "lucide-react";
+import { Button } from "@/components/ui/button";
+
+export default function EditDevicePage({ params }: { params: { id: string } }) {
+  const router = useRouter();
+
+  // 디바이스 정보 조회 (데이터 포인트 포함)
+  const {
+    data: device,
+    isError,
+    isLoading,
+  } = useQuery<Device>({
+    queryKey: ["device", params.id],
+    queryFn: async () => {
+      const { data } = await api.get(`/api/v1/app/devices/${params.id}`);
+      console.log(data);
+      return {
+        ...data,
+        // 백엔드에서 받은 데이터 포인트를 프론트엔드 형식으로 변환
+        data_points: data.DataPoints?.map((point: DataPoint) => ({
+          id: point.id,
+          tag_name: point.tag_name || "",
+          description: point.description || "",
+          data_type: point.data_type,
+          address: point.address,
+          register_type: point.register_type || "HOLDING_REGISTER",
+          scan_rate: point.scan_rate || 1000,
+          scale_factor: point.scale_factor || 1,
+          offset: point.offset || 0,
+          unit: point.unit || "",
+          is_active: point.is_active !== false,
+        })),
+        // connection 데이터도 정규화
+        connection: {
+          protocol: data.DeviceConnection?.protocol || "MODBUS_TCP",
+          ip_address: data.DeviceConnection?.ip_address || "",
+          port: data.DeviceConnection?.port || 502,
+          unit_id: data.DeviceConnection?.unit_id || 1,
+          connection_timeout: data.DeviceConnection?.connection_timeout || 1000,
+          retry_interval: data.DeviceConnection?.retry_interval || 5000,
+          protocol_settings: data.DeviceConnection?.protocol_settings || {},
+        },
+      };
+    },
+    // staleTime: 0, // 항상 최신 데이터를 가져오도록 설정
+    // cacheTime: 0, // 캐시를 사용하지 않음
+  });
+
+  if (isLoading) {
+    return (
+      <div className="container mx-auto py-6">
+        <div>디바이스 정보를 불러오는 중...</div>
+      </div>
+    );
+  }
+
+  if (isError) {
+    return (
+      <div className="container mx-auto py-6">
+        <Alert variant="destructive">
+          <AlertCircle className="h-4 w-4" />
+          <AlertDescription>
+            디바이스 정보를 불러오는데 실패했습니다.
+          </AlertDescription>
+        </Alert>
+        <Button
+          className="mt-4"
+          variant="outline"
+          onClick={() => router.push("/devices/list")}
+        >
+          목록으로 돌아가기
+        </Button>
+      </div>
+    );
+  }
+
+  return (
+    <div className="container mx-auto py-6">
+      <div className="mb-6">
+        <h1 className="text-3xl font-bold">디바이스 수정</h1>
+        <p className="text-muted-foreground">디바이스 정보를 수정합니다.</p>
+      </div>
+      {device && (
+        <DeviceForm
+          initialData={device}
+          onCancel={() => router.push("/devices/list")}
+          onSuccess={() => router.push("/devices/list")}
+        />
+      )}
+    </div>
+  );
+}
diff --git a/fems-app/src/app/(equipment)/devices/components/Detail/DeviceDetailDialog.tsx b/fems-app/src/app/(equipment)/devices/components/Detail/DeviceDetailDialog.tsx
new file mode 100644
index 0000000..23c114a
--- /dev/null
+++ b/fems-app/src/app/(equipment)/devices/components/Detail/DeviceDetailDialog.tsx
@@ -0,0 +1,239 @@
+// src/app/devices/components/Detail/DeviceDetailDialog.tsx
+"use client";
+
+import React from "react";
+import {
+  Dialog,
+  DialogContent,
+  DialogHeader,
+  DialogTitle,
+  DialogDescription,
+} from "@/components/ui/dialog";
+import { Badge } from "@/components/ui/badge";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { Wifi, WifiOff, AlertCircle, Terminal, Settings2 } from "lucide-react";
+import { DataPoint, Device } from "@/types/device";
+import { useQuery } from "@tanstack/react-query";
+import { api } from "@/lib/api";
+
+interface DeviceDetailDialogProps {
+  device: Device | null;
+  isOpen: boolean;
+  onClose: () => void;
+}
+
+export function DeviceDetailDialog({
+  device,
+  isOpen,
+  onClose,
+}: DeviceDetailDialogProps) {
+  // Fetch device details
+  const { data: deviceDetail } = useQuery({
+    queryKey: ["device", device?.id],
+    queryFn: async () => {
+      if (!device) return null;
+      const { data } = await api.get(`/api/v1/app/devices/${device.id}`);
+      return {
+        ...data,
+        // connection 데이터 정규화
+        connection: {
+          protocol: data.DeviceConnection?.protocol || "MODBUS_TCP",
+          ip_address: data.DeviceConnection?.ip_address || "",
+          port: data.DeviceConnection?.port || 502,
+          unit_id: data.DeviceConnection?.unit_id || 1,
+          connection_timeout: data.DeviceConnection?.connection_timeout || 1000,
+          retry_interval: data.DeviceConnection?.retry_interval || 5000,
+          protocol_settings: data.DeviceConnection?.protocol_settings || {},
+        },
+        // 데이터 포인트 정규화
+        data_points: data.DataPoints?.map((point: DataPoint) => ({
+          id: point.id,
+          tag_name: point.tag_name || "",
+          description: point.description || "",
+          data_type: point.data_type,
+          address: point.address,
+          register_type: point.register_type || "HOLDING_REGISTER",
+          scan_rate: point.scan_rate || 1000,
+          scale_factor: point.scale_factor || 1,
+          offset: point.offset || 0,
+          unit: point.unit || "",
+          is_active: point.is_active !== false,
+        })),
+      };
+    },
+    enabled: !!device && isOpen,
+  });
+
+  if (!device || !deviceDetail) return null;
+
+  const statusMap = {
+    ACTIVE: { label: "활성", icon: Wifi, variant: "default" },
+    INACTIVE: { label: "비활성", icon: WifiOff, variant: "secondary" },
+    MAINTENANCE: { label: "유지보수", icon: Settings2, variant: "outline" },
+    ERROR: { label: "오류", icon: AlertCircle, variant: "destructive" },
+  } as const;
+
+  const protocolMap = {
+    MODBUS_TCP: "Modbus TCP",
+    MODBUS_RTU: "Modbus RTU",
+    OPC_UA: "OPC UA",
+    MQTT: "MQTT",
+    BACNET: "BACnet",
+  } as const;
+
+  const status = statusMap[deviceDetail.status as keyof typeof statusMap];
+  const StatusIcon = status.icon;
+
+  return (
+    <Dialog open={isOpen} onOpenChange={onClose}>
+      <DialogContent className="max-w-4xl max-h-[80vh] overflow-y-auto">
+        <DialogHeader>
+          <DialogTitle>디바이스 상세 정보</DialogTitle>
+          <DialogDescription>
+            선택한 디바이스의 상세 정보를 확인합니다.
+          </DialogDescription>
+        </DialogHeader>
+
+        <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
+          {/* 기본 정보 */}
+          <Card>
+            <CardHeader>
+              <CardTitle>기본 정보</CardTitle>
+            </CardHeader>
+            <CardContent className="space-y-4">
+              <div className="grid grid-cols-2 gap-2">
+                <div className="text-sm text-muted-foreground">디바이스 ID</div>
+                <div>{deviceDetail.id}</div>
+
+                <div className="text-sm text-muted-foreground">디바이스명</div>
+                <div>{deviceDetail.device_name}</div>
+
+                <div className="text-sm text-muted-foreground">유형</div>
+                <div>{deviceDetail.device_type}</div>
+
+                <div className="text-sm text-muted-foreground">상태</div>
+                <div>
+                  <Badge variant={status.variant}>
+                    <StatusIcon className="w-3 h-3 mr-1" />
+                    {status.label}
+                  </Badge>
+                </div>
+
+                <div className="text-sm text-muted-foreground">설치 위치</div>
+                <div>{deviceDetail.location}</div>
+
+                <div className="text-sm text-muted-foreground">설명</div>
+                <div>{deviceDetail.description || "-"}</div>
+              </div>
+            </CardContent>
+          </Card>
+
+          {/* 하드웨어 정보 */}
+          <Card>
+            <CardHeader>
+              <CardTitle>하드웨어 정보</CardTitle>
+            </CardHeader>
+            <CardContent className="space-y-4">
+              <div className="grid grid-cols-2 gap-2">
+                <div className="text-sm text-muted-foreground">제조사</div>
+                <div>{deviceDetail.manufacturer}</div>
+
+                <div className="text-sm text-muted-foreground">모델</div>
+                <div>{deviceDetail.model}</div>
+
+                <div className="text-sm text-muted-foreground">시리얼 번호</div>
+                <div>{deviceDetail.serial_number || "-"}</div>
+              </div>
+            </CardContent>
+          </Card>
+
+          {/* 통신 설정 */}
+          <Card>
+            <CardHeader>
+              <CardTitle>통신 설정</CardTitle>
+            </CardHeader>
+            <CardContent className="space-y-4">
+              <div className="grid grid-cols-2 gap-2">
+                <div className="text-sm text-muted-foreground">프로토콜</div>
+                <div>
+                  {deviceDetail.connection && (
+                    <Badge variant="outline">
+                      <Terminal className="w-3 h-3 mr-1" />
+                      {
+                        protocolMap[
+                          deviceDetail.connection
+                            .protocol as keyof typeof protocolMap
+                        ]
+                      }
+                    </Badge>
+                  )}
+                </div>
+
+                {deviceDetail.connection?.ip_address && (
+                  <>
+                    <div className="text-sm text-muted-foreground">IP 주소</div>
+                    <div>{deviceDetail.connection.ip_address}</div>
+
+                    <div className="text-sm text-muted-foreground">포트</div>
+                    <div>{deviceDetail.connection.port}</div>
+
+                    <div className="text-sm text-muted-foreground">Unit ID</div>
+                    <div>{deviceDetail.connection.unit_id}</div>
+                  </>
+                )}
+
+                {deviceDetail.connection && (
+                  <>
+                    <div className="text-sm text-muted-foreground">
+                      연결 타임아웃
+                    </div>
+                    <div>{deviceDetail.connection.connection_timeout}ms</div>
+
+                    <div className="text-sm text-muted-foreground">
+                      재시도 간격
+                    </div>
+                    <div>{deviceDetail.connection.retry_interval}ms</div>
+                  </>
+                )}
+              </div>
+            </CardContent>
+          </Card>
+
+          {/* 데이터 포인트 */}
+          <Card>
+            <CardHeader>
+              <CardTitle>데이터 포인트</CardTitle>
+            </CardHeader>
+            <CardContent>
+              {deviceDetail.data_points &&
+              deviceDetail.data_points.length > 0 ? (
+                <div className="space-y-4">
+                  {deviceDetail.data_points.map((point: DataPoint) => (
+                    <div key={point.id} className="border rounded-lg p-3">
+                      <div className="flex justify-between items-start">
+                        <div className="font-medium">{point.tag_name}</div>
+                        <Badge variant="outline">{point.data_type}</Badge>
+                      </div>
+                      <div className="text-sm text-muted-foreground mt-1">
+                        주소: {point.address}
+                        {point.register_type && ` (${point.register_type})`}
+                      </div>
+                      <div className="text-sm mt-1">
+                        스캔 주기: {point.scan_rate}ms
+                        {point.unit && ` | 단위: ${point.unit}`}
+                      </div>
+                    </div>
+                  ))}
+                </div>
+              ) : (
+                <div className="text-muted-foreground text-center py-4">
+                  등록된 데이터 포인트가 없습니다.
+                </div>
+              )}
+            </CardContent>
+          </Card>
+        </div>
+      </DialogContent>
+    </Dialog>
+  );
+}
diff --git a/fems-app/src/app/(equipment)/devices/components/DeviceForm/DataPointFormFields.tsx b/fems-app/src/app/(equipment)/devices/components/DeviceForm/DataPointFormFields.tsx
new file mode 100644
index 0000000..13ee66a
--- /dev/null
+++ b/fems-app/src/app/(equipment)/devices/components/DeviceForm/DataPointFormFields.tsx
@@ -0,0 +1,249 @@
+// src/app/devices/list/components/DeviceForm/DataPointFormFields.tsx
+import React from "react";
+import { UseFormReturn } from "react-hook-form";
+import {
+  FormField,
+  FormItem,
+  FormLabel,
+  FormControl,
+  FormMessage,
+} from "@/components/ui/form";
+import { Input } from "@/components/ui/input";
+import {
+  Select,
+  SelectContent,
+  SelectItem,
+  SelectTrigger,
+  SelectValue,
+} from "@/components/ui/select";
+import { DeviceFormData } from "./schema";
+
+interface DataPointFormFieldsProps {
+  form: UseFormReturn<DeviceFormData>;
+  index: number;
+  isSubmitting: boolean;
+}
+
+export function DataPointFormFields({
+  form,
+  index,
+  isSubmitting,
+}: DataPointFormFieldsProps) {
+  return (
+    <div className="space-y-8 max-w-6xl mx-auto">
+      <div className="space-y-4">
+        <div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-2">
+          {/* 태그명 */}
+          <FormField
+            control={form.control}
+            name={`data_points.${index}.tag_name`}
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>태그명</FormLabel>
+                <FormControl>
+                  <Input
+                    placeholder="예: temperature_sensor_01"
+                    {...field}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 데이터 타입 */}
+          <FormField
+            control={form.control}
+            name={`data_points.${index}.data_type`}
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>데이터 타입</FormLabel>
+                <Select
+                  onValueChange={field.onChange}
+                  value={field.value}
+                  disabled={isSubmitting}
+                >
+                  <FormControl>
+                    <SelectTrigger>
+                      <SelectValue placeholder="데이터 타입 선택" />
+                    </SelectTrigger>
+                  </FormControl>
+                  <SelectContent>
+                    <SelectItem value="BOOL">Boolean</SelectItem>
+                    <SelectItem value="INT16">Int16</SelectItem>
+                    <SelectItem value="UINT16">UInt16</SelectItem>
+                    <SelectItem value="INT32">Int32</SelectItem>
+                    <SelectItem value="UINT32">UInt32</SelectItem>
+                    <SelectItem value="FLOAT">Float</SelectItem>
+                    <SelectItem value="DOUBLE">Double</SelectItem>
+                    <SelectItem value="STRING">String</SelectItem>
+                  </SelectContent>
+                </Select>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 레지스터 타입 */}
+          <FormField
+            control={form.control}
+            name={`data_points.${index}.register_type`}
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>레지스터 타입</FormLabel>
+                <Select
+                  onValueChange={field.onChange}
+                  value={field.value}
+                  disabled={isSubmitting}
+                >
+                  <FormControl>
+                    <SelectTrigger>
+                      <SelectValue placeholder="레지스터 타입 선택" />
+                    </SelectTrigger>
+                  </FormControl>
+                  <SelectContent>
+                    <SelectItem value="COIL">Coil</SelectItem>
+                    <SelectItem value="DISCRETE_INPUT">
+                      Discrete Input
+                    </SelectItem>
+                    <SelectItem value="HOLDING_REGISTER">
+                      Holding Register
+                    </SelectItem>
+                    <SelectItem value="INPUT_REGISTER">
+                      Input Register
+                    </SelectItem>
+                  </SelectContent>
+                </Select>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 주소 */}
+          <FormField
+            control={form.control}
+            name={`data_points.${index}.address`}
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>주소</FormLabel>
+                <FormControl>
+                  <Input
+                    placeholder="예: 40001"
+                    {...field}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 스캔 주기 */}
+          <FormField
+            control={form.control}
+            name={`data_points.${index}.scan_rate`}
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>스캔 주기 (ms)</FormLabel>
+                <FormControl>
+                  <Input
+                    type="number"
+                    min="100"
+                    placeholder="예: 1000"
+                    {...field}
+                    onChange={(e) => field.onChange(Number(e.target.value))}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 스케일 팩터 */}
+          <FormField
+            control={form.control}
+            name={`data_points.${index}.scale_factor`}
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>스케일 팩터</FormLabel>
+                <FormControl>
+                  <Input
+                    type="number"
+                    step="0.001"
+                    placeholder="예: 1"
+                    {...field}
+                    onChange={(e) => field.onChange(Number(e.target.value))}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 오프셋 */}
+          <FormField
+            control={form.control}
+            name={`data_points.${index}.offset`}
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>오프셋</FormLabel>
+                <FormControl>
+                  <Input
+                    type="number"
+                    step="0.001"
+                    placeholder="예: 0"
+                    {...field}
+                    onChange={(e) => field.onChange(Number(e.target.value))}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 단위 */}
+          <FormField
+            control={form.control}
+            name={`data_points.${index}.unit`}
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>단위</FormLabel>
+                <FormControl>
+                  <Input
+                    placeholder="예: °C"
+                    {...field}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+        </div>
+
+        {/* 설명 */}
+        <FormField
+          control={form.control}
+          name={`data_points.${index}.description`}
+          render={({ field }) => (
+            <FormItem>
+              <FormLabel>설명</FormLabel>
+              <FormControl>
+                <Input
+                  placeholder="예: 온도 센서 01"
+                  {...field}
+                  disabled={isSubmitting}
+                />
+              </FormControl>
+              <FormMessage />
+            </FormItem>
+          )}
+        />
+      </div>
+    </div>
+  );
+}
diff --git a/fems-app/src/app/(equipment)/devices/components/DeviceForm/DeviceFormFields.tsx b/fems-app/src/app/(equipment)/devices/components/DeviceForm/DeviceFormFields.tsx
new file mode 100644
index 0000000..d116f29
--- /dev/null
+++ b/fems-app/src/app/(equipment)/devices/components/DeviceForm/DeviceFormFields.tsx
@@ -0,0 +1,365 @@
+// src/app/devices/list/components/DeviceForm/DeviceFormFields.tsx
+import React from "react";
+import { UseFormReturn } from "react-hook-form";
+import {
+  FormField,
+  FormItem,
+  FormLabel,
+  FormControl,
+  FormMessage,
+} from "@/components/ui/form";
+import { Input } from "@/components/ui/input";
+import { Textarea } from "@/components/ui/textarea";
+import {
+  Select,
+  SelectContent,
+  SelectItem,
+  SelectTrigger,
+  SelectValue,
+} from "@/components/ui/select";
+import { DeviceFormData } from "./schema";
+
+interface DeviceFormFieldsProps {
+  form: UseFormReturn<DeviceFormData>;
+  isSubmitting: boolean;
+}
+
+export function DeviceFormFields({
+  form,
+  isSubmitting,
+}: DeviceFormFieldsProps) {
+  // 프로토콜에 따른 필드 표시 여부
+
+  return (
+    <div className="space-y-8 max-w-6xl mx-auto">
+      {/* 기본 정보 섹션 */}
+      <div className="space-y-4">
+        <h3 className="text-lg font-medium border-b pb-2">기본 정보</h3>
+        <div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
+          {/* 디바이스명 */}
+          <FormField
+            control={form.control}
+            name="device_name"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>디바이스명</FormLabel>
+                <FormControl>
+                  <Input
+                    placeholder="디바이스명을 입력하세요"
+                    {...field}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 디바이스 유형 */}
+          <FormField
+            control={form.control}
+            name="device_type"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>디바이스 유형</FormLabel>
+                <Select
+                  onValueChange={field.onChange}
+                  value={field.value}
+                  disabled={isSubmitting}
+                >
+                  <FormControl>
+                    <SelectTrigger>
+                      <SelectValue placeholder="디바이스 유형을 선택하세요" />
+                    </SelectTrigger>
+                  </FormControl>
+                  <SelectContent>
+                    <SelectItem value="PLC">PLC</SelectItem>
+                    <SelectItem value="PowerMeter">전력계</SelectItem>
+                    <SelectItem value="Sensor">센서</SelectItem>
+                    <SelectItem value="Gateway">게이트웨이</SelectItem>
+                    <SelectItem value="Other">기타</SelectItem>
+                  </SelectContent>
+                </Select>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 제조사 */}
+          <FormField
+            control={form.control}
+            name="manufacturer"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>제조사</FormLabel>
+                <FormControl>
+                  <Input
+                    placeholder="제조사를 입력하세요"
+                    {...field}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 모델명 */}
+          <FormField
+            control={form.control}
+            name="model"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>모델명</FormLabel>
+                <FormControl>
+                  <Input
+                    placeholder="모델명을 입력하세요"
+                    {...field}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 시리얼 번호 */}
+          <FormField
+            control={form.control}
+            name="serial_number"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>시리얼 번호</FormLabel>
+                <FormControl>
+                  <Input
+                    placeholder="시리얼 번호를 입력하세요"
+                    {...field}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 설치 위치 */}
+          <FormField
+            control={form.control}
+            name="location"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>설치 위치</FormLabel>
+                <FormControl>
+                  <Input
+                    placeholder="설치 위치를 입력하세요"
+                    {...field}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+        </div>
+
+        {/* 설명 */}
+        <FormField
+          control={form.control}
+          name="description"
+          render={({ field }) => (
+            <FormItem>
+              <FormLabel>설명</FormLabel>
+              <FormControl>
+                <Textarea
+                  placeholder="디바이스에 대한 설명을 입력하세요"
+                  {...field}
+                  disabled={isSubmitting}
+                />
+              </FormControl>
+              <FormMessage />
+            </FormItem>
+          )}
+        />
+      </div>
+
+      {/* 통신 설정 섹션 */}
+      <div className="space-y-4">
+        <h3 className="text-lg font-medium border-b pb-2">통신 설정</h3>
+        <div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
+          {/* 통신 프로토콜 */}
+          <FormField
+            control={form.control}
+            name="connection.protocol"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>통신 프로토콜</FormLabel>
+                <Select
+                  onValueChange={field.onChange}
+                  value={field.value || "MODBUS_TCP"}
+                  disabled={isSubmitting}
+                >
+                  <FormControl>
+                    <SelectTrigger>
+                      <SelectValue placeholder="프로토콜을 선택하세요" />
+                    </SelectTrigger>
+                  </FormControl>
+                  <SelectContent>
+                    <SelectItem value="MODBUS_TCP">Modbus TCP</SelectItem>
+                    <SelectItem value="MODBUS_RTU">Modbus RTU</SelectItem>
+                    <SelectItem value="OPC_UA">OPC UA</SelectItem>
+                    <SelectItem value="MQTT">MQTT</SelectItem>
+                    <SelectItem value="BACNET">BACnet</SelectItem>
+                  </SelectContent>
+                </Select>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* IP 주소 - 항상 표시 */}
+          <FormField
+            control={form.control}
+            name="connection.ip_address"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>IP 주소</FormLabel>
+                <FormControl>
+                  <Input
+                    placeholder="예: 192.168.0.100"
+                    {...field}
+                    value={field.value ?? ""} // null, undefined 모두 처리
+                    onChange={(e) => field.onChange(e.target.value || "")}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 포트 - 항상 표시 */}
+          <FormField
+            control={form.control}
+            name="connection.port"
+            render={({ field: { onChange, value, ...field } }) => (
+              <FormItem>
+                <FormLabel>포트</FormLabel>
+                <FormControl>
+                  <Input
+                    type="number"
+                    placeholder="예: 502"
+                    {...field}
+                    value={value || ""} // null 방지
+                    onChange={(e) => onChange(Number(e.target.value) || 502)}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* Unit ID - 항상 표시 */}
+          <FormField
+            control={form.control}
+            name="connection.unit_id"
+            render={({ field: { onChange, value, ...field } }) => (
+              <FormItem>
+                <FormLabel>Unit ID</FormLabel>
+                <FormControl>
+                  <Input
+                    type="number"
+                    placeholder="예: 1"
+                    {...field}
+                    value={value || ""} // null 방지
+                    onChange={(e) => onChange(Number(e.target.value) || 1)}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 연결 타임아웃 */}
+          <FormField
+            control={form.control}
+            name="connection.connection_timeout"
+            render={({ field: { onChange, value, ...field } }) => (
+              <FormItem>
+                <FormLabel>연결 타임아웃 (ms)</FormLabel>
+                <FormControl>
+                  <Input
+                    type="number"
+                    placeholder="예: 1000"
+                    {...field}
+                    value={value || ""} // null 방지
+                    onChange={(e) => onChange(Number(e.target.value) || 1000)}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+
+          {/* 재시도 간격 */}
+          <FormField
+            control={form.control}
+            name="connection.retry_interval"
+            render={({ field: { onChange, value, ...field } }) => (
+              <FormItem>
+                <FormLabel>재시도 간격 (ms)</FormLabel>
+                <FormControl>
+                  <Input
+                    type="number"
+                    placeholder="예: 5000"
+                    {...field}
+                    value={value || ""} // null 방지
+                    onChange={(e) => onChange(Number(e.target.value) || 5000)}
+                    disabled={isSubmitting}
+                  />
+                </FormControl>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+        </div>
+      </div>
+
+      {/* 상태 설정 섹션 */}
+      <div className="space-y-4">
+        <h3 className="text-lg font-medium border-b pb-2">상태 설정</h3>
+        <div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
+          <FormField
+            control={form.control}
+            name="status"
+            render={({ field }) => (
+              <FormItem>
+                <FormLabel>상태</FormLabel>
+                <Select
+                  onValueChange={field.onChange}
+                  value={field.value}
+                  disabled={isSubmitting}
+                >
+                  <FormControl>
+                    <SelectTrigger>
+                      <SelectValue placeholder="상태를 선택하세요" />
+                    </SelectTrigger>
+                  </FormControl>
+                  <SelectContent>
+                    <SelectItem value="ACTIVE">활성</SelectItem>
+                    <SelectItem value="INACTIVE">비활성</SelectItem>
+                    <SelectItem value="MAINTENANCE">유지보수</SelectItem>
+                    <SelectItem value="ERROR">오류</SelectItem>
+                  </SelectContent>
+                </Select>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+        </div>
+      </div>
+    </div>
+  );
+}
diff --git a/fems-app/src/app/(equipment)/devices/components/DeviceForm/index.tsx b/fems-app/src/app/(equipment)/devices/components/DeviceForm/index.tsx
new file mode 100644
index 0000000..8cd3476
--- /dev/null
+++ b/fems-app/src/app/(equipment)/devices/components/DeviceForm/index.tsx
@@ -0,0 +1,295 @@
+// src/app/devices/list/components/DeviceForm/index.tsx
+"use client";
+
+import React from "react";
+import { useForm } from "react-hook-form";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { Form } from "@/components/ui/form";
+import { Button } from "@/components/ui/button";
+import { DeviceFormFields } from "./DeviceFormFields";
+import { useDeviceForm } from "./useDeviceForm";
+import { deviceSchema } from "./schema";
+import { DataPointFormFields } from "./DataPointFormFields";
+import type {
+  DataPoint,
+  DeviceFormProps,
+  DeviceType,
+  DeviceStatus,
+  ProtocolType,
+  RegisterType,
+} from "@/types/device";
+import {
+  AlertDialog,
+  AlertDialogAction,
+  AlertDialogCancel,
+  AlertDialogContent,
+  AlertDialogDescription,
+  AlertDialogFooter,
+  AlertDialogHeader,
+  AlertDialogTitle,
+} from "@/components/ui/alert-dialog";
+import type { z } from "zod";
+
+export function DeviceForm({
+  initialData,
+  onCancel,
+  onSuccess,
+}: DeviceFormProps) {
+  const [deleteIndex, setDeleteIndex] = React.useState<number | null>(null);
+  const { createDevice, updateDevice, isLoading } = useDeviceForm({
+    deviceId: initialData?.id,
+    onSuccess,
+  });
+
+  // 기본값 설정을 처리하는 함수
+  const getDefaultValues = () => {
+    if (initialData) {
+      return {
+        id: initialData.id || "",
+        device_name: initialData.device_name || "",
+        device_type: (initialData.device_type as DeviceType) || "PLC",
+        description: initialData.description || "",
+        manufacturer: initialData.manufacturer || "",
+        model: initialData.model || "",
+        serial_number: initialData.serial_number || "",
+        location: initialData.location || "",
+        status: (initialData.status as DeviceStatus) || "ACTIVE",
+        connection: {
+          protocol:
+            (initialData.connection?.protocol as ProtocolType) || "MODBUS_TCP",
+          ip_address: initialData.connection?.ip_address || "",
+          port: initialData.connection?.port || 502,
+          unit_id: initialData.connection?.unit_id || 1,
+          connection_timeout:
+            initialData.connection?.connection_timeout || 1000,
+          retry_interval: initialData.connection?.retry_interval || 5000,
+          protocol_settings: initialData.connection?.protocol_settings || {},
+        },
+        data_points:
+          (initialData.data_points || []).map((point: DataPoint) => ({
+            id: point.id.toString(),
+            tag_name: point.tag_name || "",
+            description: point.description || "",
+            data_type: point.data_type as DataPoint["data_type"],
+            address: point.address || "",
+            register_type: point.register_type as RegisterType,
+            scan_rate: point.scan_rate || 1000,
+            scale_factor: point.scale_factor || 1,
+            offset: point.offset || 0,
+            unit: point.unit || "",
+            is_active: point.is_active !== false,
+          })) || [],
+      };
+    }
+
+    // 신규 생성시 기본값
+    return {
+      device_name: "",
+      device_type: "PLC" as DeviceType,
+      description: "",
+      manufacturer: "",
+      model: "",
+      serial_number: "",
+      location: "",
+      status: "ACTIVE" as DeviceStatus,
+      connection: {
+        protocol: "MODBUS_TCP" as ProtocolType,
+        ip_address: "",
+        port: 502,
+        unit_id: 1,
+        connection_timeout: 1000,
+        retry_interval: 5000,
+        protocol_settings: {},
+      },
+      data_points: [],
+    };
+  };
+
+  const form = useForm<z.infer<typeof deviceSchema>>({
+    resolver: zodResolver(deviceSchema),
+    defaultValues: getDefaultValues(),
+  });
+
+  // 제출 핸들러
+  const handleSubmit = async (data: z.infer<typeof deviceSchema>) => {
+    try {
+      if (initialData?.id) {
+        await updateDevice(data);
+      } else {
+        await createDevice(data);
+      }
+    } catch (error) {
+      console.error("Form submission error:", error);
+    }
+  };
+
+  const handleDeletePoint = (index: number) => {
+    const currentPoints = form.getValues("data_points");
+    form.setValue(
+      "data_points",
+      currentPoints.filter((_, i) => i !== index)
+    );
+    setDeleteIndex(null);
+  };
+
+  return (
+    <Form {...form}>
+      <form
+        onSubmit={form.handleSubmit(handleSubmit)}
+        className="space-y-6 max-w-6xl mx-auto"
+      >
+        <DeviceFormFields form={form} isSubmitting={isLoading} />
+
+        {/* 데이터 포인트 섹션 */}
+        <div className="space-y-4">
+          <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 border-b pb-2">
+            <h3 className="text-lg font-medium">데이터 포인트</h3>
+            <Button
+              type="button"
+              onClick={() => {
+                const currentPoints = form.getValues("data_points") || [];
+                form.setValue("data_points", [
+                  ...currentPoints,
+                  {
+                    tag_name: "",
+                    description: "",
+                    data_type: "UINT16",
+                    address: "",
+                    register_type: "HOLDING_REGISTER",
+                    scan_rate: 1000,
+                    scale_factor: 1,
+                    offset: 0,
+                    unit: "",
+                    is_active: true,
+                  },
+                ]);
+              }}
+              disabled={isLoading}
+              className="w-full sm:w-auto"
+            >
+              데이터 포인트 추가
+            </Button>
+          </div>
+
+          {/* 데이터 포인트 그리드 */}
+          <div className="grid gap-4 grid-cols-1 md:grid-cols-2 xl:grid-cols-2">
+            {form.watch("data_points")?.map((point, index) => (
+              <div
+                key={index}
+                className="border rounded-lg bg-white shadow-sm hover:shadow-md transition-shadow"
+              >
+                <div className="border-b p-4">
+                  <div className="flex justify-between items-center">
+                    <h4 className="text-sm font-medium flex items-center gap-2">
+                      <span className="flex items-center justify-center w-6 h-6 rounded-full bg-primary/10 text-primary text-xs">
+                        {index + 1}
+                      </span>
+                      <span>
+                        데이터 포인트: {point.tag_name || "새 포인트"}
+                      </span>
+                    </h4>
+                    <Button
+                      type="button"
+                      variant="ghost"
+                      size="sm"
+                      onClick={() => setDeleteIndex(index)}
+                      disabled={isLoading}
+                      className="text-red-500 hover:text-red-700 hover:bg-red-50"
+                    >
+                      삭제
+                    </Button>
+                  </div>
+                </div>
+                <div className="p-4">
+                  <DataPointFormFields
+                    form={form}
+                    index={index}
+                    isSubmitting={isLoading}
+                  />
+                </div>
+              </div>
+            ))}
+          </div>
+
+          {/* 빈 상태 표시 */}
+          {(!form.watch("data_points") ||
+            form.watch("data_points").length === 0) && (
+            <div className="text-center py-8 border-2 border-dashed rounded-lg">
+              <p className="text-gray-500">
+                등록된 데이터 포인트가 없습니다.
+                <br />
+                위의 &apos;데이터 포인트 추가&apos; 버튼을 클릭하여
+                추가해주세요.
+              </p>
+            </div>
+          )}
+        </div>
+
+        {/* 하단 버튼 */}
+        <div className="flex flex-col sm:flex-row justify-end gap-4 pt-4 border-t">
+          <Button
+            type="button"
+            variant="outline"
+            onClick={onCancel}
+            disabled={isLoading}
+            className="w-full sm:w-auto"
+          >
+            취소
+          </Button>
+          <Button
+            type="submit"
+            disabled={isLoading}
+            className="w-full sm:w-auto"
+          >
+            {isLoading ? (
+              <span className="flex items-center justify-center gap-2">
+                <span className="animate-spin">⏳</span>
+                처리중...
+              </span>
+            ) : initialData?.id ? ( // id 존재 여부로 신규/수정 구분
+              "수정하기"
+            ) : (
+              "등록하기"
+            )}
+          </Button>
+        </div>
+
+        {/* 삭제 확인 대화상자 */}
+        <AlertDialog
+          open={deleteIndex !== null}
+          onOpenChange={() => setDeleteIndex(null)}
+        >
+          <AlertDialogContent>
+            <AlertDialogHeader>
+              <AlertDialogTitle>데이터 포인트 삭제</AlertDialogTitle>
+              <AlertDialogDescription>
+                이 데이터 포인트를 삭제하시겠습니까?
+                {deleteIndex !== null &&
+                  form.watch(`data_points.${deleteIndex}.tag_name`) && (
+                    <span className="mt-2 block font-medium text-gray-900">
+                      태그명:{" "}
+                      {form.watch(`data_points.${deleteIndex}.tag_name`)}
+                    </span>
+                  )}
+                <span className="mt-2 block text-red-600">
+                  삭제한 데이터 포인트는 복구할 수 없습니다.
+                </span>
+              </AlertDialogDescription>
+            </AlertDialogHeader>
+            <AlertDialogFooter>
+              <AlertDialogCancel>취소</AlertDialogCancel>
+              <AlertDialogAction
+                onClick={() =>
+                  deleteIndex !== null && handleDeletePoint(deleteIndex)
+                }
+                className="bg-red-600 hover:bg-red-700 focus:ring-red-600"
+              >
+                삭제
+              </AlertDialogAction>
+            </AlertDialogFooter>
+          </AlertDialogContent>
+        </AlertDialog>
+      </form>
+    </Form>
+  );
+}
diff --git a/fems-app/src/app/(equipment)/devices/components/DeviceForm/schema.ts b/fems-app/src/app/(equipment)/devices/components/DeviceForm/schema.ts
new file mode 100644
index 0000000..fc49f35
--- /dev/null
+++ b/fems-app/src/app/(equipment)/devices/components/DeviceForm/schema.ts
@@ -0,0 +1,93 @@
+// src/app/devices/list/components/DeviceForm/schema.ts
+import { z } from "zod";
+// import {
+//   DataPointType,
+//   DeviceType,
+//   ProtocolType,
+//   RegisterType,
+// } from "@/types/device";
+
+// 데이터 포인트 스키마
+export const dataPointSchema = z.object({
+  id: z.string().optional(),
+  tag_name: z.string().min(1, "태그명을 입력해주세요"),
+  description: z.string().optional(),
+  data_type: z.enum(
+    [
+      "BOOL",
+      "INT16",
+      "UINT16",
+      "INT32",
+      "UINT32",
+      "FLOAT",
+      "DOUBLE",
+      "STRING",
+    ] as const,
+    {
+      required_error: "데이터 타입을 선택해주세요",
+    }
+  ),
+  address: z.string().min(1, "주소를 입력해주세요"),
+  register_type: z
+    .enum([
+      "COIL",
+      "DISCRETE_INPUT",
+      "HOLDING_REGISTER",
+      "INPUT_REGISTER",
+    ] as const)
+    .optional(),
+  scan_rate: z.number().min(100, "스캔 주기는 100ms 이상이어야 합니다"),
+  scale_factor: z.number().default(1),
+  offset: z.number().default(0),
+  unit: z.string().optional(),
+  is_active: z.boolean().default(true),
+});
+
+// 디바이스 연결 설정 스키마
+const deviceConnectionSchema = z.object({
+  protocol: z.enum([
+    "MODBUS_TCP",
+    "MODBUS_RTU",
+    "OPC_UA",
+    "MQTT",
+    "BACNET",
+  ] as const),
+  ip_address: z
+    .string()
+    .regex(/^(\d{1,3}\.){3}\d{1,3}$/, "유효한 IP 주소를 입력하세요"),
+  port: z.number().min(1).max(65535),
+  unit_id: z.number().optional(),
+  connection_timeout: z
+    .number()
+    .min(100, "연결 타임아웃은 100ms 이상이어야 합니다"),
+  retry_interval: z
+    .number()
+    .min(1000, "재시도 간격은 1000ms 이상이어야 합니다"),
+  protocol_settings: z.record(z.unknown()).optional(),
+});
+
+// 메인 디바이스 스키마
+export const deviceSchema = z.object({
+  id: z.string().optional(),
+  device_name: z.string().min(1, "디바이스명을 입력해주세요"),
+  device_type: z.enum(
+    ["PLC", "PowerMeter", "Sensor", "Gateway", "Other"] as const,
+    {
+      required_error: "디바이스 유형을 선택해주세요",
+    }
+  ),
+  description: z.string().optional(),
+  manufacturer: z.string().min(1, "제조사를 입력해주세요"),
+  model: z.string().min(1, "모델명을 입력해주세요"),
+  serial_number: z.string().optional(),
+  location: z.string().min(1, "설치 위치를 입력해주세요"),
+  status: z
+    .enum(["ACTIVE", "INACTIVE", "MAINTENANCE", "ERROR"] as const)
+    .default("ACTIVE"),
+  connection: deviceConnectionSchema,
+  data_points: z.array(dataPointSchema).default([]),
+});
+
+// 타입 추출
+export type DeviceFormData = z.infer<typeof deviceSchema>;
+export type DataPointFormData = z.infer<typeof dataPointSchema>;
diff --git a/fems-app/src/app/(equipment)/devices/components/DeviceForm/useDeviceForm.ts b/fems-app/src/app/(equipment)/devices/components/DeviceForm/useDeviceForm.ts
new file mode 100644
index 0000000..d2bf87f
--- /dev/null
+++ b/fems-app/src/app/(equipment)/devices/components/DeviceForm/useDeviceForm.ts
@@ -0,0 +1,135 @@
+// src/app/devices/list/hooks/useDeviceForm.ts
+import { useMutation, useQueryClient } from "@tanstack/react-query";
+import { api } from "@/lib/api";
+import { useToast } from "@/hooks/use-toast";
+import type {
+  DeviceInput,
+  DeviceResponse,
+  UseDeviceFormProps,
+  ApiError,
+  BackendDeviceInput,
+} from "@/types/device";
+
+export function useDeviceForm({
+  deviceId,
+  onSuccess,
+  onError,
+}: UseDeviceFormProps) {
+  const queryClient = useQueryClient();
+  const { toast } = useToast();
+
+  const transformDeviceData = (formData: DeviceInput): BackendDeviceInput => {
+    const { connection, data_points, ...rest } = formData;
+
+    // 포트 번호 유효성 검사 및 변환
+    const validatePort = (port: number | undefined) => {
+      if (port === undefined) return 502; // 기본값
+      return Math.min(Math.max(1, port), 65535); // 1~65535 범위로 제한
+    };
+
+    // IP 주소 검증
+    const validateIpAddress = (ip: string | undefined) => {
+      if (!ip) return "";
+      // 간단한 IP 주소 형식 검증
+      const ipPattern = /^(\d{1,3}\.){3}\d{1,3}$/;
+      if (!ipPattern.test(ip)) {
+        throw new Error("Invalid IP address format");
+      }
+      return ip;
+    };
+
+    return {
+      ...rest,
+      // connection을 DeviceConnection으로 변환
+      DeviceConnection: {
+        ...connection,
+        deviceId: formData.id,
+        protocol: connection.protocol || "MODBUS_TCP",
+        ip_address: validateIpAddress(connection.ip_address),
+        port: validatePort(connection.port),
+        unit_id: connection.unit_id || 1,
+        connection_timeout: connection.connection_timeout || 1000,
+        retry_interval: connection.retry_interval || 5000,
+        protocol_settings: connection.protocol_settings || {},
+      },
+      // DataPoints로 변환
+      DataPoints: data_points?.map((point) => ({
+        ...point,
+        deviceId: formData.id,
+        tag_name: point.tag_name.trim(), // 공백 제거
+        data_type: point.data_type,
+        address: point.address.trim(), // 공백 제거
+        register_type: point.register_type || "HOLDING_REGISTER",
+        scan_rate: Math.max(100, Number(point.scan_rate) || 1000), // 최소 100ms
+        scale_factor: Number(point.scale_factor) || 1,
+        offset: Number(point.offset) || 0,
+        unit: point.unit?.trim() || "",
+        is_active: point.is_active !== false,
+      })),
+    };
+  };
+
+  // 생성 mutation
+  const createMutation = useMutation<DeviceResponse, ApiError, DeviceInput>({
+    mutationFn: async (newDevice) => {
+      const transformedData = transformDeviceData(newDevice);
+      const { data } = await api.post("/api/v1/app/devices", transformedData);
+      return data;
+    },
+    onSuccess: () => {
+      toast({
+        title: "디바이스 등록 완료",
+        description: "새로운 디바이스가 성공적으로 등록되었습니다.",
+      });
+      queryClient.invalidateQueries({ queryKey: ["devices"] });
+      onSuccess?.();
+    },
+    onError: (error) => {
+      toast({
+        title: "디바이스 등록 실패",
+        description: error.message || "오류가 발생했습니다.",
+        variant: "destructive",
+      });
+      onError?.(error);
+    },
+  });
+
+  // 수정 mutation
+  const updateMutation = useMutation<DeviceResponse, ApiError, DeviceInput>({
+    mutationFn: async (updateData) => {
+      const transformedData = transformDeviceData(updateData);
+      const { data } = await api.put(
+        `/api/v1/app/devices/${deviceId}`,
+        transformedData
+      );
+      return data;
+    },
+    onSuccess: () => {
+      toast({
+        title: "디바이스 수정 완료",
+        description: "디바이스 정보가 성공적으로 수정되었습니다.",
+      });
+      // 디바이스 정보와 데이터 포인트 캐시를 함께 갱신
+      if (deviceId) {
+        queryClient.invalidateQueries({ queryKey: ["device", deviceId] });
+      }
+      onSuccess?.();
+    },
+    onError: (error) => {
+      toast({
+        title: "디바이스 수정 실패",
+        description: error.message || "오류가 발생했습니다.",
+        variant: "destructive",
+      });
+      onError?.(error);
+    },
+  });
+
+  return {
+    createDevice: (data: DeviceInput) => createMutation.mutateAsync(data),
+    updateDevice: (data: DeviceInput) => updateMutation.mutateAsync(data),
+    isCreating: createMutation.isPending,
+    isUpdating: updateMutation.isPending,
+    isLoading: createMutation.isPending || updateMutation.isPending,
+  };
+}
diff --git a/fems-app/src/app/(equipment)/devices/new/layout.tsx b/fems-app/src/app/(equipment)/devices/new/layout.tsx
new file mode 100644
index 0000000..59ec4b6
--- /dev/null
+++ b/fems-app/src/app/(equipment)/devices/new/layout.tsx
@@ -0,0 +1,15 @@
+// src/app/devices/list/new/layout.tsx
+import { Metadata } from "next";
+
+export const metadata: Metadata = {
+  title: "새 디바이스 등록 | FEMS Edge",
+  description: "새로운 디바이스를 등록합니다.",
+};
+
+export default function NewDeviceLayout({
+  children,
+}: {
+  children: React.ReactNode;
+}) {
+  return children;
+}
diff --git a/fems-app/src/app/(equipment)/devices/new/page.tsx b/fems-app/src/app/(equipment)/devices/new/page.tsx
new file mode 100644
index 0000000..5ec43e1
--- /dev/null
+++ b/fems-app/src/app/(equipment)/devices/new/page.tsx
@@ -0,0 +1,52 @@
+// src/app/devices/list/new/page.tsx
+"use client";
+
+import React from "react";
+import { useRouter } from "next/navigation";
+import { DeviceForm } from "../components/DeviceForm";
+import { Alert, AlertDescription } from "@/components/ui/alert";
+import { AlertCircle } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import { useDeviceForm } from "../components/DeviceForm/useDeviceForm";
+import { Device } from "@/types/device";
+
+export default function NewDevicePage() {
+  const router = useRouter();
+  const { isCreating, isUpdating } = useDeviceForm({}); // Create and update states
+  const isError = isCreating || isUpdating;
+  const device: Device = {} as Device;
+
+  return (
+    <div className="container mx-auto py-6">
+      <div className="mb-6">
+        <h1 className="text-3xl font-bold">새 디바이스 등록</h1>
+        <p className="text-muted-foreground">새로운 디바이스를 등록합니다.</p>
+      </div>
+
+      {/* 오류 발생시 표시할 Alert */}
+      {isError && (
+        <>
+          <Alert variant="destructive">
+            <AlertCircle className="h-4 w-4" />
+            <AlertDescription>
+              디바이스를 등록하는데 실패했습니다.
+            </AlertDescription>
+          </Alert>
+          <Button
+            className="mt-4"
+            variant="outline"
+            onClick={() => router.push("/devices/list")}
+          >
+            목록으로 돌아가기
+          </Button>
+        </>
+      )}
+
+      <DeviceForm
+        initialData={device}
+        onSuccess={() => router.push("/devices/list")}
+        onCancel={() => router.push("/devices/list")}
+      />
+    </div>
+  );
+}
diff --git a/fems-app/src/app/(equipment)/devices/page.tsx b/fems-app/src/app/(equipment)/devices/page.tsx
new file mode 100644
index 0000000..30d11fd
--- /dev/null
+++ b/fems-app/src/app/(equipment)/devices/page.tsx
@@ -0,0 +1,228 @@
+// src/app/devices/list/page.tsx
+"use client";
+
+import React, { useCallback } from "react";
+import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { DataTable } from "@/components/ui/data-table";
+import { api } from "@/lib/api";
+import { Button } from "@/components/ui/button";
+import { useToast } from "@/hooks/use-toast";
+import {
+  Plus,
+  Edit,
+  Trash2,
+  Search,
+  Wifi,
+  WifiOff,
+  AlertCircle,
+} from "lucide-react";
+import { ColumnDef } from "@tanstack/react-table";
+import { useAuthStore } from "@/stores/auth";
+import { AxiosError } from "axios";
+import { Badge } from "@/components/ui/badge";
+import { Device } from "@/types/device";
+import { DeviceDetailDialog } from "./components/Detail/DeviceDetailDialog";
+import { useRouter } from "next/navigation";
+
+const DevicesPage = () => {
+  const router = useRouter();
+  const { token } = useAuthStore();
+  const [selectedDevice, setSelectedDevice] = React.useState<Device | null>(
+    null
+  );
+  const [isDetailOpen, setIsDetailOpen] = React.useState(false);
+  const { toast } = useToast();
+  const queryClient = useQueryClient();
+
+  // Navigation handlers
+  const handleNavigateToCreate = useCallback(() => {
+    router.push("/devices/list/new");
+  }, [router]);
+
+  const handleNavigateToEdit = useCallback(
+    (id: string) => {
+      router.push(`/devices/list/${id}`);
+    },
+    [router]
+  );
+
+  // Fetch devices
+  const { data: devices, isLoading } = useQuery<Device[]>({
+    queryKey: ["devices"],
+    queryFn: async () => {
+      const { data } = await api.get("/api/v1/app/devices");
+      return data;
+    },
+    enabled: !!token,
+  });
+
+  // Delete device mutation
+  const deleteMutation = useMutation({
+    mutationFn: async (id: string) => {
+      await api.delete(`/api/v1/app/devices/${id}`);
+    },
+    onSuccess: () => {
+      queryClient.invalidateQueries({ queryKey: ["devices"] });
+      toast({
+        title: "디바이스 삭제",
+        description: "디바이스가 삭제되었습니다.",
+      });
+    },
+    onError: (error: AxiosError) => {
+      toast({
+        title: "디바이스 삭제 실패",
+        description: (error.response?.data as { message: string }).message,
+        variant: "destructive",
+      });
+    },
+  });
+
+  // Handle device selection for detail view
+  const handleShowDetails = useCallback((device: Device) => {
+    setSelectedDevice(device);
+    setIsDetailOpen(true);
+  }, []);
+
+  // Handle device deletion
+  const handleDelete = useCallback(
+    (id: string) => {
+      if (confirm("정말 삭제하시겠습니까?")) {
+        deleteMutation.mutate(id);
+      }
+    },
+    [deleteMutation]
+  );
+
+  const columns: ColumnDef<Device>[] = React.useMemo(
+    () => [
+      {
+        accessorKey: "id",
+        header: "디바이스 ID",
+        // Hide the column
+        hidden: true,
+      },
+      {
+        accessorKey: "device_name",
+        header: "디바이스명",
+      },
+      {
+        accessorKey: "device_type",
+        header: "유형",
+        cell: ({ row }) => (
+          <Badge variant="outline">{row.original.device_type}</Badge>
+        ),
+      },
+      {
+        accessorKey: "status",
+        header: "상태",
+        cell: ({ row }) => {
+          const statusMap = {
+            ACTIVE: { label: "활성", icon: Wifi, variant: "default" },
+            INACTIVE: { label: "비활성", icon: WifiOff, variant: "secondary" },
+            ERROR: { label: "오류", icon: AlertCircle, variant: "destructive" },
+          } as const;
+
+          const status =
+            statusMap[row.original.status as keyof typeof statusMap];
+          const Icon = status.icon;
+
+          return (
+            <Badge variant={status.variant}>
+              <Icon className="w-3 h-3 mr-1" />
+              {status.label}
+            </Badge>
+          );
+        },
+      },
+      {
+        accessorKey: "location",
+        header: "위치",
+      },
+      {
+        id: "actions",
+        header: "액션",
+        cell: ({ row }) => (
+          <div className="flex items-center gap-2">
+            <Button
+              variant="ghost"
+              size="sm"
+              onClick={() => handleShowDetails(row.original)}
+            >
+              <Search className="h-4 w-4" />
+            </Button>
+            <Button
+              variant="ghost"
+              size="sm"
+              onClick={() => handleNavigateToEdit(row.original.id)}
+            >
+              <Edit className="h-4 w-4" />
+            </Button>
+            <Button
+              variant="ghost"
+              size="sm"
+              onClick={() => handleDelete(row.original.id)}
+            >
+              <Trash2 className="h-4 w-4" />
+            </Button>
+          </div>
+        ),
+      },
+    ],
+    [handleNavigateToEdit, handleShowDetails, handleDelete]
+  );
+
+  if (isLoading) {
+    return (
+      <div className="container mx-auto py-6">
+        <div>Loading...</div>
+      </div>
+    );
+  }
+
+  return (
+    <div className="container mx-auto py-6">
+      {/* Header */}
+      <div className="flex justify-between items-center mb-6">
+        <div className="space-y-1">
+          <h1 className="text-3xl font-bold">디바이스 관리</h1>
+          <p className="text-muted-foreground">
+            현장 디바이스를 등록하고 관리합니다.
+          </p>
+        </div>
+        <Button onClick={handleNavigateToCreate}>
+          <Plus className="mr-2 h-4 w-4" />
+          디바이스 등록
+        </Button>
+      </div>
+
+      {/* Devices Table */}
+      <Card>
+        <CardHeader>
+          <CardTitle>디바이스 목록</CardTitle>
+        </CardHeader>
+        <CardContent>
+          {devices && devices.length > 0 ? (
+            <DataTable columns={columns} data={devices} />
+          ) : (
+            <div className="text-center py-12 text-muted-foreground">
+              등록된 디바이스가 없습니다.
+            </div>
+          )}
+        </CardContent>
+      </Card>
+
+      {/* Device Detail Dialog */}
+      <DeviceDetailDialog
+        device={selectedDevice}
+        isOpen={isDetailOpen}
+        onClose={() => {
+          setIsDetailOpen(false);
+          setSelectedDevice(null);
+        }}
+      />
+    </div>
+  );
+};
+
+export default DevicesPage;
diff --git a/fems-app/src/components/layout/SideNav.tsx b/fems-app/src/components/layout/SideNav.tsx
index 8f9c1aa..d5d8372 100644
--- a/fems-app/src/components/layout/SideNav.tsx
+++ b/fems-app/src/components/layout/SideNav.tsx
@@ -85,6 +85,7 @@ const getMenuItems = (
         { title: "정비 관리", href: "/maintenance", icon: Wrench },
         { title: "부품 관리", href: "/parts", icon: Puzzle },
         { title: "작업자 관리", href: "/personnel", icon: Users },
+        { title: "디바이스", href: "/devices", icon: Sliders },
       ],
     },
     {
diff --git a/fems-mqtt/data/mosquitto.db b/fems-mqtt/data/mosquitto.db
index 2ec3747..5cb1b02 100644
Binary files a/fems-mqtt/data/mosquitto.db and b/fems-mqtt/data/mosquitto.db differ
diff --git a/fems-mqtt/data/passwd b/fems-mqtt/data/passwd
index 296b6f8..2f493bd 100644
--- a/fems-mqtt/data/passwd
+++ b/fems-mqtt/data/passwd
@@ -1,2 +1,2 @@
-fems:$7$101$ovh8p4Iy2vad6wam$5KugLDFKCLXl0fNtZYcEkx60rKMcNLInv128xmB4IhsW6sQa+7wyzqLNouqGLa7Fn4C0Yo5ic4PvKdT19sxR9A==
-nodered_user:$7$101$cH8eC8IS2J5wB2z8$v59/KuA28HlkFX8g5njwajyKLdhNnGypJSTl5RrGfyVzPykQys87s4B0xiTvNqVAmFcDobOUWxpqDQP9BOoHMA==
+fems:$7$101$pX2RGILdPjEKoCX2$4XU2mxjlVo2mkgLIjOlBDk67gdFlRhx0lxvcb72PJDKCpvXGTCak+VeUpePNYqHbM/wTva3wPZqLI0WDaqOliA==
+nodered_user:$7$101$/usoPKu8HDa2SrkT$3x8mSiR1TvcrGMSvYwCOrEJmVIlbEKf5BaoXkfu+RvUnOpQCvcAE9HZc9o+uAElQV3leBlpgrk7RACYd0DaNsQ==
diff --git a/fems-mqtt/log/mosquitto.log b/fems-mqtt/log/mosquitto.log
index d3d2b3e..fc57973 100755
--- a/fems-mqtt/log/mosquitto.log
+++ b/fems-mqtt/log/mosquitto.log
@@ -17661,3 +17661,200 @@ To fix this, use `chmod 0700 /mosquitto/config/passwd`.
 1732601847: Client fems_realtime_39 closed its connection.
 1732601847: mosquitto version 2.0.20 terminating
 1732601847: Saving in-memory database to /mosquitto/data//mosquitto.db.
+1732602814: mosquitto version 2.0.20 starting
+1732602814: Config loaded from /mosquitto/config/mosquitto.conf.
+1732602814: Opening ipv4 listen socket on port 1883.
+1732602814: Opening ipv6 listen socket on port 1883.
+1732602814: mosquitto version 2.0.20 running
+1732602816: New connection from 172.19.0.7:54110 on port 1883.
+1732602816: New client connected from 172.19.0.7:54110 as fems_realtime_40 (p2, c1, k60, u'fems').
+1732602844: New connection from ::1:58526 on port 1883.
+1732602844: New client connected from ::1:58526 as auto-754A82FC-940A-907F-D4A8-FB6A77F24149 (p2, c1, k60, u'fems').
+1732602844: Client auto-754A82FC-940A-907F-D4A8-FB6A77F24149 closed its connection.
+1732602874: New connection from ::1:35756 on port 1883.
+1732602874: New client connected from ::1:35756 as auto-E0C2A639-0338-A735-0502-A55C21010132 (p2, c1, k60, u'fems').
+1732602874: Client auto-E0C2A639-0338-A735-0502-A55C21010132 closed its connection.
+1732602904: New connection from ::1:36586 on port 1883.
+1732602904: New client connected from ::1:36586 as auto-0943EDB3-90E7-BE73-8FD4-5F404F7FD980 (p2, c1, k60, u'fems').
+1732602904: Client auto-0943EDB3-90E7-BE73-8FD4-5F404F7FD980 closed its connection.
+1732602934: New connection from ::1:39870 on port 1883.
+1732602934: New client connected from ::1:39870 as auto-1601E100-AD13-F040-76E8-21CC77178F86 (p2, c1, k60, u'fems').
+1732602934: Client auto-1601E100-AD13-F040-76E8-21CC77178F86 closed its connection.
+1732602964: New connection from ::1:34758 on port 1883.
+1732602964: New client connected from ::1:34758 as auto-5AFB6C41-E0D9-C045-9559-45EBB665B291 (p2, c1, k60, u'fems').
+1732602964: Client auto-5AFB6C41-E0D9-C045-9559-45EBB665B291 closed its connection.
+1732602994: New connection from ::1:59586 on port 1883.
+1732602994: New client connected from ::1:59586 as auto-CD29980A-DD1B-D3D3-6726-DEBF789EE795 (p2, c1, k60, u'fems').
+1732602994: Client auto-CD29980A-DD1B-D3D3-6726-DEBF789EE795 closed its connection.
+1732603024: New connection from ::1:57712 on port 1883.
+1732603024: New client connected from ::1:57712 as auto-91916600-C085-90AF-4715-74C65FA37D47 (p2, c1, k60, u'fems').
+1732603024: Client auto-91916600-C085-90AF-4715-74C65FA37D47 closed its connection.
+1732603054: New connection from ::1:54980 on port 1883.
+1732603055: New client connected from ::1:54980 as auto-96CE561E-90AB-EDBF-209C-43E9591BB20F (p2, c1, k60, u'fems').
+1732603055: Client auto-96CE561E-90AB-EDBF-209C-43E9591BB20F closed its connection.
+1732603085: New connection from ::1:45488 on port 1883.
+1732603085: New client connected from ::1:45488 as auto-9FD18F2D-A2B3-F2B7-8758-4D263D89AAE8 (p2, c1, k60, u'fems').
+1732603085: Client auto-9FD18F2D-A2B3-F2B7-8758-4D263D89AAE8 closed its connection.
+1732603115: New connection from ::1:60430 on port 1883.
+1732603115: New client connected from ::1:60430 as auto-0D8C7443-EE3C-F235-6956-56B303E1643A (p2, c1, k60, u'fems').
+1732603115: Client auto-0D8C7443-EE3C-F235-6956-56B303E1643A closed its connection.
+1732603145: New connection from ::1:42164 on port 1883.
+1732603145: New client connected from ::1:42164 as auto-B61BFE79-FB48-9BFD-02DA-0814999E260E (p2, c1, k60, u'fems').
+1732603145: Client auto-B61BFE79-FB48-9BFD-02DA-0814999E260E closed its connection.
+1732603175: New connection from ::1:51988 on port 1883.
+1732603175: New client connected from ::1:51988 as auto-BE2F790E-BE6C-DE79-85EB-0BE1A4AB04AE (p2, c1, k60, u'fems').
+1732603175: Client auto-BE2F790E-BE6C-DE79-85EB-0BE1A4AB04AE closed its connection.
+1732603205: New connection from ::1:36822 on port 1883.
+1732603205: New client connected from ::1:36822 as auto-D8165230-B8F2-04A2-7F0A-476D72959620 (p2, c1, k60, u'fems').
+1732603205: Client auto-D8165230-B8F2-04A2-7F0A-476D72959620 closed its connection.
+1732603235: New connection from ::1:50446 on port 1883.
+1732603235: New client connected from ::1:50446 as auto-3B6CEFE6-1FD9-1DD6-A3EE-6C69EC82AC3B (p2, c1, k60, u'fems').
+1732603235: Client auto-3B6CEFE6-1FD9-1DD6-A3EE-6C69EC82AC3B closed its connection.
+1732603265: New connection from ::1:46622 on port 1883.
+1732603265: New client connected from ::1:46622 as auto-F76E3E39-5677-AA3A-8D38-75341055603C (p2, c1, k60, u'fems').
+1732603265: Client auto-F76E3E39-5677-AA3A-8D38-75341055603C closed its connection.
+1732603295: New connection from ::1:41536 on port 1883.
+1732603295: New client connected from ::1:41536 as auto-2B723323-33EF-DD68-8B02-6578A4306B82 (p2, c1, k60, u'fems').
+1732603295: Client auto-2B723323-33EF-DD68-8B02-6578A4306B82 closed its connection.
+1732603325: New connection from ::1:49736 on port 1883.
+1732603325: New client connected from ::1:49736 as auto-CCDFD4E5-9CC2-D93E-E524-75EEEAF9863F (p2, c1, k60, u'fems').
+1732603325: Client auto-CCDFD4E5-9CC2-D93E-E524-75EEEAF9863F closed its connection.
+1732603355: New connection from ::1:52870 on port 1883.
+1732603355: New client connected from ::1:52870 as auto-96B81626-9E64-9AF6-E8C2-BBDD66E60CDC (p2, c1, k60, u'fems').
+1732603355: Client auto-96B81626-9E64-9AF6-E8C2-BBDD66E60CDC closed its connection.
+1732603385: New connection from ::1:43772 on port 1883.
+1732603385: New client connected from ::1:43772 as auto-2B4B8286-D794-42DC-823A-CC3F59471AB3 (p2, c1, k60, u'fems').
+1732603385: Client auto-2B4B8286-D794-42DC-823A-CC3F59471AB3 closed its connection.
+1732603416: New connection from ::1:44142 on port 1883.
+1732603416: New client connected from ::1:44142 as auto-ACE35949-8840-FD41-66E0-FE9A35F7B0C4 (p2, c1, k60, u'fems').
+1732603416: Client auto-ACE35949-8840-FD41-66E0-FE9A35F7B0C4 closed its connection.
+1732603446: New connection from ::1:41878 on port 1883.
+1732603446: New client connected from ::1:41878 as auto-CD4C9897-E54E-9AFD-3E42-A53EBDD3A44A (p2, c1, k60, u'fems').
+1732603446: Client auto-CD4C9897-E54E-9AFD-3E42-A53EBDD3A44A closed its connection.
+1732603476: New connection from ::1:42368 on port 1883.
+1732603476: New client connected from ::1:42368 as auto-49879275-FCBC-92B9-C516-91C91CB42533 (p2, c1, k60, u'fems').
+1732603476: Client auto-49879275-FCBC-92B9-C516-91C91CB42533 closed its connection.
+1732603506: New connection from ::1:37142 on port 1883.
+1732603506: New client connected from ::1:37142 as auto-997C9096-DD2F-8F17-B6B3-FFA22F76E1C5 (p2, c1, k60, u'fems').
+1732603506: Client auto-997C9096-DD2F-8F17-B6B3-FFA22F76E1C5 closed its connection.
+1732603536: New connection from ::1:44342 on port 1883.
+1732603536: New client connected from ::1:44342 as auto-917626B3-543A-C17E-DD91-C41A2DAA860D (p2, c1, k60, u'fems').
+1732603536: Client auto-917626B3-543A-C17E-DD91-C41A2DAA860D closed its connection.
+1732603566: New connection from ::1:40722 on port 1883.
+1732603566: New client connected from ::1:40722 as auto-5B22E48E-0D64-DC2F-272B-CEA8705C3161 (p2, c1, k60, u'fems').
+1732603566: Client auto-5B22E48E-0D64-DC2F-272B-CEA8705C3161 closed its connection.
+1732603596: New connection from ::1:48506 on port 1883.
+1732603596: New client connected from ::1:48506 as auto-53073475-9D8E-15E6-7744-50D25B13C4D3 (p2, c1, k60, u'fems').
+1732603596: Client auto-53073475-9D8E-15E6-7744-50D25B13C4D3 closed its connection.
+1732603626: New connection from ::1:43278 on port 1883.
+1732603626: New client connected from ::1:43278 as auto-3CF226CF-4106-068D-B51C-26433B3C72CD (p2, c1, k60, u'fems').
+1732603626: Client auto-3CF226CF-4106-068D-B51C-26433B3C72CD closed its connection.
+1732603656: New connection from ::1:41992 on port 1883.
+1732603656: New client connected from ::1:41992 as auto-0BAEB8A4-BD28-0D71-22B1-491CD4FDA7E7 (p2, c1, k60, u'fems').
+1732603656: Client auto-0BAEB8A4-BD28-0D71-22B1-491CD4FDA7E7 closed its connection.
+1732603686: New connection from ::1:44918 on port 1883.
+1732603686: New client connected from ::1:44918 as auto-7384624C-68B2-5113-E5EA-0AC0F2296313 (p2, c1, k60, u'fems').
+1732603686: Client auto-7384624C-68B2-5113-E5EA-0AC0F2296313 closed its connection.
+1732603716: New connection from ::1:48628 on port 1883.
+1732603716: New client connected from ::1:48628 as auto-C41451CE-FE2A-3662-C1D3-23C583ED7DA2 (p2, c1, k60, u'fems').
+1732603716: Client auto-C41451CE-FE2A-3662-C1D3-23C583ED7DA2 closed its connection.
+1732603746: New connection from ::1:35912 on port 1883.
+1732603746: New client connected from ::1:35912 as auto-564B487B-FA69-67AB-B264-30D803421420 (p2, c1, k60, u'fems').
+1732603747: Client auto-564B487B-FA69-67AB-B264-30D803421420 closed its connection.
+1732603777: New connection from ::1:33478 on port 1883.
+1732603777: New client connected from ::1:33478 as auto-26E874FE-32D0-A240-C3A7-18CCADB4D852 (p2, c1, k60, u'fems').
+1732603777: Client auto-26E874FE-32D0-A240-C3A7-18CCADB4D852 closed its connection.
+1732603807: New connection from ::1:45306 on port 1883.
+1732603807: New client connected from ::1:45306 as auto-71BDD556-ED73-BB53-2B90-E0C91C33A631 (p2, c1, k60, u'fems').
+1732603807: Client auto-71BDD556-ED73-BB53-2B90-E0C91C33A631 closed its connection.
+1732603837: New connection from ::1:58252 on port 1883.
+1732603837: New client connected from ::1:58252 as auto-8D726B23-6879-88A4-145C-4E43536E49CB (p2, c1, k60, u'fems').
+1732603837: Client auto-8D726B23-6879-88A4-145C-4E43536E49CB closed its connection.
+1732603867: New connection from ::1:47832 on port 1883.
+1732603867: New client connected from ::1:47832 as auto-17FFB8C5-1041-EC11-C68B-F52581404BAE (p2, c1, k60, u'fems').
+1732603867: Client auto-17FFB8C5-1041-EC11-C68B-F52581404BAE closed its connection.
+1732603897: New connection from ::1:49580 on port 1883.
+1732603897: New client connected from ::1:49580 as auto-EE24A5EA-9CB2-EBA1-831C-97180FCE6D62 (p2, c1, k60, u'fems').
+1732603897: Client auto-EE24A5EA-9CB2-EBA1-831C-97180FCE6D62 closed its connection.
+1732603927: New connection from ::1:52654 on port 1883.
+1732603927: New client connected from ::1:52654 as auto-6EA0A671-30EB-2121-1244-41D77A72826D (p2, c1, k60, u'fems').
+1732603927: Client auto-6EA0A671-30EB-2121-1244-41D77A72826D closed its connection.
+1732603957: New connection from ::1:59852 on port 1883.
+1732603957: New client connected from ::1:59852 as auto-75013A3D-05A9-3F9E-29F1-4EC7E1469D2F (p2, c1, k60, u'fems').
+1732603957: Client auto-75013A3D-05A9-3F9E-29F1-4EC7E1469D2F closed its connection.
+1732603987: New connection from ::1:48904 on port 1883.
+1732603987: New client connected from ::1:48904 as auto-D20D97A5-E260-BFBB-2D52-2DD28C21C546 (p2, c1, k60, u'fems').
+1732603987: Client auto-D20D97A5-E260-BFBB-2D52-2DD28C21C546 closed its connection.
+1732604017: New connection from ::1:36682 on port 1883.
+1732604017: New client connected from ::1:36682 as auto-E59B14CD-F9B2-43BD-6ED3-4601E61ED8D5 (p2, c1, k60, u'fems').
+1732604018: Client auto-E59B14CD-F9B2-43BD-6ED3-4601E61ED8D5 closed its connection.
+1732604048: New connection from ::1:57168 on port 1883.
+1732604048: New client connected from ::1:57168 as auto-01616CFF-8E2F-D2F8-E935-59C20C83CAF5 (p2, c1, k60, u'fems').
+1732604048: Client auto-01616CFF-8E2F-D2F8-E935-59C20C83CAF5 closed its connection.
+1732604078: New connection from ::1:41446 on port 1883.
+1732604078: New client connected from ::1:41446 as auto-A8D32F7E-E362-15F6-ADEC-9FAFE25E96AC (p2, c1, k60, u'fems').
+1732604078: Client auto-A8D32F7E-E362-15F6-ADEC-9FAFE25E96AC closed its connection.
+1732604108: New connection from ::1:45182 on port 1883.
+1732604108: New client connected from ::1:45182 as auto-B839DEAF-7357-DD70-9755-01EAE665A9F5 (p2, c1, k60, u'fems').
+1732604108: Client auto-B839DEAF-7357-DD70-9755-01EAE665A9F5 closed its connection.
+1732604138: New connection from ::1:56366 on port 1883.
+1732604138: New client connected from ::1:56366 as auto-ED4C27B2-39FD-F202-D07A-C48047DD77EC (p2, c1, k60, u'fems').
+1732604138: Client auto-ED4C27B2-39FD-F202-D07A-C48047DD77EC closed its connection.
+1732604168: New connection from ::1:45452 on port 1883.
+1732604168: New client connected from ::1:45452 as auto-A50DB7E4-5193-DB6E-19BC-B3F606A397E0 (p2, c1, k60, u'fems').
+1732604168: Client auto-A50DB7E4-5193-DB6E-19BC-B3F606A397E0 closed its connection.
+1732604198: New connection from ::1:45744 on port 1883.
+1732604198: New client connected from ::1:45744 as auto-7B0FDA2A-1DC0-D742-1516-F6075FEED0AC (p2, c1, k60, u'fems').
+1732604198: Client auto-7B0FDA2A-1DC0-D742-1516-F6075FEED0AC closed its connection.
+1732604228: New connection from ::1:37222 on port 1883.
+1732604228: New client connected from ::1:37222 as auto-619F8BEF-D282-4CB3-4E7D-DDB997D3AD26 (p2, c1, k60, u'fems').
+1732604228: Client auto-619F8BEF-D282-4CB3-4E7D-DDB997D3AD26 closed its connection.
+1732604258: New connection from ::1:52198 on port 1883.
+1732604258: New client connected from ::1:52198 as auto-46F084CC-54C5-5CAF-5F3B-2881E680FE3B (p2, c1, k60, u'fems').
+1732604258: Client auto-46F084CC-54C5-5CAF-5F3B-2881E680FE3B closed its connection.
+1732604288: New connection from ::1:46508 on port 1883.
+1732604288: New client connected from ::1:46508 as auto-10688AF9-CB04-9137-1639-C24AF4BFF300 (p2, c1, k60, u'fems').
+1732604288: Client auto-10688AF9-CB04-9137-1639-C24AF4BFF300 closed its connection.
+1732604318: New connection from ::1:35532 on port 1883.
+1732604318: New client connected from ::1:35532 as auto-1816CCDF-E9B3-C5D8-4730-454783971FE1 (p2, c1, k60, u'fems').
+1732604318: Client auto-1816CCDF-E9B3-C5D8-4730-454783971FE1 closed its connection.
+1732604348: New connection from ::1:55400 on port 1883.
+1732604348: New client connected from ::1:55400 as auto-F97F5BE7-F898-2684-B9E3-5D8A4DC58194 (p2, c1, k60, u'fems').
+1732604348: Client auto-F97F5BE7-F898-2684-B9E3-5D8A4DC58194 closed its connection.
+1732604379: New connection from ::1:40820 on port 1883.
+1732604379: New client connected from ::1:40820 as auto-E3D92CF6-880F-C242-D857-7D9743488EE9 (p2, c1, k60, u'fems').
+1732604379: Client auto-E3D92CF6-880F-C242-D857-7D9743488EE9 closed its connection.
+1732604409: New connection from ::1:43856 on port 1883.
+1732604409: New client connected from ::1:43856 as auto-FF3D9A73-0327-58C8-1BF5-C13E4D4B3887 (p2, c1, k60, u'fems').
+1732604409: Client auto-FF3D9A73-0327-58C8-1BF5-C13E4D4B3887 closed its connection.
+1732604439: New connection from ::1:40000 on port 1883.
+1732604439: New client connected from ::1:40000 as auto-16233E17-161B-BDE2-FB6C-3AD33FD53B81 (p2, c1, k60, u'fems').
+1732604439: Client auto-16233E17-161B-BDE2-FB6C-3AD33FD53B81 closed its connection.
+1732604469: New connection from ::1:55918 on port 1883.
+1732604469: New client connected from ::1:55918 as auto-52183970-05BC-084B-DFBB-3D9203B6EB57 (p2, c1, k60, u'fems').
+1732604469: Client auto-52183970-05BC-084B-DFBB-3D9203B6EB57 closed its connection.
+1732604499: New connection from ::1:53410 on port 1883.
+1732604499: New client connected from ::1:53410 as auto-51B634AB-F25F-C151-BC2D-3E8E342F3476 (p2, c1, k60, u'fems').
+1732604499: Client auto-51B634AB-F25F-C151-BC2D-3E8E342F3476 closed its connection.
+1732604529: New connection from ::1:32802 on port 1883.
+1732604529: New client connected from ::1:32802 as auto-D9368501-4284-8BC0-5623-47C0F90C7698 (p2, c1, k60, u'fems').
+1732604529: Client auto-D9368501-4284-8BC0-5623-47C0F90C7698 closed its connection.
+1732604559: New connection from ::1:32868 on port 1883.
+1732604559: New client connected from ::1:32868 as auto-B593D0CF-C01F-1C77-970A-0A543BB0EB87 (p2, c1, k60, u'fems').
+1732604559: Client auto-B593D0CF-C01F-1C77-970A-0A543BB0EB87 closed its connection.
+1732604589: New connection from ::1:46038 on port 1883.
+1732604589: New client connected from ::1:46038 as auto-1BB57210-2946-DB35-2424-DF152AA62163 (p2, c1, k60, u'fems').
+1732604589: Client auto-1BB57210-2946-DB35-2424-DF152AA62163 closed its connection.
+1732604615: Saving in-memory database to /mosquitto/data//mosquitto.db.
+1732604619: New connection from ::1:42858 on port 1883.
+1732604619: New client connected from ::1:42858 as auto-3CEA4C57-0514-8061-F3FA-B6610B355505 (p2, c1, k60, u'fems').
+1732604619: Client auto-3CEA4C57-0514-8061-F3FA-B6610B355505 closed its connection.
+1732604649: New connection from ::1:37340 on port 1883.
+1732604649: New client connected from ::1:37340 as auto-0EAEB5C6-4B5A-398E-C2D8-EFD939439679 (p2, c1, k60, u'fems').
+1732604649: Client auto-0EAEB5C6-4B5A-398E-C2D8-EFD939439679 closed its connection.
+1732604679: New connection from ::1:56122 on port 1883.
+1732604679: New client connected from ::1:56122 as auto-908E9122-3B50-6862-DF6E-200E71E4AAA2 (p2, c1, k60, u'fems').
+1732604679: Client auto-908E9122-3B50-6862-DF6E-200E71E4AAA2 closed its connection.
+1732604709: New connection from ::1:51980 on port 1883.
+1732604709: New client connected from ::1:51980 as auto-FE0AAE47-6009-8CA2-43D4-BEFC7E816FE0 (p2, c1, k60, u'fems').
+1732604709: Client auto-FE0AAE47-6009-8CA2-43D4-BEFC7E816FE0 closed its connection.
diff --git a/fems-realtime-api/logs/info/info-2024-11-26.log b/fems-realtime-api/logs/info/info-2024-11-26.log
index f0ffb43..d3c791e 100644
--- a/fems-realtime-api/logs/info/info-2024-11-26.log
+++ b/fems-realtime-api/logs/info/info-2024-11-26.log
@@ -82,3 +82,10 @@
 {"environment":"development","level":"info","message":"Connected to MQTT broker","service":"fems-edge","timestamp":"2024-11-26 15:14:45"}
 {"environment":"development","level":"info","message":"Realtime backend server running on port 3004","service":"fems-edge","timestamp":"2024-11-26 15:14:45"}
 {"environment":"development","level":"info","message":"Subscribed to data/+/+/+/#","service":"fems-edge","timestamp":"2024-11-26 15:14:45"}
+{"environment":"development","level":"info","message":"Successfully connected to TimescaleDB","service":"fems-edge","timestamp":"2024-11-26 15:33:35"}
+{"environment":"development","level":"info","message":"Successfully connected to Redis","service":"fems-edge","timestamp":"2024-11-26 15:33:35"}
+{"environment":"development","level":"info","message":"All services are connected","service":"fems-edge","timestamp":"2024-11-26 15:33:35"}
+{"broker":"mqtt://fems-mqtt:1883","clientId":"fems_realtime_40","environment":"development","level":"info","message":"Connecting to MQTT broker...","service":"fems-edge","timestamp":"2024-11-26 15:33:36"}
+{"environment":"development","level":"info","message":"Connected to MQTT broker","service":"fems-edge","timestamp":"2024-11-26 15:33:36"}
+{"environment":"development","level":"info","message":"Realtime backend server running on port 3004","service":"fems-edge","timestamp":"2024-11-26 15:33:36"}
+{"environment":"development","level":"info","message":"Subscribed to data/+/+/+/#","service":"fems-edge","timestamp":"2024-11-26 15:33:36"}
diff --git a/fems-realtime-api/logs/system/system-2024-11-26.log b/fems-realtime-api/logs/system/system-2024-11-26.log
index f0ffb43..d3c791e 100644
--- a/fems-realtime-api/logs/system/system-2024-11-26.log
+++ b/fems-realtime-api/logs/system/system-2024-11-26.log
@@ -82,3 +82,10 @@
 {"environment":"development","level":"info","message":"Connected to MQTT broker","service":"fems-edge","timestamp":"2024-11-26 15:14:45"}
 {"environment":"development","level":"info","message":"Realtime backend server running on port 3004","service":"fems-edge","timestamp":"2024-11-26 15:14:45"}
 {"environment":"development","level":"info","message":"Subscribed to data/+/+/+/#","service":"fems-edge","timestamp":"2024-11-26 15:14:45"}
+{"environment":"development","level":"info","message":"Successfully connected to TimescaleDB","service":"fems-edge","timestamp":"2024-11-26 15:33:35"}
+{"environment":"development","level":"info","message":"Successfully connected to Redis","service":"fems-edge","timestamp":"2024-11-26 15:33:35"}
+{"environment":"development","level":"info","message":"All services are connected","service":"fems-edge","timestamp":"2024-11-26 15:33:35"}
+{"broker":"mqtt://fems-mqtt:1883","clientId":"fems_realtime_40","environment":"development","level":"info","message":"Connecting to MQTT broker...","service":"fems-edge","timestamp":"2024-11-26 15:33:36"}
+{"environment":"development","level":"info","message":"Connected to MQTT broker","service":"fems-edge","timestamp":"2024-11-26 15:33:36"}
+{"environment":"development","level":"info","message":"Realtime backend server running on port 3004","service":"fems-edge","timestamp":"2024-11-26 15:33:36"}
+{"environment":"development","level":"info","message":"Subscribed to data/+/+/+/#","service":"fems-edge","timestamp":"2024-11-26 15:33:36"}