diff --git a/fems-api/src/middleware/cors.middleware.js b/fems-api/src/middleware/cors.middleware.js
new file mode 100644
index 0000000..9d980c4
--- /dev/null
+++ b/fems-api/src/middleware/cors.middleware.js
@@ -0,0 +1,21 @@
+// CORS 설정
+// src/middleware/cors.middleware.js
+const cors = require("cors");
+const config = require("../config");
+
+const corsOptions = {
+  origin: (origin, callback) => {
+    const whitelist = config.cors.whitelist;
+    if (whitelist.indexOf(origin) !== -1 || !origin) {
+      callback(null, true);
+    } else {
+      callback(new Error("Not allowed by CORS"));
+    }
+  },
+  methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
+  allowedHeaders: ["Content-Type", "Authorization"],
+  credentials: true,
+  maxAge: 86400, // 24시간
+};
+
+module.exports = cors(corsOptions);
diff --git a/fems-api/src/middleware/error.middleware.js b/fems-api/src/middleware/error.middleware.js
new file mode 100644
index 0000000..4c043c9
--- /dev/null
+++ b/fems-api/src/middleware/error.middleware.js
@@ -0,0 +1,69 @@
+// src/middleware/error.middleware.js
+const { logger, auditLogger } = require("../config/logger");
+
+const errorHandler = (err, req, res) => {
+  err.statusCode = err.statusCode || 500;
+  err.status = err.status || "error";
+
+  // 운영 환경과 개발 환경의 에러 응답 구분
+  if (process.env.NODE_ENV === "development") {
+    logger.error(err.stack);
+
+    res.status(err.statusCode).json({
+      status: err.status,
+      message: err.message,
+      errors: err.errors,
+      stack: err.stack,
+    });
+  } else {
+    // 운영 환경에서는 스택 트레이스 제외
+    logger.error(err.message, {
+      status: err.status,
+      statusCode: err.statusCode,
+      errors: err.errors,
+    });
+
+    // 운영 환경에서는 일반적인 에러 메시지만 전송
+    if (err.isOperational) {
+      res.status(err.statusCode).json({
+        status: err.status,
+        message: err.message,
+        errors: err.errors,
+      });
+    } else {
+      // 프로그래밍 에러의 경우 일반적인 에러 메시지 전송
+      res.status(500).json({
+        status: "error",
+        message: "Something went wrong!",
+      });
+    }
+  }
+};
+
+// 감사 로그 미들웨어
+const auditMiddleware = (req, res, next) => {
+  const startTime = Date.now();
+
+  // 응답이 완료된 후 로깅
+  res.on("finish", () => {
+    const duration = Date.now() - startTime;
+
+    auditLogger.info({
+      type: "API_ACCESS",
+      method: req.method,
+      path: req.path,
+      statusCode: res.statusCode,
+      duration,
+      userId: req.user?.id,
+      ip: req.ip,
+      userAgent: req.headers["user-agent"],
+    });
+  });
+
+  next();
+};
+
+module.exports = {
+  errorHandler,
+  auditMiddleware,
+};
diff --git a/fems-api/src/middleware/permission.middleware.js b/fems-api/src/middleware/permission.middleware.js
new file mode 100644
index 0000000..b7aa8e5
--- /dev/null
+++ b/fems-api/src/middleware/permission.middleware.js
@@ -0,0 +1,29 @@
+// src/middleware/permission.middleware.js
+const PermissionService = require("../services/permission.service");
+const permissionService = new PermissionService();
+
+/**
+ * 권한 검사 미들웨어
+ */
+const checkPermission = (resource, action) => async (req, res, next) => {
+  try {
+    const hasPermission = await permissionService.checkPermission(
+      req.user.id,
+      resource,
+      action
+    );
+
+    if (!hasPermission) {
+      return res.status(403).json({
+        message: "Permission denied",
+        detail: `Required permission: ${resource}:${action}`,
+      });
+    }
+
+    next();
+  } catch (error) {
+    next(error);
+  }
+};
+
+module.exports = checkPermission;
diff --git a/fems-api/src/middleware/rateLimit.middleware.js b/fems-api/src/middleware/rateLimit.middleware.js
new file mode 100644
index 0000000..7a3e2e8
--- /dev/null
+++ b/fems-api/src/middleware/rateLimit.middleware.js
@@ -0,0 +1,24 @@
+// Rate Limiting 미들웨어
+// src/middleware/rateLimit.middleware.js
+const rateLimit = require("express-rate-limit");
+const RedisStore = require("rate-limit-redis");
+const redis = require("../config/redis");
+
+const createRateLimiter = (options = {}) => {
+  return rateLimit({
+    store: new RedisStore({
+      client: redis,
+      prefix: "rate-limit:",
+    }),
+    windowMs: options.windowMs || 15 * 60 * 1000, // 기본 15분
+    max: options.max || 100, // 기본 100회
+    message: {
+      status: "error",
+      message: "Too many requests, please try again later.",
+    },
+    standardHeaders: true,
+    legacyHeaders: false,
+  });
+};
+
+module.exports = createRateLimiter;
diff --git a/fems-api/src/middleware/securityHeaders.middleware.js b/fems-api/src/middleware/securityHeaders.middleware.js
new file mode 100644
index 0000000..3b2f59a
--- /dev/null
+++ b/fems-api/src/middleware/securityHeaders.middleware.js
@@ -0,0 +1,35 @@
+// 보안 헤더 미들웨어
+// src/middleware/securityHeaders.middleware.js
+const helmet = require("helmet");
+
+const securityHeaders = helmet({
+  contentSecurityPolicy: {
+    directives: {
+      defaultSrc: ["'self'"],
+      scriptSrc: ["'self'", "'unsafe-inline'"],
+      styleSrc: ["'self'", "'unsafe-inline'"],
+      imgSrc: ["'self'", "data:", "https:"],
+      connectSrc: ["'self'"],
+      fontSrc: ["'self'"],
+      objectSrc: ["'none'"],
+      mediaSrc: ["'self'"],
+      frameSrc: ["'none'"],
+    },
+  },
+  crossOriginEmbedderPolicy: true,
+  crossOriginOpenerPolicy: true,
+  crossOriginResourcePolicy: true,
+  dnsPrefetchControl: true,
+  expectCt: true,
+  frameguard: true,
+  hidePoweredBy: true,
+  hsts: true,
+  ieNoOpen: true,
+  noSniff: true,
+  originAgentCluster: true,
+  permittedCrossDomainPolicies: true,
+  referrerPolicy: true,
+  xssFilter: true,
+});
+
+module.exports = securityHeaders;
diff --git a/fems-api/src/services/permission.service.js b/fems-api/src/services/permission.service.js
new file mode 100644
index 0000000..4c3205a
--- /dev/null
+++ b/fems-api/src/services/permission.service.js
@@ -0,0 +1,124 @@
+// src/services/permission.service.js
+const { Role, UserRole, User } = require("../models");
+const redis = require("../config/redis");
+const logger = require("../utils/logger");
+
+class PermissionService {
+  constructor() {
+    // 권한 캐시 TTL (24시간)
+    this.CACHE_TTL = 24 * 60 * 60;
+  }
+
+  /**
+   * 사용자의 권한을 검사
+   */
+  async checkPermission(userId, resource, action) {
+    try {
+      const permissions = await this.getUserPermissions(userId);
+      return this.evaluatePermission(permissions, resource, action);
+    } catch (error) {
+      logger.error("Permission check failed", {
+        userId,
+        resource,
+        action,
+        error,
+      });
+      return false;
+    }
+  }
+
+  /**
+   * 사용자의 모든 권한 조회 (캐시 활용)
+   */
+  async getUserPermissions(userId) {
+    const cacheKey = `permissions:${userId}`;
+
+    // 캐시 확인
+    let permissions = await redis.get(cacheKey);
+    if (permissions) {
+      return JSON.parse(permissions);
+    }
+
+    // DB에서 권한 조회
+    permissions = await this._loadPermissionsFromDB(userId);
+
+    // 캐시 저장
+    await redis.set(
+      cacheKey,
+      JSON.stringify(permissions),
+      "EX",
+      this.CACHE_TTL
+    );
+
+    return permissions;
+  }
+
+  /**
+   * DB에서 사용자 권한 로드
+   */
+  async _loadPermissionsFromDB(userId) {
+    const user = await User.findByPk(userId, {
+      include: [
+        {
+          model: Role,
+          through: UserRole,
+          where: { isActive: true },
+        },
+      ],
+    });
+
+    if (!user) {
+      throw new Error("User not found");
+    }
+
+    // 모든 역할의 권한을 병합
+    return user.Roles.reduce((acc, role) => {
+      return this._mergePermissions(acc, role.permissions);
+    }, {});
+  }
+
+  /**
+   * 권한 평가
+   */
+  evaluatePermission(permissions, resource, action) {
+    // 슈퍼관리자 권한 체크
+    if (permissions.superAdmin) {
+      return true;
+    }
+
+    // 리소스별 권한 체크
+    const resourcePermissions = permissions[resource];
+    if (!resourcePermissions) {
+      return false;
+    }
+
+    // 작업 권한 체크
+    return resourcePermissions.includes(action);
+  }
+
+  /**
+   * 권한 병합
+   */
+  _mergePermissions(base, additional) {
+    const merged = { ...base };
+
+    Object.entries(additional).forEach(([resource, actions]) => {
+      if (!merged[resource]) {
+        merged[resource] = new Set();
+      }
+      actions.forEach((action) => merged[resource].add(action));
+    });
+
+    return merged;
+  }
+
+  /**
+   * 사용자 권한 캐시 무효화
+   */
+  async invalidateUserPermissions(userId) {
+    const cacheKey = `permissions:${userId}`;
+    await redis.del(cacheKey);
+  }
+}
+
+module.exports = PermissionService;
diff --git a/fems-api/src/utils/cache.js b/fems-api/src/utils/cache.js
new file mode 100644
index 0000000..3ee94b4
--- /dev/null
+++ b/fems-api/src/utils/cache.js
@@ -0,0 +1,149 @@
+// src/utils/cache.js
+const redis = require("../config/redis");
+const logger = require("./logger");
+const { User } = require("../models");
+const { DatabaseUtils } = require("./database");
+const { PermissionService } = require("../services/permission.service");
+
+class CacheManager {
+  constructor(prefix = "app") {
+    this.prefix = prefix;
+    this.defaultTTL = 3600; // 1시간
+  }
+
+  /**
+   * 캐시 키 생성
+   */
+  _generateKey(key) {
+    return `${this.prefix}:${key}`;
+  }
+
+  /**
+   * 캐시 조회 또는 설정
+   */
+  async getOrSet(key, callback, ttl = this.defaultTTL) {
+    const cacheKey = this._generateKey(key);
+
+    try {
+      // 캐시 확인
+      const cached = await redis.get(cacheKey);
+      if (cached) {
+        return JSON.parse(cached);
+      }
+
+      // 캐시가 없는 경우 콜백 실행
+      const data = await callback();
+
+      // 캐시 저장
+      await redis.set(cacheKey, JSON.stringify(data), "EX", ttl);
+
+      return data;
+    } catch (error) {
+      logger.error("Cache operation failed", { key, error });
+      // 캐시 실패 시 콜백 직접 실행
+      return callback();
+    }
+  }
+
+  /**
+   * 캐시 무효화
+   */
+  async invalidate(key) {
+    const cacheKey = this._generateKey(key);
+    await redis.del(cacheKey);
+  }
+
+  /**
+   * 패턴으로 캐시 무효화
+   */
+  async invalidatePattern(pattern) {
+    const keys = await redis.keys(this._generateKey(pattern));
+    if (keys.length > 0) {
+      await redis.del(keys);
+    }
+  }
+
+  /**
+   * 해시 캐시 처리
+   */
+  async hashGetOrSet(hashKey, field, callback, ttl = this.defaultTTL) {
+    const cacheKey = this._generateKey(hashKey);
+
+    try {
+      // 해시 필드 확인
+      const cached = await redis.hget(cacheKey, field);
+      if (cached) {
+        return JSON.parse(cached);
+      }
+
+      // 캐시가 없는 경우 콜백 실행
+      const data = await callback();
+
+      // 해시 필드 저장
+      await redis.hset(cacheKey, field, JSON.stringify(data));
+      await redis.expire(cacheKey, ttl);
+
+      return data;
+    } catch (error) {
+      logger.error("Hash cache operation failed", { hashKey, field, error });
+      return callback();
+    }
+  }
+}
+
+// 사용 예시를 위한 서비스 구현
+class UserCacheService {
+  constructor() {
+    this.cacheManager = new CacheManager("users");
+  }
+
+  /**
+   * 사용자 정보 조회 (캐시 적용)
+   */
+  async getUserById(userId) {
+    return this.cacheManager.getOrSet(
+      `user:${userId}`,
+      async () => {
+        const user = await User.findByPk(userId);
+        return user ? user.toJSON() : null;
+      },
+      3600 // 1시간 캐시
+    );
+  }
+
+  /**
+   * 사용자의 권한 정보 조회 (해시 캐시 적용)
+   */
+  async getUserPermissions(userId) {
+    return this.cacheManager.hashGetOrSet(
+      `permissions`,
+      userId,
+      async () => {
+        const permissions = await PermissionService.getUserPermissions(userId);
+        return permissions;
+      },
+      3600 // 1시간 캐시
+    );
+  }
+
+  /**
+   * 사용자 정보 업데이트 후 캐시 무효화
+   */
+  async updateUser(userId, userData) {
+    return DatabaseUtils.withTransaction(async (transaction) => {
+      const user = await User.findByPk(userId);
+      await user.update(userData, { transaction });
+
+      // 관련 캐시 무효화
+      await this.cacheManager.invalidate(`user:${userId}`);
+      await this.cacheManager.hashGetOrSet(`permissions`, userId);
+
+      return user;
+    });
+  }
+}
+
+module.exports = {
+  CacheManager,
+  UserCacheService,
+};
diff --git a/fems-api/src/utils/database.js b/fems-api/src/utils/database.js
new file mode 100644
index 0000000..5709599
--- /dev/null
+++ b/fems-api/src/utils/database.js
@@ -0,0 +1,49 @@
+// src/utils/database.js
+const { sequelize } = require("../models");
+const logger = require("./logger");
+
+class DatabaseUtils {
+  /**
+   * 트랜잭션 관리 유틸리티
+   * @param {Function} callback - 트랜잭션 내에서 실행할 콜백 함수
+   */
+  static async withTransaction(callback) {
+    const transaction = await sequelize.transaction();
+
+    try {
+      const result = await callback(transaction);
+      await transaction.commit();
+      return result;
+    } catch (error) {
+      await transaction.rollback();
+      logger.error("Transaction failed", { error });
+      throw error;
+    }
+  }
+
+  /**
+   * 벌크 연산 유틸리티
+   * @param {Array} items - 처리할 아이템 배열
+   * @param {Function} handler - 각 아이템을 처리할 핸들러 함수
+   * @param {Object} options - 설정 옵션
+   */
+  static async bulkOperation(items, handler, options = {}) {
+    const batchSize = options.batchSize || 1000;
+    const results = [];
+
+    for (let i = 0; i < items.length; i += batchSize) {
+      const batch = items.slice(i, i + batchSize);
+
+      await this.withTransaction(async (transaction) => {
+        const batchResults = await Promise.all(
+          batch.map((item) => handler(item, transaction))
+        );
+        results.push(...batchResults);
+      });
+    }
+
+    return results;
+  }
+}
+
+module.exports = DatabaseUtils;
diff --git a/fems-api/src/utils/errors.js b/fems-api/src/utils/errors.js
new file mode 100644
index 0000000..d7941ea
--- /dev/null
+++ b/fems-api/src/utils/errors.js
@@ -0,0 +1,37 @@
+// src/utils/errors.js
+class AppError extends Error {
+  constructor(message, statusCode = 500, errors = []) {
+    super(message);
+    this.statusCode = statusCode;
+    this.errors = errors;
+    this.status = `${statusCode}`.startsWith("4") ? "fail" : "error";
+    this.isOperational = true;
+
+    Error.captureStackTrace(this, this.constructor);
+  }
+}
+
+class ValidationError extends AppError {
+  constructor(message, errors = []) {
+    super(message, 400, errors);
+  }
+}
+
+class AuthenticationError extends AppError {
+  constructor(message) {
+    super(message, 401);
+  }
+}
+
+class AuthorizationError extends AppError {
+  constructor(message) {
+    super(message, 403);
+  }
+}
+
+module.exports = {
+  AppError,
+  ValidationError,
+  AuthenticationError,
+  AuthorizationError,
+};
diff --git a/fems-api/src/utils/logger.js b/fems-api/src/utils/logger.js
new file mode 100644
index 0000000..0c1fd11
--- /dev/null
+++ b/fems-api/src/utils/logger.js
@@ -0,0 +1,59 @@
+// src/utils/logger.js
+const winston = require("winston");
+const { createLogger, format, transports } = winston;
+const { combine, timestamp, printf, colorize } = format;
+
+// 로그 포맷 정의
+const logFormat = printf(({ level, message, timestamp, ...metadata }) => {
+  let msg = `${timestamp} [${level}] : ${message}`;
+
+  if (Object.keys(metadata).length > 0) {
+    msg += JSON.stringify(metadata);
+  }
+
+  return msg;
+});
+
+// 로거 생성
+const logger = createLogger({
+  format: combine(timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), logFormat),
+  transports: [
+    // 콘솔 출력
+    new transports.Console({
+      format: combine(colorize(), logFormat),
+    }),
+    // 에러 로그 파일
+    new transports.File({
+      filename: "logs/error.log",
+      level: "error",
+    }),
+    // 전체 로그 파일
+    new transports.File({
+      filename: "logs/combined.log",
+    }),
+  ],
+});
+
+// 감사 로그를 위한 별도 로거
+const auditLogger = createLogger({
+  format: combine(
+    timestamp(),
+    printf(({ message, timestamp, ...metadata }) => {
+      return JSON.stringify({
+        timestamp,
+        ...message,
+        ...metadata,
+      });
+    })
+  ),
+  transports: [
+    new transports.File({
+      filename: "logs/audit.log",
+    }),
+  ],
+});
+
+module.exports = {
+  logger,
+  auditLogger,
+};
diff --git a/fems-api/src/utils/security.js b/fems-api/src/utils/security.js
new file mode 100644
index 0000000..be8ca9e
--- /dev/null
+++ b/fems-api/src/utils/security.js
@@ -0,0 +1,125 @@
+// src/utils/security.js
+const crypto = require("crypto");
+const jwt = require("jsonwebtoken");
+const { AuthenticationError } = require("./errors");
+const config = require("../config/config");
+const redis = require("../config/redis");
+// const logger = require("./logger");
+
+class SecurityUtils {
+  /**
+   * JWT 토큰 생성
+   */
+  static generateTokens(payload) {
+    const accessToken = jwt.sign(payload, config.jwt.secret, {
+      expiresIn: config.jwt.accessTokenExpiry,
+    });
+
+    const refreshToken = jwt.sign(payload, config.jwt.refreshSecret, {
+      expiresIn: config.jwt.refreshTokenExpiry,
+    });
+
+    return {
+      accessToken,
+      refreshToken,
+    };
+  }
+
+  /**
+   * 토큰 검증
+   */
+  static async verifyToken(token, isRefreshToken = false) {
+    try {
+      // 토큰 블랙리스트 확인
+      const isBlacklisted = await this.checkTokenBlacklist(token);
+      if (isBlacklisted) {
+        throw new AuthenticationError("Token has been revoked");
+      }
+
+      const secret = isRefreshToken
+        ? config.jwt.refreshSecret
+        : config.jwt.secret;
+      return jwt.verify(token, secret);
+    } catch (error) {
+      if (error.name === "TokenExpiredError") {
+        throw new AuthenticationError("Token has expired");
+      }
+      throw new AuthenticationError("Invalid token");
+    }
+  }
+
+  /**
+   * 토큰 블랙리스트 관리
+   */
+  static async addToBlacklist(token, expirationTime) {
+    const tokenHash = this.hashToken(token);
+    await redis.set(`blacklist:${tokenHash}`, "true", "EX", expirationTime);
+  }
+
+  static async checkTokenBlacklist(token) {
+    const tokenHash = this.hashToken(token);
+    return await redis.exists(`blacklist:${tokenHash}`);
+  }
+
+  /**
+   * 토큰 해시화
+   */
+  static hashToken(token) {
+    return crypto.createHash("sha256").update(token).digest("hex");
+  }
+
+  /**
+   * API 키 생성 및 관리
+   */
+  static generateApiKey() {
+    return crypto.randomBytes(32).toString("hex");
+  }
+
+  /**
+   * IP 제한 검사
+   */
+  static checkIpRestriction(allowedIps, currentIp) {
+    if (!allowedIps || allowedIps.length === 0) {
+      return true;
+    }
+    return allowedIps.some((ip) => {
+      if (ip.includes("*")) {
+        const pattern = ip.replace(/\*/g, "\\d+");
+        const regex = new RegExp(`^${pattern}$`);
+        return regex.test(currentIp);
+      }
+      return ip === currentIp;
+    });
+  }
+
+  /**
+   * 데이터 암호화/복호화
+   */
+  static encrypt(text) {
+    const iv = crypto.randomBytes(16);
+    const cipher = crypto.createCipheriv(
+      "aes-256-cbc",
+      Buffer.from(config.encryption.key),
+      iv
+    );
+    let encrypted = cipher.update(text);
+    encrypted = Buffer.concat([encrypted, cipher.final()]);
+    return `${iv.toString("hex")}:${encrypted.toString("hex")}`;
+  }
+
+  static decrypt(text) {
+    const [ivHex, encryptedHex] = text.split(":");
+    const iv = Buffer.from(ivHex, "hex");
+    const encrypted = Buffer.from(encryptedHex, "hex");
+    const decipher = crypto.createDecipheriv(
+      "aes-256-cbc",
+      Buffer.from(config.encryption.key),
+      iv
+    );
+    let decrypted = decipher.update(encrypted);
+    decrypted = Buffer.concat([decrypted, decipher.final()]);
+    return decrypted.toString();
+  }
+}
+
+module.exports = SecurityUtils;
diff --git a/fems-app/src/app/(equipment)/maintenance/page.tsx b/fems-app/src/app/(equipment)/maintenance/page.tsx
index 34637f5..5ecbb4a 100644
--- a/fems-app/src/app/(equipment)/maintenance/page.tsx
+++ b/fems-app/src/app/(equipment)/maintenance/page.tsx
@@ -95,12 +95,12 @@ const MaintenancePage = () => {
         return statusMap[row.original.status] || row.original.status;
       },
     },
-    {
-      accessorKey: "scheduledDate",
-      header: "예정일",
-      cell: ({ row }) =>
-        new Date(row.original.scheduledDate).toLocaleDateString(),
-    },
+    // {
+    //   accessorKey: "scheduledDate",
+    //   header: "예정일",
+    //   cell: ({ row }) =>
+    //     new Date(row.original.scheduledDate).toLocaleDateString(),
+    // },
     {
       accessorKey: "completionDate",
       header: "완료일",