iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
Vibe Coding

Vibe Mode 開啟:30 天用 AI 打造網頁,邊做邊學 JavaScript系列 第 6

# Day 6: Vibe Mode 開啟:資料庫設計 —— 用 AI 規劃 ERD、生成 SQL Migration 與 Drizzle Schema

  • 分享至 

  • xImage
  •  

本日目標

到了階段二,我們正式進入後端與資料層(Data Layer)的建立!
今天我們要為專案打造穩固的資料庫基石。我們將引導 AI 分析我們的產品需求,產出 ERD (實體關係圖) 概念,並自動生成 SQL Migration 腳本與現代 Node.js 絕佳搭配的 Drizzle ORM Schema


JavaScript / DB 觀念補給站

在叫 AI 幫我們寫程式碼之前,先釐清兩個關鍵概念:

  1. ORM (Object-Relational Mapping):讓你在 JavaScript 中可以使用物件 (Object) 與方法 (Method) 來操作資料庫,而不必手寫複雜的 SQL 語句。
  2. Migration (資料庫遷移):就像資料庫的版本控制(Git),記錄資料庫結構(Schema)的每一次變更,方便團隊協作與正式環境部署。

Human vs. AI 實戰對決

1. 給 AI 的指令 (Prompt)

我們打開 IDE(如 Cursor / VS Code),在包含 .cursorrules 的環境下輸入以下 Prompt:

我們正在開發「AI 個人財務追蹤器」,請幫我設計 PostgreSQL 資料庫結構。

【需求】
1. 使用者 (Users) 系統
2. 交易記錄 (Transactions):包含金額、類型(收入/支出)、類別、日期、備註
3. AI 財務建議記錄 (AITips):記錄 AI 針對使用者財務狀況產生的分析建議

【產出要求】
- 先用 Mermaid 語法繪製 ERD 關係圖
- 使用 Drizzle ORM 語法定義 TypeScript Schema (包含 Primary Key, Foreign Key, Enum, CreatedAt)

2. AI 產出的結果 (AI Output)

AI 很快地生成了 Mermaid ERD 圖與以下 Drizzle Schema:
// schema.ts (AI 初次生成版本)
import { pgTable, text, timestamp, uuid, numeric, pgEnum } from 'drizzle-orm/pg-core';

export const transactionTypeEnum = pgEnum('transaction_type', ['INCOME', 'EXPENSE']);

export const users = pgTable('users', {
  id: uuid('id').primaryKey().defaultRandom(),
  email: text('email').notNull().unique(),
  name: text('name'),
  createdAt: timestamp('created_at').defaultNow(),
});

export const transactions = pgTable('transactions', {
  id: uuid('id').primaryKey().defaultRandom(),
  userId: uuid('user_id').references(() => users.id),
  amount: numeric('amount').notNull(),
  type: transactionTypeEnum('type').notNull(),
  category: text('category').notNull(),
  createdAt: timestamp('created_at').defaultNow(),
});

export const aiTips = pgTable('ai_tips', {
  id: uuid('id').primaryKey().defaultRandom(),
  userId: uuid('user_id').references(() => users.id),
  content: text('content').notNull(),
});

3. 我做出的修正與翻車記錄 (Debug & Human Intervention)

看似很完美,但我仔細檢查後發現了 兩個潛在的坑 (Technical Debt & Bugs)

🚨 翻車點 1:外鍵缺乏刪除策略 (Cascade Delete)

  • 問題userId: uuid('user_id').references(() => users.id) 沒有設定 onDelete: 'cascade'。如果未來刪除使用者,資料庫會因為外鍵約束跳錯而無法刪除,或者殘留孤立的交易紀錄。
  • JavaScript / SQL 觀念:資料關聯必須思考生命週期,使用者沒了,其底下的交易與 AI 建議也應該一併清除。

🚨 翻車點 2:Numeric 型別在 JS 中的型別轉換問題

  • 問題:Drizzle 的 numeric('amount') 在 JavaScript/TypeScript 中預設會被映射為 string(為了避免 JS 浮點數精度不準的問題)。但後端做計算時,如果不注意直接拿來做加減,會變成字串串接 (例如 '100' + '50' = '10050')!

引導 AI 修正 (The Refined Prompt)

我針對問題給出第二輪修正指令:

請修正上面的 Drizzle Schema:
1. 為所有 foreign key 加上 `onDelete: 'cascade'`。
2. 在 transactions 表中加上 `date` 欄位(預設為當前時間)。
3. 導出 Drizzle Migration 腳本指令,並提醒我 numeric 型別在 JavaScript 中運算時的注意事項。

修正完產出結果

// schema.ts (最終優化版)
import { pgTable, text, timestamp, uuid, numeric, pgEnum } from 'drizzle-orm/pg-core';

export const transactionTypeEnum = pgEnum('transaction_type', ['INCOME', 'EXPENSE']);

export const users = pgTable('users', {
  id: uuid('id').primaryKey().defaultRandom(),
  email: text('email').notNull().unique(),
  name: text('name'),
  createdAt: timestamp('created_at').defaultNow().notNull(),
});

export const transactions = pgTable('transactions', {
  id: uuid('id').primaryKey().defaultRandom(),
  userId: uuid('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
  amount: numeric('amount', { precision: 12, scale: 2 }).notNull(),
  type: transactionTypeEnum('type').notNull(),
  category: text('category').notNull(),
  date: timestamp('date').defaultNow().notNull(),
  createdAt: timestamp('created_at').defaultNow().notNull(),
});

export const aiTips = pgTable('ai_tips', {
  id: uuid('id').primaryKey().defaultRandom(),
  userId: uuid('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
  content: text('content').notNull(),
  createdAt: timestamp('created_at').defaultNow().notNull(),
});

接著執行 Drizzle Kit 生成並推送 Migration:

npx drizzle-kit generate
npx drizzle-kit push

心得

將精力從「手寫語法」轉移到「架構審查與業務邏輯驗證」!

今日雖然有讓 AI生出 80% 的資料庫結構,但身為開發者,我們必須發揮人類工程師的價值:檢查邊界條件、維護資料完整性 (Integrity),以及預防 JavaScript 轉型(Type Coercion)的潛在漏洞!


上一篇
Day 5:Context 的藝術:建立專案 .clinerules / .cursorrules,讓 AI 聽懂專案規範
下一篇
# Day 7 : Vibe Mode 開啟:打造 RESTful API —— 讓 AI 撰寫 Controller 與 Service 邏輯
系列文
Vibe Mode 開啟:30 天用 AI 打造網頁,邊做邊學 JavaScript9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言