diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index cbf9df2..c60a7f3 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,8 +1,12 @@
 {
   "name": "replace_me",
-  "image": "micr.cloud.mioffice.cn/zhaoyingbo/dev:bun",
-  "remoteUser": "bun",
-  "containerUser": "bun",
+  "image": "mcr.microsoft.com/devcontainers/typescript-node:20",
+  "features": {
+    "ghcr.io/devcontainers/features/docker-in-docker:2": {
+      "version": "latest",
+      "moby": true
+    }
+  },
   "customizations": {
     "vscode": {
       "settings": {
@@ -10,20 +14,25 @@
         "editor.guides.bracketPairs": true,
         "editor.defaultFormatter": "esbenp.prettier-vscode",
         "editor.formatOnSave": true,
-        "github.copilot.chat.localeOverride": "zh-CN"
+        "github.copilot.chat.localeOverride": "zh-CN",
+        "editor.codeActionsOnSave": {
+          "source.fixAll.eslint": "always"
+        }
       },
       "extensions": [
-        "dbaeumer.vscode-eslint",
-        "esbenp.prettier-vscode",
+        "jock.svg",
+        "GitHub.copilot",
         "eamodio.gitlens",
         "unifiedjs.vscode-mdx",
-        "oderwat.indent-rainbow",
-        "jock.svg",
-        "ChakrounAnas.turbo-console-log",
+        "dbaeumer.vscode-eslint",
+        "esbenp.prettier-vscode",
         "Gruntfuggly.todo-tree",
+        "ChakrounAnas.turbo-console-log",
+        "streetsidesoftware.code-spell-checker",
         "MS-CEINTL.vscode-language-pack-zh-hans",
-        "GitHub.copilot"
+        "Prisma.prisma"
       ]
     }
-  }
+  },
+  "onCreateCommand": "curl -fsSL https://bun.sh/install | bash"
 }
diff --git a/.env b/.env
new file mode 100644
index 0000000..14f5aab
--- /dev/null
+++ b/.env
@@ -0,0 +1,7 @@
+# Environment variables declared in this file are automatically made available to Prisma.
+# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
+
+# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
+# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
+
+DATABASE_URL="mysql://root:rootpassword@localhost:3306/testdb"
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 52962c2..1a74851 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,8 +49,8 @@ profile-*
 .idea
 
 # vscode
-.vscode
-*code-workspace
+# .vscode
+# *code-workspace
 
 # clinic
 profile*
diff --git a/.husky/commit-msg b/.husky/commit-msg
new file mode 100644
index 0000000..0a4b97d
--- /dev/null
+++ b/.husky/commit-msg
@@ -0,0 +1 @@
+npx --no -- commitlint --edit $1
diff --git a/.husky/pre-commit b/.husky/pre-commit
new file mode 100644
index 0000000..af5adff
--- /dev/null
+++ b/.husky/pre-commit
@@ -0,0 +1 @@
+lint-staged
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..04bbd13
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+  "cSpell.words": ["bunx", "oxlint"]
+}
diff --git a/bun.lockb b/bun.lockb
index 9961da9..0e2dd0e 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/bunfig.toml b/bunfig.toml
new file mode 100644
index 0000000..76ef786
--- /dev/null
+++ b/bunfig.toml
@@ -0,0 +1,2 @@
+[install]
+registry = "https://registry.npmjs.org"
\ No newline at end of file
diff --git a/commitlint.config.js b/commitlint.config.js
new file mode 100644
index 0000000..fba73fb
--- /dev/null
+++ b/commitlint.config.js
@@ -0,0 +1 @@
+export default { extends: ["@commitlint/config-conventional"] }
diff --git a/controllers/template/index.ts b/controllers/template/index.ts
index 437b535..078d6f7 100644
--- a/controllers/template/index.ts
+++ b/controllers/template/index.ts
@@ -2,6 +2,6 @@ const templateFunc = () => {}
 
 const template = {
   templateFunc,
-};
+}
 
-export default template;
+export default template
diff --git a/db/index.ts b/db/index.ts
index 8570c84..1a300d5 100644
--- a/db/index.ts
+++ b/db/index.ts
@@ -1,7 +1,7 @@
-import user from "./user";
+import user from "./user"
 
 const db = {
   user,
-};
+}
 
-export default db;
+export default db
diff --git a/db/pbClient.ts b/db/pbClient.ts
index 7999649..7bd419b 100644
--- a/db/pbClient.ts
+++ b/db/pbClient.ts
@@ -1,7 +1,7 @@
-import PocketBase from "pocketbase";
+import PocketBase from "pocketbase"
 
-const pbClient = new PocketBase("https://ci-pb.xiaomiwh.cn");
+const pbClient = new PocketBase("https://ci-pb.xiaomiwh.cn")
 
-pbClient.autoCancellation(false);
+pbClient.autoCancellation(false)
 
-export default pbClient;
+export default pbClient
diff --git a/db/prisma/user/index.ts b/db/prisma/user/index.ts
new file mode 100644
index 0000000..3b76fe4
--- /dev/null
+++ b/db/prisma/user/index.ts
@@ -0,0 +1,19 @@
+import { PrismaClient } from "@prisma/client"
+
+const prisma = new PrismaClient()
+
+const main = async () => {
+  const user = await prisma.user.create({
+    data: {
+      name: "Alice",
+      email: "alice@example.com",
+    },
+  })
+  console.log(user)
+  const users = await prisma.user.findMany()
+  console.log(users)
+}
+
+main().then(() => {
+  prisma.$disconnect()
+})
diff --git a/db/user/index.ts b/db/user/index.ts
index 389a9ec..c7f52e5 100644
--- a/db/user/index.ts
+++ b/db/user/index.ts
@@ -1,19 +1,19 @@
-import { RecordModel } from "pocketbase";
-import { managePb404 } from "../../utils/pbTools";
-import pbClient from "../pbClient";
+import { RecordModel } from "pocketbase"
+import { managePb404 } from "../../utils/pbTools"
+import pbClient from "../pbClient"
 
 export interface UserRecordModel extends RecordModel {
-  user_id: number;
-  username: string;
-  name: string;
-  avatar_url: string;
-  web_url: string;
+  user_id: number
+  username: string
+  name: string
+  avatar_url: string
+  web_url: string
 }
 
 const getOne = (id: string) =>
   managePb404<UserRecordModel>(
     async () => await pbClient.collection("user").getOne(id)
-  );
+  )
 
 const getOneByUserId = (user_id: number) => {
   return managePb404<UserRecordModel>(
@@ -23,24 +23,24 @@ const getOneByUserId = (user_id: number) => {
         .getFirstListItem(`user_id="${user_id}"`, {
           sort: "-created",
         })
-  );
-};
+  )
+}
 
 const create = async (data: Partial<UserRecordModel>) =>
-  await pbClient.collection("user").create<UserRecordModel>(data);
+  await pbClient.collection("user").create<UserRecordModel>(data)
 
 const upsert = async (data: Partial<UserRecordModel>) => {
-  if (!data.user_id) return null;
-  const userInfo = await getOneByUserId(data.user_id);
-  if (userInfo) return userInfo;
-  return await create(data);
-};
+  if (!data.user_id) return null
+  const userInfo = await getOneByUserId(data.user_id)
+  if (userInfo) return userInfo
+  return await create(data)
+}
 
 const user = {
   create,
   upsert,
   getOne,
   getOneByUserId,
-};
+}
 
-export default user;
+export default user
diff --git a/docker/mysql/dev.docker-compose.yml b/docker/mysql/dev.docker-compose.yml
new file mode 100644
index 0000000..fb3d905
--- /dev/null
+++ b/docker/mysql/dev.docker-compose.yml
@@ -0,0 +1,16 @@
+version: "3.8"
+
+services:
+  mysql:
+    image: micr.cloud.mioffice.cn/zhaoyingbo/mysql:8.0
+    container_name: mysql
+    environment:
+      MYSQL_ROOT_PASSWORD: rootpassword
+      MYSQL_DATABASE: testdb
+    ports:
+      - "3306:3306"
+    volumes:
+      - mysql-data:/var/lib/mysql
+
+volumes:
+  mysql-data:
diff --git a/docker/mysql/run.sh b/docker/mysql/run.sh
new file mode 100644
index 0000000..97001a0
--- /dev/null
+++ b/docker/mysql/run.sh
@@ -0,0 +1 @@
+docker compose -f dev.docker-compose.yml up -d
\ No newline at end of file
diff --git a/docker/mysql/stop.sh b/docker/mysql/stop.sh
new file mode 100644
index 0000000..699e964
--- /dev/null
+++ b/docker/mysql/stop.sh
@@ -0,0 +1 @@
+docker compose -f dev.docker-compose.yml down
\ No newline at end of file
diff --git a/eslint.config.js b/eslint.config.js
index ac8d057..88e3a2b 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -1,26 +1,26 @@
 export default {
   languageOptions: {
     ecmaVersion: 2021,
-    sourceType: 'module',
+    sourceType: "module",
   },
-  ignores: ['*.js', '*.cjs', '*.mjs', '/src/Backup/*'],
-  plugins: ['@typescript-eslint', 'simple-import-sort'],
+  ignores: ["*.js", "*.cjs", "*.mjs", "/src/Backup/*"],
+  plugins: ["@typescript-eslint", "simple-import-sort"],
   extends: [
-    'eslint:recommended',
-    'plugin:@typescript-eslint/recommended',
-    'prettier',
+    "eslint:recommended",
+    "plugin:@typescript-eslint/recommended",
+    "prettier",
   ],
   rules: {
-    '@typescript-eslint/no-explicit-any': 'off',
-    'simple-import-sort/imports': 'error',
-    'simple-import-sort/exports': 'error',
+    "@typescript-eslint/no-explicit-any": "off",
+    "simple-import-sort/imports": "error",
+    "simple-import-sort/exports": "error",
   },
   overrides: [
     {
-      files: ['**/*.ts', '**/*.tsx'],
+      files: ["**/*.ts", "**/*.tsx"],
       languageOptions: {
-        parser: '@typescript-eslint/parser',
+        parser: "@typescript-eslint/parser",
       },
     },
   ],
-};
\ No newline at end of file
+}
diff --git a/index.ts b/index.ts
index e67874e..0fea807 100644
--- a/index.ts
+++ b/index.ts
@@ -1,14 +1,14 @@
-import { initSchedule } from "./schedule";
+import { initSchedule } from "./schedule"
 
 initSchedule()
 
 Bun.serve({
   async fetch(req) {
-    const url = new URL(req.url);
+    const url = new URL(req.url)
     // 根路由
-    if (url.pathname === "/") return new Response("hello, glade to see you!");
-    if (url.pathname === '/ci') return new Response("OK")
-    return new Response("OK");
+    if (url.pathname === "/") return new Response("hello, glade to see you!")
+    if (url.pathname === "/ci") return new Response("OK")
+    return new Response("OK")
   },
   port: 3000,
-});
+})
diff --git a/package.json b/package.json
index 7287580..af7995a 100644
--- a/package.json
+++ b/package.json
@@ -3,21 +3,40 @@
   "module": "index.ts",
   "type": "module",
   "scripts": {
-    "start": "bun run index.ts"
+    "start": "NODE_ENV=production bun run index.ts",
+    "dev": "NODE_ENV=dev bun run index.ts --watch",
+    "lint": "oxlint --fix .",
+    "prepare": "husky",
+    "prettier": "prettier --write .",
+    "init:prisma": "bunx prisma migrate dev --name init"
+  },
+  "lint-staged": {
+    "*.{js,jsx,ts,tsx}": [
+      "oxlint --fix",
+      "eslint --fix",
+      "prettier --write"
+    ]
   },
   "devDependencies": {
-    "eslint": "^9.2.0",
-    "bun-types": "latest",
+    "@commitlint/cli": "^19.5.0",
+    "@commitlint/config-conventional": "^19.5.0",
     "@types/lodash": "^4.14.202",
     "@types/node-schedule": "^2.1.6",
-    "eslint-plugin-simple-import-sort": "^12.1.0",
     "@typescript-eslint/eslint-plugin": "^7.8.0",
-    "@typescript-eslint/parser": "^7.8.0"
+    "@typescript-eslint/parser": "^7.8.0",
+    "bun-types": "latest",
+    "eslint": "^9.2.0",
+    "eslint-plugin-simple-import-sort": "^12.1.0",
+    "husky": "^9.1.6",
+    "lint-staged": "^15.2.10",
+    "oxlint": "^0.11.1",
+    "prettier": "^3.3.3"
   },
   "peerDependencies": {
     "typescript": "^5.0.0"
   },
   "dependencies": {
+    "@prisma/client": "^5.22.0",
     "lodash": "^4.17.21",
     "node-schedule": "^2.1.1",
     "pocketbase": "^0.21.1"
diff --git a/prettier.config.js b/prettier.config.js
new file mode 100644
index 0000000..db67959
--- /dev/null
+++ b/prettier.config.js
@@ -0,0 +1,6 @@
+export default {
+  trailingComma: "es5",
+  tabWidth: 2,
+  semi: false,
+  singleQuote: false,
+}
diff --git a/prisma/migrations/20241116101639_init/migration.sql b/prisma/migrations/20241116101639_init/migration.sql
new file mode 100644
index 0000000..4166918
--- /dev/null
+++ b/prisma/migrations/20241116101639_init/migration.sql
@@ -0,0 +1,9 @@
+-- CreateTable
+CREATE TABLE `User` (
+    `id` INTEGER NOT NULL AUTO_INCREMENT,
+    `name` VARCHAR(191) NOT NULL,
+    `email` VARCHAR(191) NOT NULL,
+
+    UNIQUE INDEX `User_email_key`(`email`),
+    PRIMARY KEY (`id`)
+) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml
new file mode 100644
index 0000000..e5a788a
--- /dev/null
+++ b/prisma/migrations/migration_lock.toml
@@ -0,0 +1,3 @@
+# Please do not edit this file manually
+# It should be added in your version-control system (i.e. Git)
+provider = "mysql"
\ No newline at end of file
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
new file mode 100644
index 0000000..f879a6e
--- /dev/null
+++ b/prisma/schema.prisma
@@ -0,0 +1,20 @@
+// This is your Prisma schema file,
+// learn more about it in the docs: https://pris.ly/d/prisma-schema
+
+// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
+// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
+
+generator client {
+  provider = "prisma-client-js"
+}
+
+datasource db {
+  provider = "mysql"
+  url      = env("DATABASE_URL")
+}
+
+model User {
+  id    Int     @id @default(autoincrement())
+  name  String
+  email String  @unique
+}
\ No newline at end of file
diff --git a/schedule/index.ts b/schedule/index.ts
index 6a3ceec..e2b41d8 100644
--- a/schedule/index.ts
+++ b/schedule/index.ts
@@ -1,10 +1,10 @@
-import schedule from 'node-schedule'
+import schedule from "node-schedule"
 
 const func = () => {}
 
 export const initSchedule = async () => {
   // 定时任务,每15分钟刷新一次token
-  schedule.scheduleJob('*/15 * * * *', func);
+  schedule.scheduleJob("*/15 * * * *", func)
   // 立即执行一次
   func()
 }
diff --git a/service/index.ts b/service/index.ts
index 6fcaa20..a29ad0c 100644
--- a/service/index.ts
+++ b/service/index.ts
@@ -1,7 +1,7 @@
 const fetchGetParams = {
   method: "GET",
   headers: { "PRIVATE-TOKEN": "Zd1UASPcMwVox5tNS6ep" },
-};
+}
 
 /**
  * 获取项目详情
@@ -12,17 +12,17 @@ const fetchTemplate = async (id: number) => {
     const response = await fetch(
       `https://git.n.xiaomi.com/api/v4/projects/${id}`,
       fetchGetParams
-    );
-    const body = (await response.json()) as any;
-    if (body.message === "404 Project Not Found") return null;
-    return body;
+    )
+    const body = (await response.json()) as any
+    if (body.message === "404 Project Not Found") return null
+    return body
   } catch {
-    return null;
+    return null
   }
-};
+}
 
 const service = {
   fetchTemplate,
-};
+}
 
-export default service;
+export default service
diff --git a/types/index.ts b/types/index.ts
index e69de29..92e97c4 100644
--- a/types/index.ts
+++ b/types/index.ts
@@ -0,0 +1,4 @@
+export interface FakeType {
+  name: string
+  age: number
+}
diff --git a/utils/pbTools.ts b/utils/pbTools.ts
index 3d8a903..93a4bc1 100644
--- a/utils/pbTools.ts
+++ b/utils/pbTools.ts
@@ -1,9 +1,9 @@
 export const managePb404 = async <T>(dbFunc: Function): Promise<T | null> => {
   try {
-    return await dbFunc();
+    return await dbFunc()
   } catch (err: any) {
     if (err?.message === "The requested resource wasn't found.") {
-      return null;
-    } else throw err;
+      return null
+    } else throw err
   }
-};
+}