diff --git a/cmdb-api/.ruff.toml b/cmdb-api/.ruff.toml
new file mode 100644
index 0000000..9b8290e
--- /dev/null
+++ b/cmdb-api/.ruff.toml
@@ -0,0 +1,79 @@
+line-length = 120
+cache-dir = ".ruff_cache"
+target-version = "py310"
+unsafe-fixes = true
+show-fixes = true
+
+[lint]
+select = [
+    "E",
+    "F",
+    "I",
+    "TCH",
+    # W
+    "W505",
+    # PT
+    "PT018",
+    # SIM
+    "SIM101",
+    "SIM114",
+    # PGH
+    "PGH004",
+    # PL
+    "PLE1142",
+    # RUF
+    "RUF100",
+    # UP
+    "UP007"
+]
+preview = true
+ignore = ["FURB101"]
+
+[lint.flake8-pytest-style]
+mark-parentheses = false
+parametrize-names-type = "list"
+parametrize-values-row-type = "list"
+parametrize-values-type = "tuple"
+
+[lint.flake8-unused-arguments]
+ignore-variadic-names = true
+
+[lint.isort]
+lines-between-types = 1
+order-by-type = true
+
+[lint.per-file-ignores]
+"**/api/v1/*.py" = ["TCH"]
+"**/model/*.py" = ["TCH003"]
+"**/models/__init__.py" = ["F401", "F403"]
+"**/tests/*.py" = ["E402"]
+"celery_worker.py" = ["F401"]
+"api/views/entry.py" = ["I001"]
+"migrations/*.py" = ["I001", "E402"]
+"*.py" = ["I001"]
+"api/views/common_setting/department.py" = ["F841"]
+"api/lib/common_setting/upload_file.py" = ["F841"]
+"api/lib/common_setting/acl.py" = ["F841"]
+"**/__init__.py" = ["F822"]
+"api/tasks/*.py" = ["E722"]
+"api/views/cmdb/*.py" = ["E722"]
+"api/views/acl/*.py" = ["E722"]
+"api/lib/secrets/*.py" = ["E722", "F841"]
+"api/lib/utils.py" = ["E722", "E731"]
+"api/lib/perm/authentication/cas/*" = ["E113", "F841"]
+"api/lib/perm/acl/*" = ["E722"]
+"api/lib/*" = ["E721", "F722"]
+"api/lib/cmdb/*" = ["F722", "E722"]
+"api/lib/cmdb/search/ci/es/search.py" = ["F841", "SIM114"]
+"api/lib/cmdb/search/ci/db/search.py" = ["F841"]
+"api/lib/cmdb/value.py" = ["F841"]
+"api/lib/cmdb/history.py" = ["E501"]
+"api/commands/common.py" = ["E722"]
+"api/commands/click_cmdb.py" = ["E722"]
+"api/lib/perm/auth.py" = ["SIM114"]
+
+[format]
+preview = true
+quote-style = "single"
+docstring-code-format = true
+skip-magic-trailing-comma = false
diff --git a/cmdb-api/api/commands/click_cmdb.py b/cmdb-api/api/commands/click_cmdb.py
index 9482068..9c9ab11 100644
--- a/cmdb-api/api/commands/click_cmdb.py
+++ b/cmdb-api/api/commands/click_cmdb.py
@@ -346,7 +346,7 @@ def cmdb_inner_secrets_init(address):
     if valid_address(address):
         token = current_app.config.get("INNER_TRIGGER_TOKEN", "") if not token else token
         if not token:
-            token = click.prompt(f'Enter root token', hide_input=True, confirmation_prompt=False)
+            token = click.prompt('Enter root token', hide_input=True, confirmation_prompt=False)
         assert token is not None
         resp = requests.post("{}/api/v0.1/secrets/auto_seal".format(address.strip("/")),
                              headers={"Inner-Token": token})
diff --git a/cmdb-api/api/lib/cmdb/attribute.py b/cmdb-api/api/lib/cmdb/attribute.py
index 2fc9be6..77175b0 100644
--- a/cmdb-api/api/lib/cmdb/attribute.py
+++ b/cmdb-api/api/lib/cmdb/attribute.py
@@ -415,7 +415,7 @@ class AttributeManager(object):
             db.session.rollback()
             current_app.logger.error("update attribute error, {0}".format(str(e)))
 
-            return abort(400, ErrFormat.update_attribute_failed.format(("id=".format(_id))))
+            return abort(400, ErrFormat.update_attribute_failed.format(("id={}".format(_id))))
 
         new = attr.to_dict()
         if not new['choice_web_hook'] and new['is_choice']:
diff --git a/cmdb-api/api/lib/cmdb/ci_type.py b/cmdb-api/api/lib/cmdb/ci_type.py
index dc3cb27..61459a4 100644
--- a/cmdb-api/api/lib/cmdb/ci_type.py
+++ b/cmdb-api/api/lib/cmdb/ci_type.py
@@ -862,7 +862,7 @@ class CITypeRelationManager(object):
 
         graph = nx.DiGraph()
 
-        def get_children(_id):
+        def get_children(_id, graph):
             children = CITypeRelation.get_by(parent_id=_id, to_dict=False)
 
             for i in children:
@@ -870,7 +870,7 @@ class CITypeRelationManager(object):
                     graph.add_edge(i.parent_id, i.child_id)
                     get_children(i.child_id)
 
-        get_children(source_type_id)
+        get_children(source_type_id, graph)
 
         paths = list(nx.all_simple_paths(graph, source_type_id, target_type_ids))
 
diff --git a/cmdb-api/api/lib/cmdb/resp_format.py b/cmdb-api/api/lib/cmdb/resp_format.py
index 71f1236..881fd31 100644
--- a/cmdb-api/api/lib/cmdb/resp_format.py
+++ b/cmdb-api/api/lib/cmdb/resp_format.py
@@ -16,8 +16,9 @@ class ErrFormat(CommonErrFormat):
     argument_file_not_found = _l("The file doesn't seem to be uploaded")  # 文件似乎并未上传
 
     attribute_not_found = _l("Attribute {} does not exist!")  # 属性 {} 不存在!
+    # 该属性是模型的唯一标识,不能被删除!
     attribute_is_unique_id = _l(
-        "This attribute is the unique identifier of the model and cannot be deleted!")  # 该属性是模型的唯一标识,不能被删除!
+        "This attribute is the unique identifier of the model and cannot be deleted!")  
     attribute_is_ref_by_type = _l(
         "This attribute is referenced by model {} and cannot be deleted!")  # 该属性被模型 {} 引用, 不能删除!
     attribute_value_type_cannot_change = _l(
@@ -129,7 +130,8 @@ class ErrFormat(CommonErrFormat):
     adr_default_ref_once = _l("The default auto-discovery rule is already referenced by model {}!")
     # unique_key方法必须返回非空字符串!
     adr_unique_key_required = _l("The unique_key method must return a non-empty string!")
-    adr_plugin_attributes_list_required = _l("The attributes method must return a list")  # attributes方法必须返回的是list
+    # attributes方法必须返回的是list
+    adr_plugin_attributes_list_required = _l("The attributes method must return a list")  
     # attributes方法返回的list不能为空!
     adr_plugin_attributes_list_no_empty = _l("The list returned by the attributes method cannot be empty!")
     # 只有管理员才可以定义执行机器为: 所有节点!
diff --git a/cmdb-api/api/lib/cmdb/utils.py b/cmdb-api/api/lib/cmdb/utils.py
index 7ea7e2a..f924037 100644
--- a/cmdb-api/api/lib/cmdb/utils.py
+++ b/cmdb-api/api/lib/cmdb/utils.py
@@ -55,7 +55,6 @@ def str2datetime(x):
     return datetime.datetime.strptime(x, "%Y-%m-%d %H:%M")
 
 
-
 class ValueTypeMap(object):
     deserialize = {
         ValueTypeEnum.INT: string2int,
diff --git a/cmdb-api/api/lib/common_setting/decorator.py b/cmdb-api/api/lib/common_setting/decorator.py
index 30106e1..d55b6fe 100644
--- a/cmdb-api/api/lib/common_setting/decorator.py
+++ b/cmdb-api/api/lib/common_setting/decorator.py
@@ -1,6 +1,6 @@
 import functools
 
-from flask import abort, session
+from flask import abort, session, current_app
 from api.lib.common_setting.acl import ACLManager
 from api.lib.common_setting.resp_format import ErrFormat
 from api.lib.perm.acl.acl import is_app_admin
@@ -15,6 +15,7 @@ def perms_role_required(app_name, resource_type_name, resource_name, perm, role_
             try:
                 has_perms = acl.role_has_perms(session["acl"]['rid'], resource_name, resource_type_name, perm)
             except Exception as e:
+                current_app.logger.error(f"acl role_has_perms err: {e}")
                 # resource_type not exist, continue check role
                 if role_name:
                     if role_name not in session.get("acl", {}).get("parentRoles", []) and not is_app_admin(app_name):
diff --git a/cmdb-api/api/lib/common_setting/department.py b/cmdb-api/api/lib/common_setting/department.py
index 7d72bc6..61d5d58 100644
--- a/cmdb-api/api/lib/common_setting/department.py
+++ b/cmdb-api/api/lib/common_setting/department.py
@@ -476,7 +476,7 @@ class EditDepartmentInACL(object):
         for employee in e_list:
             employee_acl_rid = employee.get('e_acl_rid')
             if employee_acl_rid == 0:
-                result.append(f"employee_acl_rid == 0")
+                result.append("employee_acl_rid == 0")
                 continue
             cls.remove_single_employee_from_old_department(acl, employee, result)
 
@@ -501,8 +501,8 @@ class EditDepartmentInACL(object):
             acl.remove_user_from_role(employee.get('e_acl_rid'), payload)
             current_app.logger.info(f"remove {employee.get('e_acl_rid')} from {d_acl_rid}")
         except Exception as e:
-            result.append(
-                f"remove_user_from_role employee_acl_rid: {employee.get('e_acl_rid')}, parent_id: {d_acl_rid}, err: {e}")
+            err = f"remove_user_from_role e_acl_rid: {employee.get('e_acl_rid')}, parent_id: {d_acl_rid}, err: {e}"
+            result.append(err)
 
         return True
 
@@ -548,7 +548,7 @@ class EditDepartmentInACL(object):
         for employee in e_list:
             employee_acl_rid = employee.get('e_acl_rid')
             if employee_acl_rid == 0:
-                result.append(f"employee_acl_rid == 0")
+                result.append("employee_acl_rid == 0")
                 continue
 
             cls.remove_single_employee_from_old_department(acl, employee, result)
diff --git a/cmdb-api/api/lib/common_setting/employee.py b/cmdb-api/api/lib/common_setting/employee.py
index ca7173f..5dbeeb2 100644
--- a/cmdb-api/api/lib/common_setting/employee.py
+++ b/cmdb-api/api/lib/common_setting/employee.py
@@ -4,7 +4,7 @@ import traceback
 from datetime import datetime
 
 import requests
-from flask import abort
+from flask import abort, current_app
 from flask_login import current_user
 from sqlalchemy import or_, literal_column, func, not_, and_
 from werkzeug.datastructures import MultiDict
@@ -478,7 +478,7 @@ class EmployeeCRUD(object):
             Employee.deleted == 0,
             Employee.block == block,
         ]
-        if type(department_id) == list:
+        if isinstance(department_id, list):
             if len(department_id) == 0:
                 return []
             else:
@@ -702,6 +702,7 @@ class EmployeeCRUD(object):
             try:
                 last_login = datetime.strptime(last_login, '%Y-%m-%d %H:%M:%S')
             except Exception as e:
+                current_app.logger.error(f"strptime {last_login} err: {e}")
                 last_login = datetime.now()
         else:
             last_login = datetime.now()
@@ -712,6 +713,7 @@ class EmployeeCRUD(object):
             )
             return last_login
         except Exception as e:
+            current_app.logger.error(f"update last_login err: {e}")
             return
 
 
diff --git a/cmdb-api/api/lib/common_setting/notice_config.py b/cmdb-api/api/lib/common_setting/notice_config.py
index 152eb53..6246962 100644
--- a/cmdb-api/api/lib/common_setting/notice_config.py
+++ b/cmdb-api/api/lib/common_setting/notice_config.py
@@ -2,7 +2,7 @@ import requests
 
 from api.lib.common_setting.const import BotNameMap
 from api.lib.common_setting.resp_format import ErrFormat
-from api.models.common_setting import CompanyInfo, NoticeConfig
+from api.models.common_setting import NoticeConfig
 from wtforms import Form
 from wtforms import StringField
 from wtforms import validators
diff --git a/cmdb-api/api/lib/common_setting/role_perm_base.py b/cmdb-api/api/lib/common_setting/role_perm_base.py
index 7a210a5..a508b06 100644
--- a/cmdb-api/api/lib/common_setting/role_perm_base.py
+++ b/cmdb-api/api/lib/common_setting/role_perm_base.py
@@ -48,7 +48,9 @@ class CMDBApp(BaseApp):
         {"page": "Model_Relationships", "page_cn": "模型关系", "perms": ["read"]},
         {"page": "Operation_Audit", "page_cn": "操作审计", "perms": ["read"]},
         {"page": "Relationship_Types", "page_cn": "关系类型", "perms": ["read"]},
-        {"page": "Auto_Discovery", "page_cn": "自动发现", "perms": ["read", "create_plugin", "update_plugin", "delete_plugin"]},
+        {"page": "Auto_Discovery", "page_cn": "自动发现",
+         "perms": ["read", "create_plugin", "update_plugin", "delete_plugin"]
+        },
         {"page": "TopologyView", "page_cn": "拓扑视图",
          "perms": ["read", "create_topology_group", "update_topology_group", "delete_topology_group",
                    "create_topology_view"],
diff --git a/cmdb-api/api/lib/perm/acl/__init__.py b/cmdb-api/api/lib/perm/acl/__init__.py
index a44fc64..2185830 100644
--- a/cmdb-api/api/lib/perm/acl/__init__.py
+++ b/cmdb-api/api/lib/perm/acl/__init__.py
@@ -6,7 +6,7 @@ from functools import wraps
 from flask import abort
 from flask import request
 
-from api.lib.perm.acl.cache import AppCache, AppAccessTokenCache
+from api.lib.perm.acl.cache import AppCache
 from api.lib.perm.acl.resp_format import ErrFormat
 
 
diff --git a/cmdb-api/api/lib/perm/acl/role.py b/cmdb-api/api/lib/perm/acl/role.py
index 2faacbb..e08207d 100644
--- a/cmdb-api/api/lib/perm/acl/role.py
+++ b/cmdb-api/api/lib/perm/acl/role.py
@@ -1,8 +1,5 @@
 # -*- coding:utf-8 -*-
 
-
-import time
-
 import redis_lock
 import six
 from flask import abort
diff --git a/cmdb-api/api/lib/utils.py b/cmdb-api/api/lib/utils.py
index 8f79358..f1b397c 100644
--- a/cmdb-api/api/lib/utils.py
+++ b/cmdb-api/api/lib/utils.py
@@ -1,7 +1,6 @@
 # -*- coding:utf-8 -*- 
 
 import base64
-from typing import Set
 
 import elasticsearch
 import redis
diff --git a/cmdb-api/api/views/common_setting/employee.py b/cmdb-api/api/views/common_setting/employee.py
index 173dc13..06e947b 100644
--- a/cmdb-api/api/views/common_setting/employee.py
+++ b/cmdb-api/api/views/common_setting/employee.py
@@ -131,7 +131,7 @@ class EmployeeChangePasswordWithACLID(APIView):
         if not password:
             abort(400, ErrFormat.password_is_required)
 
-        data = EmployeeCRUD.change_password_by_uid(_uid, password)
+        EmployeeCRUD.change_password_by_uid(_uid, password)
         return self.jsonify(200)
 
 
diff --git a/cmdb-api/api/views/common_setting/file_manage.py b/cmdb-api/api/views/common_setting/file_manage.py
index fb304df..35f24e8 100644
--- a/cmdb-api/api/views/common_setting/file_manage.py
+++ b/cmdb-api/api/views/common_setting/file_manage.py
@@ -6,7 +6,7 @@ import magic
 
 from api.lib.common_setting.const import MIMEExtMap
 from api.lib.common_setting.resp_format import ErrFormat
-from api.lib.common_setting.upload_file import allowed_file, generate_new_file_name, CommonFileCRUD
+from api.lib.common_setting.upload_file import generate_new_file_name, CommonFileCRUD
 from api.resource import APIView
 
 prefix = '/file'
diff --git a/cmdb-api/requirements.txt b/cmdb-api/requirements.txt
index 33fe829..5f256c1 100644
--- a/cmdb-api/requirements.txt
+++ b/cmdb-api/requirements.txt
@@ -58,3 +58,4 @@ python-magic==0.4.27
 jsonpath==0.82.2
 networkx>=3.1
 ipaddress>=1.0.23
+ruff==0.8.3