---
# System prepended metadata

title: 後端環境相關
tags: [環境相關]

---

---

title: 後端環境相關
tags: [環境相關]

---

# 後端環境相關

> 主要採用 JavaScript，並補充 TypeScript 專案的建構方式

## 後端建立環境指令與順序

1. 🧰 專案初始化與安裝流程
2. ⚙️ 開發用指令（scripts）
3. 📌 需手動建立的檔案建議（.env、結構）

📁 推測的檔案內容依據：

- 框架：Express
- 驗證系統：Passport（local + jwt）
- 資料庫：MongoDB（Mongoose）
- 加密：bcrypt
- 環境變數：dotenv
- 開發工具：nodemon + eslint + prettier

## 🧾 整體安裝清單懶人表（依順序）

| 類別               | 套件                                                                | 安裝指令                                                                                         |
| ------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| 建立環境           | `express dotenv`                                                    | `npm install express dotenv`                                                                     |
| 建立環境（開發用） | `nodemon eslint ...`                                                | `npm install -D nodemon eslint @eslint/js eslint-config-prettier eslint-plugin-prettier globals` |
| 常駐工具           | `cors http-status-codes validator`                                  | `npm install cors http-status-codes validator`                                                   |
| 功能型功能         | `bcrypt jsonwebtoken mongoose passport passport-local passport-jwt` | `npm install bcrypt jsonwebtoken mongoose passport passport-local passport-jwt`                  |

---

# 🧰 專案初始化與安裝流程

## 💿 進入專案資料夾裡面放後端的區域

```
cd back
```

---

## 1️⃣ 建立環境（系統框架與開發基礎）

> 📌 目的：讓 Express 專案可以跑起來、有伺服器、有環境變數、能熱重啟、能檢查語法

### 📍 初始化 Node 專案

```
npm init --yes
npm i -D nodemon
```

#### 📝 改動 packge.json

設定為 module 語法

```
  "type": "module",
```

設定開發用指令（scripts）

```
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "nodemon index.js",
    "start": "node index.js"
  },
```

### 📍 安裝框架與環境變數工具

```
npm i express dotenv
```

### 📌 需手動建立的檔案建議（.env、.gitignore）

#### 📝 建立檔案.env

> 內容為：環境變數等不能說的秘密

檔名

```
.env
```

#### 📝 建立檔案.gitignore

> 內容為：要設定讓 git 忽略的檔案

檔名

```
.gitignore
```

內容（最少）

```
.env
node_modules
dump/*
!dump/.gitkeep
```

#### 📁 建立資料夾 models

> 內容：定義資料庫的資料結構（Schema）、驗證規則與資料模型

```
models
```

**用途說明**：

- 定義資料表/集合的欄位結構與資料型態
- 設定欄位驗證規則（必填、長度、格式等）
- 定義資料模型的方法（如密碼加密、資料查詢等）

**常見檔案範例**：

- `user.js`：使用者資料模型
- `product.js`：商品資料模型
- `order.js`：訂單資料模型

**Mongoose 範例**：

```js
import { Schema, model } from "mongoose";

const userSchema = new Schema({
  account: { type: String, required: true, unique: true },
  email: { type: String, required: true },
  password: { type: String, required: true },
});

export default model("users", userSchema);
```

#### 📁 建立資料夾 controllers

> 內容：處理業務邏輯，對資料庫執行增刪改查（CRUD）操作

```
controllers
```

**用途說明**：

- 接收路由傳來的請求資料
- 呼叫 models 進行資料庫操作
- 處理資料處理邏輯與錯誤處理
- 回傳處理結果給前端

**常見檔案範例**：

- `userController.js`：處理使用者相關操作（註冊、登入、更新資料等）
- `productController.js`：處理商品相關操作（新增、查詢、修改、刪除）
- `orderController.js`：處理訂單相關操作

**Controller 範例**：

```js
import User from "../models/user.js";
import { StatusCodes } from "http-status-codes";

export const register = async (req, res) => {
  try {
    await User.create(req.body);
    res.status(StatusCodes.OK).json({ success: true, message: "註冊成功" });
  } catch (error) {
    res
      .status(StatusCodes.INTERNAL_SERVER_ERROR)
      .json({ success: false, message: "註冊失敗" });
  }
};
```

#### 📁 建立資料夾 middlewares

> 內容：處理請求前後的中介邏輯，如身分驗證、資料驗證、錯誤處理等

```
middlewares
```

**用途說明**：

- **身分驗證**：檢查使用者是否登入、token 是否有效
- **權限控制**：檢查使用者是否有權限執行某操作
- **資料驗證**：驗證請求資料格式是否正確
- **錯誤處理**：統一處理錯誤回應格式

**常見檔案範例**：

- `auth.js`：身分驗證中介軟體（如 JWT 驗證）
- `validator.js`：資料驗證中介軟體
- `errorHandler.js`：錯誤處理中介軟體
- `upload.js`：檔案上傳處理中介軟體

**Middleware 範例**：

```js
import passport from "passport";
import { StatusCodes } from "http-status-codes";

// JWT 驗證中介軟體
export const auth = (req, res, next) => {
  passport.authenticate("jwt", { session: false }, (error, user, info) => {
    if (error || !user) {
      return res
        .status(StatusCodes.UNAUTHORIZED)
        .json({ success: false, message: "未登入" });
    }
    req.user = user;
    next();
  })(req, res, next);
};
```

#### 📁 建立資料夾 routers

> 內容：定義 API 路由規則，將請求分配給對應的 controller

```
routers
```

**用途說明**：

- 定義 API 端點路徑（如 `/api/users`, `/api/products`）
- 指定 HTTP 方法（GET, POST, PUT, DELETE）
- 串接 middlewares 與 controllers
- 組織與管理 API 結構

**常見檔案範例**：

- `userRouter.js`：使用者相關路由（註冊、登入、個人資料）
- `productRouter.js`：商品相關路由
- `orderRouter.js`：訂單相關路由

**Router 範例**：

```js
import { Router } from "express";
import { register, login, getProfile } from "../controllers/userController.js";
import { auth } from "../middlewares/auth.js";

const router = Router();

router.post("/register", register);
router.post("/login", login);
router.get("/profile", auth, getProfile); // 需要驗證身分

export default router;
```

**在 index.js 中使用**：

```js
import userRouter from "./routers/userRouter.js";
app.use("/api/users", userRouter);
```

#### 📝 建立檔案 index.js

檔名

```
index.js
```

> 內容：

```js
import "dotenv/config";
import express from "express";
import mongoose from "mongoose";
import { StatusCodes } from "http-status-codes";
import cors from "cors";

// routes（根據不同專案有不同的東西）
// import 路由名稱 from '路由檔案'

// passport.js
import "./passport.js";

// 連線資料庫 1.設環境變數 2.成功 3.失敗
mongoose
  .connect(process.env.DB_URL)
  .then(() => {
    console.log("☑️　資料庫連接成功");
    mongoose.set("sanitizeFilter", true);
  })
  .catch((err) => {
    console.log("⛔　資料庫連線失敗");
    console.error("資料庫連線失敗", err);
  });

// 建立 express 伺服器
const app = express();
app.use(express.json());

// 使用 CORS 中介軟體（處理跨域請求）
app.use(cors());

// ↓錯誤處理
app.use((err, req, res, _next) => {
  res.status(StatusCodes.BAD_REQUEST).json({
    sucess: false,
    message: "Json格式錯誤",
  });
});

// 設置路由（根據不同專案有不同的東西）
// app.use('/路由檔案', 路由名稱)

// 處理未定義的路由
app.all(/.*/, (req, res) => {
  res.status(StatusCodes.NOT_FOUND).json({
    success: false,
    message: "找不到該路由",
  });
});

// 監聽與啟動
app.listen(4000, () => {
  console.log("伺服器啟動");
});
```

### 📍 安裝開發用工具（語法檢查、自動重啟）

> 檢查語法是否符合規則（eslint / oslint / tslint…）
> 檔案變動時自動重啟伺服器（開發用）

```
npm init @eslint/config@latest
```

```
npm i -D nodemon prettier eslint-plugin-prettier eslint-config-prettier
```

#### 📝 eslint.config.js 內容

檔名

```
eslint.config.js
```

檔案內容

```
import js from '@eslint/js'
import globals from 'globals'
import { defineConfig } from 'eslint/config'
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'

export default defineConfig([
  {
    files: ['**/*.{js,mjs,cjs}'],
    plugins: { js },
    extends: ['js/recommended'],
  },
  { files: ['**/*.{js,mjs,cjs}'], languageOptions: { globals: globals.node } },
  eslintPluginPrettierRecommended,
  {
    rules: {
      'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
    },
  },
])
```

#### 📝 .prettierrc.json 內容

檔名

```
.prettierrc.json
```

檔案內容

```
{
  "$schema": "https://json.schemastore.org/prettierrc",
  "printWidth": 100,
  "semi": false,
  "singleQuote": true
}
```

> 補充：index.js 是進入點

---

## 2️⃣ 常駐工具型功能（必裝輔助開發用，不是主流程但超常出現）

> 📌 目的：提升錯誤處理與 API 品質，跨域通訊、欄位驗證也能幫忙

```
npm i cors http-status-codes validator
```

1. cors：讓前端能 call API（跨網域）
2. http-status-codes：不要手寫 404、200 之類的數字
3. validator：欄位驗證（ex: email、長度）

---

## 3️⃣ 明確功能型功能（安裝你需要用的功能套件，依需求增減）

> 📌 目的：實作帳號登入、密碼加密、token 機制、資料庫操作，依需求增減

資料庫：MongoDB

```
npm i mongoose
```

mongoose：操作 MongoDB

各種驗證

```
npm i bcrypt jsonwebtoken mongoose passport passport-local passport-jwt
```

1. bcrypt：密碼加密與比對
2. jsonwebtoken：產出 JWT token
3. passport：登入驗證框架
4. passport-local：帳號密碼策略
5. passport-jwt：JWT 身分驗證策略

## 4️⃣ (選用)使用 TypeScript

> 📌 目的:提升開發體驗、型別安全、減少執行時錯誤

### 📍 安裝 TypeScript 相關套件

```bash
npm install -D typescript @types/node @types/express ts-node
npm install -D @types/cors @types/bcrypt @types/jsonwebtoken @types/validator
npm install -D @types/passport @types/passport-local @types/passport-jwt
```

**套件說明**:

| 套件                    | 用途                             |
| ----------------------- | -------------------------------- |
| `typescript`            | TypeScript 編譯器                |
| `@types/node`           | Node.js 型別定義                 |
| `@types/express`        | Express 型別定義                 |
| `ts-node`               | 直接執行 TypeScript 檔案(開發用) |
| `@types/cors`           | CORS 套件型別定義                |
| `@types/bcrypt`         | bcrypt 套件型別定義              |
| `@types/jsonwebtoken`   | JWT 套件型別定義                 |
| `@types/validator`      | validator 套件型別定義           |
| `@types/passport`       | Passport 主套件型別定義          |
| `@types/passport-local` | Passport Local 策略型別定義      |
| `@types/passport-jwt`   | Passport JWT 策略型別定義        |

### 📝 建立 tsconfig.json

檔名:

```
tsconfig.json
```

內容:

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "node",
    "outDir": "./dist",
    "rootDir": "./",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "allowSyntheticDefaultImports": true,
    "types": ["node"]
  },
  "include": ["**/*.ts"],
  "exclude": ["node_modules", "dist"]
}
```

**設定說明**:

- `target`: 編譯後的 JavaScript 版本
- `module`: 模組系統(使用 ESNext 支援 ES Modules)
- `outDir`: 編譯後的檔案輸出資料夾
- `strict`: 啟用所有嚴格型別檢查
- `esModuleInterop`: 改善 CommonJS 與 ES Module 互通性

### 📝 調整 package.json

將 scripts 區塊修改為:

```json
{
  "type": "module",
  "scripts": {
    "dev": "nodemon --exec ts-node index.ts",
    "build": "tsc",
    "start": "node dist/index.js",
    "type-check": "tsc --noEmit"
  }
}
```

**指令說明**:

- `npm run dev`: 開發模式,使用 ts-node 直接執行 TypeScript
- `npm run build`: 編譯 TypeScript 為 JavaScript
- `npm start`: 執行編譯後的 JavaScript(正式環境)
- `npm run type-check`: 只檢查型別,不編譯

### 📝 調整 ESLint 設定

安裝 TypeScript ESLint 套件:

```bash
npm install -D typescript-eslint
```

修改 `eslint.config.js`:

```js
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import { defineConfig } from "eslint/config";

export default defineConfig(
  js.configs.recommended,
  tseslint.configs.recommended,
  {
    files: ["**/*.{js,mjs,cjs,ts}"],
    languageOptions: {
      globals: globals.node,
    },
  },
  {
    files: ["**/*.ts"],
    rules: {
      "no-unused-vars": "off",
      "@typescript-eslint/no-unused-vars": [
        "warn",
        { argsIgnorePattern: "^_" },
      ],
    },
  },
  eslintPluginPrettierRecommended
);
```

### 📁 檔案結構調整

將原本的 `.js` 檔案改為 `.ts`:

```
專案根目錄/
├── index.ts              (原 index.js)
├── passport.ts           (原 passport.js)
├── models/
│   └── user.ts          (原 user.js)
├── controllers/
│   └── userController.ts
├── middlewares/
│   └── auth.ts
├── routers/
│   └── userRouter.ts
└── dist/                (編譯後的輸出資料夾)
```

### 📝 TypeScript 範例:User Model

```ts
import { Schema, model, Document } from "mongoose";

// 定義介面
export interface IUser extends Document {
  account: string;
  email: string;
  password: string;
}

// 定義 Schema
const userSchema = new Schema<IUser>({
  account: { type: String, required: true, unique: true },
  email: { type: String, required: true },
  password: { type: String, required: true },
});

// 匯出模型
export default model<IUser>("users", userSchema);
```

### 📝 TypeScript 範例:Controller

```ts
import { Request, Response } from "express";
import User from "../models/user.js";
import { StatusCodes } from "http-status-codes";

export const register = async (req: Request, res: Response): Promise<void> => {
  try {
    await User.create(req.body);
    res.status(StatusCodes.OK).json({ success: true, message: "註冊成功" });
  } catch (error) {
    res
      .status(StatusCodes.INTERNAL_SERVER_ERROR)
      .json({ success: false, message: "註冊失敗" });
  }
};
```

### 📝 TypeScript 範例:index.ts

```ts
import "dotenv/config";
import express, { Request, Response, NextFunction } from "express";
import mongoose from "mongoose";
import { StatusCodes } from "http-status-codes";
import cors from "cors";

// routes
// import userRouter from './routers/userRouter.js'

// passport.js
import "./passport.js";

// 連線資料庫
mongoose
  .connect(process.env.DB_URL as string)
  .then(() => {
    console.log("☑️　資料庫連接成功");
    mongoose.set("sanitizeFilter", true);
  })
  .catch((err) => {
    console.log("⛔　資料庫連線失敗");
    console.error("資料庫連線失敗", err);
  });

// 建立 express 伺服器
const app = express();
app.use(express.json());

// 使用 CORS
app.use(cors());

// 錯誤處理
app.use((err: Error, req: Request, res: Response, _next: NextFunction) => {
  res.status(StatusCodes.BAD_REQUEST).json({
    success: false,
    message: "Json格式錯誤",
  });
});

// 設置路由
// app.use('/api/users', userRouter)

// 處理未定義的路由
app.all(/.*/, (req: Request, res: Response) => {
  res.status(StatusCodes.NOT_FOUND).json({
    success: false,
    message: "找不到該路由",
  });
});

// 監聽與啟動
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
  console.log(`伺服器啟動於 port ${PORT}`);
});
```

### ⚠️ 注意事項

1. **import 路徑需加 .js 副檔名**(即使是 TypeScript 檔案)

   ```ts
   import User from "../models/user.js"; // ✅ 正確
   import User from "../models/user"; // ❌ 可能出錯
   ```

2. **型別定義不完整時的處理**

   ```ts
   // 如果某個套件沒有 @types,可以建立 types/custom.d.ts
   declare module "some-package";
   ```

3. **環境變數型別安全**
   ```ts
   // 可以建立 types/env.d.ts
   declare global {
     namespace NodeJS {
       interface ProcessEnv {
         DB_URL: string;
         JWT_SECRET: string;
         PORT?: string;
       }
     }
   }
   export {};
   ```

### 🎯 TypeScript vs JavaScript 決策

| 情境                       | 建議          |
| -------------------------- | ------------- |
| 小型專案、快速開發         | JavaScript    |
| 多人協作、大型專案         | TypeScript ✅ |
| 需要高度型別安全           | TypeScript ✅ |
| 學習成本考量               | JavaScript    |
| 與前端 TypeScript 專案整合 | TypeScript ✅ |

---

# 🧩 後端套件分類表（含 `dependencies` 與 `devDependencies`）

| 套件名稱                     | 安裝位置 | 類型     | 用途說明            | 代表常見用途                 |
| ---------------------------- | -------- | -------- | ------------------- | ---------------------------- |
| `express`                    | ✅ 後端  | Web 框架 | 架設 API Server     | 處理請求與回應               |
| `dotenv`                     | ✅ 後端  | 設定工具 | 管理 `.env` 變數    | API 金鑰                     |
| `nodemon`                    | ✅ 後端  | 開發工具 | 變更自動重啟 server | 提升開發效率                 |
| `cors`                       | ✅ 後端  | 中介軟體 | 解決跨域問題        | 前後端分離                   |
| `body-parser`                | ✅ 後端  | 請求解析 | 拿到 req.body       | POST/PUT 資料                |
| `jsonwebtoken`               | ✅ 後端  | 驗證     | 處理 JWT 驗證       | 登入憑證                     |
| `bcryptjs` / `bcrypt`        | ✅ 後端  | 加密     | 密碼加密比對        | 登入系統                     |
| `mongoose` / `mysql2` / `pg` | ✅ 後端  | DB 驅動  | 資料庫連線操作      | MongoDB / MySQL / PostgreSQL |
| `multer`                     | ✅ 後端  | 檔案處理 | 處理檔案上傳        | 上傳圖片                     |

## 📁 一、建立環境款（系統框架與開發支援）

| 套件名                                              | 用途說明                                               | 適合場景                            |
| --------------------------------------------------- | ------------------------------------------------------ | ----------------------------------- |
| `express`                                           | 建立 HTTP 伺服器與路由管理，是整個後端的基礎           | 所有 Express 專案必備               |
| `dotenv`                                            | 讀取 `.env` 檔案設定環境變數                           | 區分開發、正式環境設定（如 DB URI） |
| `nodemon`                                           | 檔案變動時自動重啟伺服器（開發用）                     | 提高開發效率，不需手動重啟          |
| `eslint` / `@eslint/js`                             | 程式碼風格檢查器（靜態分析）                           | 寫 code 時維持一致風格              |
| `eslint-config-prettier` / `eslint-plugin-prettier` | 整合 Prettier 與 ESLint，避免衝突                      | 同時使用兩者時很常用                |
| `globals`                                           | 提供 ESLint 可辨識的全域變數（如 `window`, `process`） | 靜態檢查時避免誤報錯誤              |

---

## 🛠️ 二、常駐工具型功能款（幾乎每個專案會加的功能輔助）

| 套件名              | 用途說明                                   | 適合場景               |
| ------------------- | ------------------------------------------ | ---------------------- |
| `cors`              | 處理跨來源請求，允許前端與後端不同來源通訊 | 前後端分離開發中必裝   |
| `http-status-codes` | 提供標準 HTTP 狀態碼常數，避免寫死數字     | 統一錯誤回應格式       |
| `validator`         | 驗證 email、網址、字串格式等（輕量、常用） | 表單驗證、後端欄位檢查 |

---

## 🎯 三、明確功能型功能款（為了特定需求裝的）

| 套件名           | 用途說明                            | 適合場景                      |
| ---------------- | ----------------------------------- | ----------------------------- |
| `bcrypt`         | 加密密碼、驗證密碼                  | 帳號登入系統、保護使用者資料  |
| `jsonwebtoken`   | 產生與驗證 JWT（token 機制）        | 登入後產出 token、驗證使用者  |
| `mongoose`       | 操作 MongoDB 的 ODM（資料模型管理） | 資料庫存取、欄位定義與驗證    |
| `passport`       | 使用者驗證中介系統                  | 處理登入、登出、身分驗證      |
| `passport-local` | `passport` 的本地帳密登入策略       | 基本帳號密碼登入              |
| `passport-jwt`   | `passport` 的 JWT 驗證策略          | 支援使用 JWT token 登入持久化 |

---

# 👀 無用的知識增加了

## 各種驗證套件差別

### ✅ 一、**前端送表單前要檢查資料對不對**

> ➤ 負責人：`validator`

🧪 格式錯誤例子：

- Email 不合法
- 密碼太短
- 名稱為空

```js
validator.isEmail(email); // ✅ or ❌
```

### ✅ 二、**登入時要比對使用者密碼**

> ➤ 負責人：`bcrypt`

🔐 一進資料庫前就加密，登入時也用它來比對：

```js
bcrypt.compare(使用者輸入的密碼, 資料庫的加密密碼);
```

### ✅ 三、**登入成功後，要頒發「通關憑證」**

> ➤ 負責人：`jsonwebtoken`

🎫 就像辦完護照拿到簽證，使用者登入成功後，產生一張 **JWT token**。

```js
const token = jwt.sign(payload, secretKey, { expiresIn: "1h" });
```

### ✅ 四、**之後每次請求，要驗證使用者憑證是否合法**

> ➤ 負責人：`passport` + `passport-jwt`

🕵️ 守門系統來了，這邊會攔截請求，看 token 是否正確（如：有沒有過期？有沒有被竄改？）

```js
passport.use(new JwtStrategy(...))
```

### ✅ 五、**第一次登入的帳號密碼邏輯**

> ➤ 負責人：`passport-local`

👮 檢查帳號密碼正確性（第一次登入用的驗證策略）

```js
passport.use(new LocalStrategy(帳號密碼檢查邏輯));
```

---

### 📌 小整理圖：

```
🔎 表單送出前 —— validator
🔐 密碼上路前 —— bcrypt（加密儲存）
✅ 登入成功時 —— jsonwebtoken（產出 token）
🧠 架構整合者 —— passport
　└─ passport-local：帳密比對邏輯（登入那刻）
　└─ passport-jwt：驗證 JWT token（後續請求）
```

---

### 總整理

| 套件                   | 分類           | 簡單比喻             | 驗證什麼？                 |
| ---------------------- | -------------- | -------------------- | -------------------------- |
| `validator`            | 格式驗證       | 格式小警察           | email 格式、必填欄位、長度 |
| `bcrypt`               | 加密驗證       | 把密碼攪爛後存起來   | 使用者輸入密碼對不對       |
| `jsonwebtoken` (`jwt`) | 身分憑證       | 成功登入後發的票     | JWT 有效嗎？是誰？         |
| `passport`             | 驗證系統架構   | 驗證流程主控中心     | 調度各種驗證方式           |
| `passport-local`       | 登入策略       | 傳統帳號密碼比對方式 | 使用者帳號密碼是否正確     |
| `passport-jwt`         | token 驗證策略 | 持票者是否合法       | JWT 是否有效、是否過期     |

## validator 為什麼是常駐工具？

### 🧪 validator 屬於「常駐工具型功能」的理由

✅ 1. 它不是為了某個功能而來，而是「幫你寫任何功能時更安全」
你寫會員系統會用 validator（驗證 email）
你寫商品系統也會用（名稱長度限制）
寫留言表單、報名表單、客服系統……都用得到

> 它的角色是「資料的守門員」，而不是「功能的實作者」

### ✅ 2. 範圍極廣，不只登入／註冊才用

不像：
passport = 為了登入驗證設計
bcrypt = 為了密碼比對設計
jwt = 為了登入產出 token
這三個是為了「身份驗證」這一個功能而存在，沒做登入就用不到。
但 validator 像是萬用刀：
是你送出任何資料給後端時，都要有人檢查格式
它不是功能，是習慣

### ✅ 3. 你可能根本不做登入，也會用它

例如你只做一個「留言板」，完全匿名：
不需要 passport、bcrypt、jwt
但還是會用 validator → 限制留言內容字數、email 格式、避免空值

| 工具                          | 是否功能導向？            | 是否常駐？              | 分類              |
| ----------------------------- | ------------------------- | ----------------------- | ----------------- |
| `passport` / `bcrypt` / `jwt` | ✅ 明確是為了登入、權限   | ❌ 沒做就不會用         | 🎯 明確功能型功能 |
| `validator`                   | ❌ 不是某個功能的專屬工具 | ✅ 幾乎什麼功能都能用上 | 🛠 常駐工具型功能  |

---

## 📦 比較各種資料庫對應的套件選擇（給 Node.js 用）

不同資料庫有不同的 Node.js 連接方式與套件選擇。

### 1️⃣ MongoDB

- ✅ 套件：`mongoose`（ODM）
- 功能：提供資料模型、驗證、自動轉換格式等功能
- 📦 替代選項：`mongodb`（原生驅動）→ 比較底層、自由度高但需自己寫邏輯

```
npm i mongoose
```

### 2️⃣ MySQL / MariaDB（關聯式資料庫）

#### 👉 常見套件：

| 套件        | 類型        | 說明                                             |
| ----------- | ----------- | ------------------------------------------------ |
| `mysql2`    | 原生 client | 操作資料庫的最基本工具，查詢語法需自己寫         |
| `sequelize` | ORM         | 幫你抽象成「模型」，支援關聯、驗證、migration 等 |

🔧 安裝範例：

```
npm i mysql2 sequelize
```

📘 建議搭配：

- `dotenv`：放 DB 帳密
- `sequelize-cli`（選用）：管理 migration、seed 資料

### 3️⃣ PostgreSQL（關聯式，功能強大）

#### 👉 常見套件：

| 套件        | 類型        | 說明                                                  |
| ----------- | ----------- | ----------------------------------------------------- |
| `pg`        | 原生 client | 輕量、穩定、官方推薦                                  |
| `sequelize` | ORM         | 也支援 PostgreSQL（多資料庫通用）                     |
| `prisma`    | ORM         | 現代化 ORM，更嚴謹、支援 type 安全（TypeScript 友善） |

🔧 安裝範例：

```
npm install pg sequelize
```

或

```
npm install prisma @prisma/client
```

### 4️⃣ SQLite（輕量型，適合測試用）

- 套件：`sqlite3` 或 `better-sqlite3`
- ORM：同樣可以搭配 `sequelize` 或 `prisma`

🔧 安裝範例：

```
npm install sqlite3 sequelize
```

### 5️⃣ 其他（非傳統資料庫）

#### 🧰 Google Sheet × Node.js 的資料存取方式

🎯 **Google Sheet** 的使用邏輯比較不一樣：它不是傳統的資料庫，但可以當作**簡易資料儲存後台**。如果你想在 Node.js 中把 Google Sheet 當作資料來源或儲存工具，這邊有一套常見工具和方式可以用：

✅ 常見用途：

- 表單送出資料 → 存到 Google Sheet
- 後台設定資料 → 存在 Google Sheet 當成資料庫用
- 顯示表格資訊（例如後台管理員表、產品庫存表）

#### 📦 套件選擇與安裝

✅ 最主流方式：使用 Google 官方 API 套件

```
npm i googleapis
```

📁 會用到的東西：

| 工具         | 用途說明                                            |
| ------------ | --------------------------------------------------- |
| `googleapis` | 官方 SDK，支援 Sheets API（也支援 Drive、Gmail 等） |
| `dotenv`     | 儲存你的憑證與 Google Sheet ID                      |

#### 🗂️ Google Sheet 串接概念流程

1. **在 Google Cloud Platform 建立專案**
2. **啟用 Google Sheets API**
3. **建立服務帳號並下載 JSON 憑證**
4. **與你的 Sheet 分享編輯權給那個服務帳號的 email**
5. **在 Node.js 中使用 `googleapis` 將憑證讀進來、連接 Sheet**
6. **讀取 / 寫入資料**

#### ✅ 套件與初始化步驟懶人表

| 類別       | 套件         | 安裝指令                 |
| ---------- | ------------ | ------------------------ |
| 建立環境   | `dotenv`     | `npm install dotenv`     |
| 功能型功能 | `googleapis` | `npm install googleapis` |

📦 如果你不想處理複雜的授權流程，也可以用 Google 提供的「App Script + Webhook」或用第三方平台如 [SheetDB](https://sheetdb.io/)、[Sheet.best](https://sheet.best/) 這類工具，但彈性較低。

#### 🎯 使用情境與限制提醒

| 優點                           | 限制                                 |
| ------------------------------ | ------------------------------------ |
| 免費、上手快、適合簡單資料儲存 | 不適合大量資料操作（有限 API 限速）  |
| 資料可視化、多人共編方便       | 欄位與資料架構不夠嚴謹（不像資料庫） |
| 不用架設 DB 就能快速測試       | 權限管理複雜、容易洩漏憑證           |

#### 🚀 決策建議

| 想要這樣用…                    | 推薦方案                                  |
| ------------------------------ | ----------------------------------------- |
| 當成後台可視資料庫（小型系統） | ✅ Google Sheet + `googleapis`            |
| 當成表單資料收集庫             | ✅ Google Form + AppScript / `googleapis` |
| 如果日後有複雜關聯查詢         | ❌ 建議改用 MongoDB / MySQL 等真資料庫    |

### 🎯 資料庫懶人決策建議

| 資料庫          | 套件選擇                          | 建議用途                             |
| --------------- | --------------------------------- | ------------------------------------ |
| MongoDB         | `mongoose`                        | 文件型資料，彈性高，NoSQL 專案首選   |
| MySQL / MariaDB | `mysql2` + `sequelize`            | 有資料表設計（欄位明確、關聯明確）   |
| PostgreSQL      | `pg` + `prisma`（或 `sequelize`） | 關聯型但要更強功能，支援 JSON 欄位等 |
| SQLite          | `sqlite3` + `sequelize`           | 測試開發、本機 demo 用               |
