---
# System prepended metadata

title: 軟體設計文件(SDD)

---

---

title: 軟體設計文件(SDD)

---

# 軟體設計文件(SDD)


## 專案資訊
- **專案名稱**：早一點
- **撰寫日期**：2025/11/24
- **發展者**：
01157128 蔡翊宣
01257116 康慈軒
01257126 呂亭儀
01257153 鄭尹宣
01257161 李永聖

---

## 版次變更記錄

| 版次 | 變更項目 | 變更日期 |
|------|----------|----------|
| 0.1  |初版          |2025/11/24|
| 0.2  |使用者畫面設計  |2025/11/25|
| 0.3  |新增C4 Model圖|2025/12/23|
| 1.0  |最終版        |2026/01/03|



---

## 目錄
1. [系統模型與架構 (System Model / System Architecture)](#section1)  
2. [介面需求與設計 (Interface Requirement and Design)](#section2)  
3. [流程設計 (Process Design)](#section3)  
4. [使用者畫面設計 (User Interface Design)](#section4)  
5. [資料設計 (Data Design)](#section5)  
6. [類別圖設計 (Class Diagram)](#section6)  
7. [實作方案 (Implementation Languages and Platforms)](#section7)  
8. [設計議題 (Design Issue)](#section8)

---

## <span id="section1">1. 系統模型與架構 (System Model / System Architecture)</span>
![image](https://hackmd.io/_uploads/B1BcPzfW-e.png)
![image](https://hackmd.io/_uploads/Hy4HKMf-be.png)
![image](https://hackmd.io/_uploads/H1v_KNumbl.png)




---

## <span id="section2">2. 介面需求與設計 (Interface Requirement and Design)</span>

- Store

| 介面名稱 | 介面提供者 | 介面使用者 | 連結方式 | 輸入資料 | 輸出資料 | 介面描述 |
|---------|------------|------------|----------|----------|----------|-----------|
| 創建新店家 | Backend - StoreController | Frontend - StoreSettingView | HTTP POST /api/stores | Header (Authorization), JSON (Store 物件) | JSON (Store 物件) | 驗證使用者 Token，將新的店家資訊寫入資料庫，並將當前使用者設為擁有者 Owner。 |
| 獲取所有店家 | Backend - StoreController | Frontend - StoreListView | HTTP GET /api/stores | 無 | JSON (List<Store>) | 從資料庫中檢索並回傳所有已註冊且狀態為 Active 的店家列表。 |
| 獲取店家詳情 | Backend - StoreController | Frontend - StoreDetailView | HTTP GET /api/stores/{storeId} | Path (storeId) | JSON (Store 物件) | 根據提供的 Store ID 查詢並回傳該店家的詳細資訊（包含菜單）。 |
| 更新店家菜單 | Backend - StoreController | Frontend - StoreManagementView | HTTP PUT /api/stores/{id}/menu | Path (id), Header (Authorization), JSON (List<MenuItem>) | JSON (Store 物件) 或 錯誤訊息 | 驗證店家擁有者權限，更新指定店家的菜單項目（若項目無 ID 則自動產生 ObjectId）。 |
| 搜尋店內商品 | Backend - StoreController | Frontend - StoreDetailView | HTTP GET /api/stores/{storeId}/search-product | Path (storeId), Query Param (keyword) | JSON (List<MenuItem>) | 在特定店家根據關鍵字搜尋菜單項目，回傳名稱包含關鍵字的商品列表。 |

---

- User

| 介面名稱  | 介面提供者 | 介面使用者 | 連結方式 | 輸入資料 | 輸出資料 | 介面描述| 
| ------- | -------- | --------- | ---- | ----- | ---- | ----- |
| 使用者註冊 | Backend - UserController | Frontend - RegisterView | HTTP POST | JSON (account, password, role, email) | JSON (User 物件) | 接收使用者資訊，檢查帳號是否重複，若無重複就寫入資料庫 |
| 使用者登入 | Backend - UserController | Frontend - LoginView | HTTP POST | JSON (account, password) | JSON (User 物件) | 接收使用者帳號密碼，若與資料庫資料相同就登入 |
| 回傳使用者資訊 | Backend - UserController | Frontend - HomeView | HTTP GET | URL Path Variable: userId | JSON (User 物件) | 根據網址中的 userId 回傳該使用者的資訊 |
| 修改使用者資訊 | Backend - UserController | Frontend - HomeView | HTTP PATCH | URL Path Variable: userId + JSON(password, nickname, photo, phone, email) | JSON (User 物件) | 根據網址中的 userId 和 傳入的 JSON 資料來修改該使用者資訊 |
| 刪除使用者 | Backend - UserController | Frontend - HomeView | HTTP DELETE | URL Path Variable: userId | String(使用者 ID: userId 已成功刪除) | 根據網址中的 userId 來刪除該使用者 |
| 將店家加入收藏 | Backend - UserController | Frontend - ShopView or FavoriteView | HTTP POST | URL Path Variable: userId, storeId | JSON (User 物件) | 根據網址中的 userId 和 storeId ，將店家加入該使用者的收藏 |
| 將店家移除收藏 | Backend - UserController | Frontend - ShopView or FavoriteView | HTTP DELETE | URL Path Variable: userId, storeId | JSON (User 物件) | 根據網址中的 userId 和 storeId ，將店家移除該使用者的收藏 |
| 回傳收藏店家列表 | Backend - UserController | Frontend - FavoriteView | HTTP GET | URL Path Variable: userId | JSON (List<String\>) | 根據網址中的 userId ，回傳該使用者的收藏店家之 storeId |
| 將商品加入收藏 | Backend - UserController | Frontend - ShopView or FavoriteView | HTTP POST | URL Path Variable: userId, storeId, itemId | JSON (User 物件) | 根據網址中的 userId 、 storeId 和 itemId ，將商品加入該使用者的收藏 |
| 將商品移除收藏 | Backend - UserController | Frontend - ShopView or FavoriteView | HTTP DELETE | URL Path Variable: userId, storeId, itemId | JSON (User 物件) | 根據網址中的 userId 、 storeId 和 itemId ，將商品移除該使用者的收藏 |
| 回傳收藏商品列表 | Backend - UserController | Frontend - ShopView or FavoriteView | HTTP GET | URL Path Variable: userId, storeId, itemId | JSON (List<FavorItem 物件>) | 根據網址中的 userId ，回傳該使用者的收藏商品（FavorItem 物件） |
| 新增自訂義組合 | Backend - UserController | Frontend - ShopView or FavoriteView | HTTP POST | URL Path Variable: userId + JSON(comboName) | JSON (User 物件) | 根據網址中的 userId ，為該使用者的新增名稱為 comboName 的自訂義組合（內容為空） |
| 修改自訂義組合名稱 | Backend - UserController | Frontend - ShopView or FavoriteView | HTTP PATCH | URL Path Variable: userId, comboId + JSON(comboName) | JSON (User 物件) | 根據網址中的 userId ，為該使用者修改 ID 為 comboId 的自訂義組合名稱，修改為 comboName |
| 刪除自訂義組合 | Backend - UserController | Frontend - ShopView or FavoriteView | HTTP DELETE | URL Path Variable: userId, comboId | JSON (User 物件) | 根據網址中的 userId ，為該使用者刪除 ID 為 comboId 的自訂義組合 |
| 將商品加入自訂義組合 | Backend - UserController | Frontend - ShopView or FavoriteView | HTTP POST | URL Path Variable: userId, comboId, storeId, itemId | JSON (User 物件) | 根據網址中的 userId ，為該使用者將商品加入 ID 為 comboId 的自訂義組合（同一個自訂義組合內的商品不能跨店家） |
| 將商品移除自訂義組合 | Backend - UserController | Frontend - ShopView or FavoriteView | HTTP DELETE | URL Path Variable: userId, comboId, storeId, itemId | JSON (User 物件) | 根據網址中的 userId ，為該使用者將商品移除 ID 為 comboId 的自訂義組合 |
| 回傳自訂義組合列表 | Backend - UserController | Frontend - ShopView or FavoriteView | HTTP GET | URL Path Variable: userId | JSON (List<CustomCombo 物件>) | 根據網址中的 userId ，回傳該使用者的自訂義組合列表 |
| 回傳特定自訂義組合內容 | Backend - UserController | Frontend - ShopView or FavoriteView | HTTP GET | URL Path Variable: userId, comboId | JSON (CustomCombo 物件) | 根據網址中的 userId 和 comboId ，回傳該使用者的 ID 為 comboId 的自訂義組合內容 |
    
---
    
- Cart

| 介面名稱  | 介面提供者 | 介面使用者 | 連結方式 | 輸入資料 | 輸出資料 | 介面描述| 
| ------- | -------- | --------- | ---- | ----- | ---- | ----- |
| 取得購物車內容 | Backend - CartController | Frontend - CartView, ShopView | HTTP GET | URL Path Variable: userId | JSON (Cart 物件) | 根據 User ID 取得該使用者的購物車內容，包含店家 ID、商品列表與總金額。若無購物車則回傳空車 |
| 加入商品至購物車 | Backend - CartController | Frontend - CartView, ShopView | HTTP POST | URL Path Variable: userId + JSON (CartItem 物件) + Request Param: storeId | JSON (Cart 物件) | 將商品加入購物車。若車內已有不同店家的商品，則回傳錯誤（禁止跨店點餐），若商品已存在則增加數量 |
| 移除購物車商品 | Backend - CartController | Frontend - CartView, ShopView | HTTP DELETE | URL Path Variable: userId, itemId | JSON (Cart 物件) | 根據 Item ID 將特定商品從購物車中移除，並重新計算總金額。若購物車清空，則重置店家鎖定 |
| 清空購物車 | Backend - CartController | Frontend - CartView, ShopView | HTTP DELETE | URL Path Variable: userId | String(使用者 ID 為：userId的購物車已清空) | 移除購物車內所有商品，並重置 storeId 為 null |

---

- Order

| 介面名稱  | 介面提供者 | 介面使用者 | 連結方式 | 輸入資料 | 輸出資料 | 介面描述| 
| ------- | -------- | --------- | ---- | ----- | ---- | ----- |
| 建立新訂單 | Backend - OrderController | Frontend - CheckoutView | HTTP POST | JSON (storeId, customerId, items, totalAmount, orderType, dineInDetail/takeoutDetail, paymentMethod) | JSON (Order 物件) | 接收前端傳來的訂單詳細資訊，將資料寫入 MongoDB 資料庫，並回傳包含自動生成 `_id` 與 `createAt` 的完整訂單物件。 |
| 查詢顧客歷史訂單 | Backend - OrderController | Frontend - OrderHistoryView | HTTP GET | URL Path Variable: customerId | JSON (List<Order>) | 根據網址中的 `customerId`，回傳該名顧客過去所有的訂單列表（通常按時間倒序排列）。 |
| 查詢單筆訂單詳情 | Backend - OrderController | Frontend - OrderDetailView | HTTP GET | URL Path Variable: orderId | JSON (Order 物件) | 根據網址中的 `orderId`，回傳該筆訂單的完整資訊（包含訂單項目、金額、狀態等）。 |
| 查詢店家所有訂單 | Backend - OrderController | Frontend - MerchantOrderView | HTTP GET | URL Path Variable: storeId | JSON (List<Order>) | 根據網址中的 `storeId`，回傳該店家收到的所有訂單列表。 |
| 更新訂單狀態 | Backend - OrderController | Frontend - MerchantOrderView | HTTP PATCH | URL Path Variable: orderId + JSON (state) | JSON (Order 物件) | 商家操作接單或完成餐點時呼叫。接收新的狀態字串（如 '已接單', '已完成'），更新資料庫並回傳更新後的訂單。 |
| 取消訂單 | Backend - OrderController | Frontend - OrderHistoryView | HTTP PATCH | URL Path Variable: orderId | JSON (Order 物件) | 顧客或商家取消訂單。後端需驗證訂單狀態是否允許取消（例如：只有 '已送出' 狀態可取消），將狀態更新為 '已取消'。 |
---


## <span id="section3">3. 流程設計 (Process Design)</span>
<!-- <span style="color:red">可用 UML 之 Activity diagram / State Transition diagram 或一般的程式流程圖描述所開發的系統流程，目的是運用流程圖或狀態圖設計整個系統的完整運作。 此部分應是操作概念的細部設計。</span>
（於此處插入主要流程之 Activity diagram、State diagram 或流程圖） -->

### 3.1 Store
- 首頁顯示流程
![截圖 2025-11-25 晚上11.45.24](https://hackmd.io/_uploads/rkHQy8Q-bx.png)

- 查看商家流程
![截圖 2025-11-26 凌晨12.40.21](https://hackmd.io/_uploads/rJBb3LmZbl.png)	

- 商家建立與設定流程
![截圖 2025-11-26 凌晨12.10.25](https://hackmd.io/_uploads/H1y-SLX-be.png)

- 商家的菜單管理流程
![截圖 2025-11-26 凌晨12.27.02](https://hackmd.io/_uploads/rJvJKL7b-e.png)

### 3.2 User
- 註冊
![image](https://hackmd.io/_uploads/ByKB1D7bWx.png)
    
- 登入
![image](https://hackmd.io/_uploads/Bkt1bPQbbg.png)
    
- 加入收藏
![image](https://hackmd.io/_uploads/S1TR1PXbWe.png)
    
### 3.3 Cart
- 查詢購物車
![image](https://hackmd.io/_uploads/H1FhSD7-Ze.png)

- 加入購物車
![image](https://hackmd.io/_uploads/By06Sv7Wbx.png)

- 移除購物車
![image](https://hackmd.io/_uploads/B1b18v7Zbg.png)


### 3.4 Order
- 建立訂單流程圖
![image](https://hackmd.io/_uploads/B1lvvImbbe.png)



---

## <span id="section4">4. 使用者畫面設計 (User Interface Design)</span>
    1.登入頁面
![image](https://hackmd.io/_uploads/B19ygHQbZg.png)
    2.註冊頁面
![image](https://hackmd.io/_uploads/B1TgeBmb-e.png)
    3.顧客主頁面
![image](https://hackmd.io/_uploads/H1_Xgr7WWx.png)
    4.使用者資訊
![image](https://hackmd.io/_uploads/S1grlS7W-e.png)
    5.商家頁面
![image](https://hackmd.io/_uploads/rJVIxB7Z-e.png)
    6.商品頁面
![image](https://hackmd.io/_uploads/r1LDgH7b-x.png)
    7.購物車頁面
![image](https://hackmd.io/_uploads/BJbtxHQbbl.png)
    8.訂單管理頁面
![image](https://hackmd.io/_uploads/Bk8MS7fZbx.png)
    9.收藏頁面
![image](https://hackmd.io/_uploads/ryNieBQZbg.png)
    10.商家設定頁面
![image](https://hackmd.io/_uploads/Skp16zMbZe.png)





---

## <span id="section5">5. 資料設計 (Data Design)</span>

### 5.1 資料庫 Schema
<table style="width: 100%; border-collapse: collapse;">
    <tr style="background-color: #4472C4; color: white; text-align: center; font-weight: bold;">
        <td colspan="2" style="border: 1px solid black; padding: 8px;">名稱</td>
        <td colspan="2" style="border: 1px solid black; padding: 8px;">描述</td>
    </tr>
    <tr style="text-align: center;">
        <td colspan="2" style="border: 1px solid black; padding: 8px;">store</td>
        <td colspan="2" style="border: 1px solid black; padding: 8px;">店家的設定（包括菜單、資訊等）</td>
    </tr>
    <tr style="background-color: #4472C4; color: white; text-align: center; font-weight: bold;">
        <td style="border: 1px solid black; padding: 8px; width: 20%;">屬性描述</td>
        <td style="border: 1px solid black; padding: 8px; width: 20%;">屬性名稱</td>
        <td style="border: 1px solid black; padding: 8px; width: 20%;">屬性型態</td>
        <td style="border: 1px solid black; padding: 8px; width: 40%;">屬性設定</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">店家 ID</td>
        <td style="border: 1px solid black; padding: 8px;">_id</td>
        <td style="border: 1px solid black; padding: 8px;">ObjectId</td>
        <td style="border: 1px solid black; padding: 8px;">required: true, PK<br>unique: true</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">店家名稱</td>
        <td style="border: 1px solid black; padding: 8px;">name</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">required: true</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">店家分類</td>
        <td style="border: 1px solid black; padding: 8px;">category</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">required: true</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">店家簡介</td>
        <td style="border: 1px solid black; padding: 8px;">description</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">default: ""</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">擁有者 ID</td>
        <td style="border: 1px solid black; padding: 8px;">ownerId</td>
        <td style="border: 1px solid black; padding: 8px;">ObjectId</td>
        <td style="border: 1px solid black; padding: 8px;">required: true</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">聯絡電話</td>
        <td style="border: 1px solid black; padding: 8px;">phone</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">default: ""</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">聯絡信箱</td>
        <td style="border: 1px solid black; padding: 8px;">email</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">default: ""</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">店家地址</td>
        <td style="border: 1px solid black; padding: 8px;">address</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">required: true</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">經緯度座標</td>
        <td style="border: 1px solid black; padding: 8px;">coordinates</td>
        <td style="border: 1px solid black; padding: 8px;">Array<Number></td>
        <td style="border: 1px solid black; padding: 8px;">required: true（格式：[經度, 緯度]）</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">營業時間</td>
        <td style="border: 1px solid black; padding: 8px;">businessHours</td>
        <td style="border: 1px solid black; padding: 8px;">{
                                                              day: String,
                                                              start: String,
                                                              close: String,
                                                              note: String
                                                            }[]
</td>
        <td style="border: 1px solid black; padding: 8px;">default: []</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">菜單</td>
        <td style="border: 1px solid black; padding: 8px;">menu</td>
        <td style="border: 1px solid black; padding: 8px;">{
                                                              _id: ObjectId,
                                                              itemName: String,
                                                              category: String,
                                                              price: Number,
                                                              description: String,
                                                              imgUrl: String,
                                                              isAvailable: Boolean,
                                                              tag: String
                                                            }[]
</td>
        <td style="border: 1px solid black; padding: 8px;">default: []</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">店家狀態</td>
        <td style="border: 1px solid black; padding: 8px;">isActive</td>
        <td style="border: 1px solid black; padding: 8px;">Boolean</td>
        <td style="border: 1px solid black; padding: 8px;">default: true</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">更新時間</td>
        <td style="border: 1px solid black; padding: 8px;">updateAt</td>
        <td style="border: 1px solid black; padding: 8px;">Date</td>
        <td style="border: 1px solid black; padding: 8px;">default: 現在時間</td>
    </tr>
</table>

---

<table style="width: 100%; border-collapse: collapse;">
    <tr style="background-color: #4472C4; color: white; text-align: center; font-weight: bold;">
        <td colspan="2" style="border: 1px solid black; padding: 8px;">名稱</td>
        <td colspan="2" style="border: 1px solid black; padding: 8px;">描述</td>
    </tr>
    <tr style="text-align: center;">
        <td colspan="2" style="border: 1px solid black; padding: 8px;">user</td>
        <td colspan="2" style="border: 1px solid black; padding: 8px;">使用者的設定（包括帳密、偏好等）</td>
    </tr>
    <tr style="background-color: #4472C4; color: white; text-align: center; font-weight: bold;">
        <td style="border: 1px solid black; padding: 8px; width: 20%;">屬性描述</td>
        <td style="border: 1px solid black; padding: 8px; width: 20%;">屬性名稱</td>
        <td style="border: 1px solid black; padding: 8px; width: 20%;">屬性型態</td>
        <td style="border: 1px solid black; padding: 8px; width: 40%;">屬性設定</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">使用者 ID</td>
        <td style="border: 1px solid black; padding: 8px;">_id</td>
        <td style="border: 1px solid black; padding: 8px;">ObjectId</td>
        <td style="border: 1px solid black; padding: 8px;">required: true, PK<br>unique: true</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">使用者帳號</td>
        <td style="border: 1px solid black; padding: 8px;">account</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">required: true, <br>unique: true</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">使用者密碼</td>
        <td style="border: 1px solid black; padding: 8px;">password</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">required: true</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">角色</td>
        <td style="border: 1px solid black; padding: 8px;">role</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">required: true, <br>enum: [owner, buyer, admin]</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">大頭貼</td>
        <td style="border: 1px solid black; padding: 8px;">photo</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">default: ""</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">電話</td>
        <td style="border: 1px solid black; padding: 8px;">phone</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">default: ""</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">電子郵件</td>
        <td style="border: 1px solid black; padding: 8px;">email</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">required: true, <br>unique: true</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">收藏店家</td>
        <td style="border: 1px solid black; padding: 8px;">favorStores</td>
        <td style="border: 1px solid black; padding: 8px;">Array<ObjectId></td>
        <td style="border: 1px solid black; padding: 8px;">default: [], <br>ref: 'store'</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">收藏商品</td>
        <td style="border: 1px solid black; padding: 8px;">favorItems</td>
        <td style="border: 1px solid black; padding: 8px;">{
                                                              storeId: ObjectId,
                                                              itemId: ObjectId
                                                            }[]</td>
        <td style="border: 1px solid black; padding: 8px;">default: [], <br>ref: 'store'</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">自訂義組合</td>
        <td style="border: 1px solid black; padding: 8px;">customCombos</td>
        <td style="border: 1px solid black; padding: 8px;">{ 
                                                              comboId: ObjectId,
                                                              comboName: String,
                                                              storeId: ObjectId,
                                                              {
                                                                storeId: ObjectId,
                                                                itemId: ObjectId
                                                              }[]
                                                            }[]</td>
        <td style="border: 1px solid black; padding: 8px;">default: [], <br>ref: 'store'</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">更新時間</td>
        <td style="border: 1px solid black; padding: 8px;">updateAt</td>
        <td style="border: 1px solid black; padding: 8px;">Date</td>
        <td style="border: 1px solid black; padding: 8px;">default: 現在時間</td>
    </tr>
</table>

---
   
<table style="width: 100%; border-collapse: collapse;">
    <tr style="background-color: #4472C4; color: white; text-align: center; font-weight: bold;">
        <td colspan="2" style="border: 1px solid black; padding: 8px;">名稱</td>
        <td colspan="2" style="border: 1px solid black; padding: 8px;">描述</td>
    </tr>
    <tr style="text-align: center;">
        <td colspan="2" style="border: 1px solid black; padding: 8px;">cart</td>
        <td colspan="2" style="border: 1px solid black; padding: 8px;">顧客在某店的購物車資訊（包含商品、價錢等）</td>
    </tr>
    <tr style="background-color: #4472C4; color: white; text-align: center; font-weight: bold;">
        <td style="border: 1px solid black; padding: 8px; width: 20%;">屬性描述</td>
        <td style="border: 1px solid black; padding: 8px; width: 20%;">屬性名稱</td>
        <td style="border: 1px solid black; padding: 8px; width: 20%;">屬性型態</td>
        <td style="border: 1px solid black; padding: 8px; width: 40%;">屬性設定</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">購物車 ID</td>
        <td style="border: 1px solid black; padding: 8px;">_id</td>
        <td style="border: 1px solid black; padding: 8px;">ObjectId</td>
        <td style="border: 1px solid black; padding: 8px;">required: true, PK, <br>unique: true</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">使用者 ID</td>
        <td style="border: 1px solid black; padding: 8px;">userId</td>
        <td style="border: 1px solid black; padding: 8px;">ObjectId</td>
        <td style="border: 1px solid black; padding: 8px;">required: true, <br>Indexed</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">店家 ID</td>
        <td style="border: 1px solid black; padding: 8px;">storeId</td>
        <td style="border: 1px solid black; padding: 8px;">ObjectId</td>
        <td style="border: 1px solid black; padding: 8px;">required: true</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">購物車內容</td>
        <td style="border: 1px solid black; padding: 8px;">items</td>
        <td style="border: 1px solid black; padding: 8px;">{
            itemId: ObjectId,
            itemName: String,
            price: Number,
            quantity: Number,
            subtotal: Number,
            description: String
       }[]</td>
        <td style="border: 1px solid black; padding: 8px;">default: []</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">總金額</td>
        <td style="border: 1px solid black; padding: 8px;">totalPrice</td>
        <td style="border: 1px solid black; padding: 8px;">Number</td>
        <td style="border: 1px solid black; padding: 8px;">default: 0</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">更新時間</td>
        <td style="border: 1px solid black; padding: 8px;">updateAt</td>
        <td style="border: 1px solid black; padding: 8px;">Date</td>
        <td style="border: 1px solid black; padding: 8px;">default: 現在時間</td>
    </tr>
</table>
    
---

<table style="width: 100%; border-collapse: collapse;">
    <tr style="background-color: #4472C4; color: white; text-align: center; font-weight: bold;">
        <td colspan="2" style="border: 1px solid black; padding: 8px;">名稱</td>
        <td colspan="2" style="border: 1px solid black; padding: 8px;">描述</td>
    </tr>
    <tr style="text-align: center;">
        <td colspan="2" style="border: 1px solid black; padding: 8px;">order</td>
        <td colspan="2" style="border: 1px solid black; padding: 8px;">顧客提交的訂單（訂單詳情、訂單狀態等）</td>
    </tr>
    <tr style="background-color: #4472C4; color: white; text-align: center; font-weight: bold;">
        <td style="border: 1px solid black; padding: 8px; width: 20%;">屬性描述</td>
        <td style="border: 1px solid black; padding: 8px; width: 20%;">屬性名稱</td>
        <td style="border: 1px solid black; padding: 8px; width: 20%;">屬性型態</td>
        <td style="border: 1px solid black; padding: 8px; width: 40%;">屬性設定</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">訂單 ID</td>
        <td style="border: 1px solid black; padding: 8px;">_id</td>
        <td style="border: 1px solid black; padding: 8px;">ObjectId</td>
        <td style="border: 1px solid black; padding: 8px;">required: true, PK <br>unique: true
</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">店家 ID</td>
        <td style="border: 1px solid black; padding: 8px;">storeId</td>
        <td style="border: 1px solid black; padding: 8px;">ObjectId</td>
        <td style="border: 1px solid black; padding: 8px;">required: true, <br>ref: 'store'</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">顧客 ID</td>
        <td style="border: 1px solid black; padding: 8px;">customerId</td>
        <td style="border: 1px solid black; padding: 8px;">ObjectId</td>
        <td style="border: 1px solid black; padding: 8px;">ref: 'user'</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">顧客電話號碼</td>
        <td style="border: 1px solid black; padding: 8px;">customerPhone</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">（未登入顧客必填）</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">訂單類型</td>
        <td style="border: 1px solid black; padding: 8px;">orderType</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">required: true, <br>enum: ['內用', '外帶']</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">內用詳情</td>
        <td style="border: 1px solid black; padding: 8px;">dineInDetail</td>
        <td style="border: 1px solid black; padding: 8px;">{
                                                              tableNumber: String
                                                            }</td>
        <td style="border: 1px solid black; padding: 8px;">（當 orderType 為'內用'時需要）</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">外帶詳情</td>
        <td style="border: 1px solid black; padding: 8px;">takeoutDetail</td>
        <td style="border: 1px solid black; padding: 8px;">{
                                                              takeoutTime: Date
                                                            }</td>
        <td style="border: 1px solid black; padding: 8px;">（當 orderType 為'外帶'時需要）</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">訂單項目</td>
        <td style="border: 1px solid black; padding: 8px;">items</td>
        <td style="border: 1px solid black; padding: 8px;">{
                                                              menuItemId: ObjectId, 
                                                              itemName: String,
                                                              quantity: Number, 
                                                              unitPrice: Number, 
                                                              customization: [String],
                                                              itemSubTotal: Number
                                                            }[]</td>
        <td style="border: 1px solid black; padding: 8px;">default = []</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">訂單總金額</td>
        <td style="border: 1px solid black; padding: 8px;">totalAmount</td>
        <td style="border: 1px solid black; padding: 8px;">Number</td>
        <td style="border: 1px solid black; padding: 8px;">requied: true</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">顧客備註</td>
        <td style="border: 1px solid black; padding: 8px;">remarks</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">default: ''</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">支付方式</td>
        <td style="border: 1px solid black; padding: 8px;">paymentMethod</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">requied: true, <br>enum: ['店內付款']</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">訂單狀態</td>
        <td style="border: 1px solid black; padding: 8px;">state</td>
        <td style="border: 1px solid black; padding: 8px;">String</td>
        <td style="border: 1px solid black; padding: 8px;">required: true, <br>default: '已送出訂單', <br>enum: ['已送出訂單', '已接單', '準備中', '已完成', '顧客已取餐']</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">訂單成立時間</td>
        <td style="border: 1px solid black; padding: 8px;">createAt</td>
        <td style="border: 1px solid black; padding: 8px;">Date</td>
        <td style="border: 1px solid black; padding: 8px;">default: 現在時間</td>
    </tr>
    <tr>
        <td style="border: 1px solid black; padding: 8px;">訂單更新時間</td>
        <td style="border: 1px solid black; padding: 8px;">updateAt</td>
        <td style="border: 1px solid black; padding: 8px;">Date</td>
        <td style="border: 1px solid black; padding: 8px;">default: 現在時間</td>
    </tr>
</table>

---


### 5.2 檔案結構
```
backend
└── src
    └── main
        ├── java
        │   └── Team5
        │       └── example
        │           └── breakfast_ordering
        │               │
        │               ├── config
        │               │   └── WebSocketConfig.java      // 建立後端與前端之間的通訊通道，推播通知使用
        │               │
        │               ├── controller                    // 負責接收前端 API 請求
        │               │   ├── UserController.java       // 處理使用者註冊、登入、收藏、自定義組合
        │               │   ├── StoreController.java      // 處理店家瀏覽、菜單、搜尋商品
        │               │   ├── CartController.java       // 處理購物車邏輯
        │               │   ├── OrderController.java      // 處理訂單邏輯 
        │               │   └── WebConfig.java            // 處理 CORS 跨域設定
        │               │
        │               ├── model                         // 定義資料庫結構
        │               │   ├── User.java                 // 使用者資料
        │               │   ├── Store.java                // 店家與菜單資料
        │               │   ├── Cart.java                 // 購物車資料
        │               │   └── Order.java                // 訂單資料
        │               │
        │               ├── repository                    // 負責與 MongoDB 溝通
        │               │   ├── UserRepository.java       // User 資料庫操作介面
        │               │   ├── StoreRepository.java      // Store 資料庫操作介面
        │               │   ├── CartRepository.java       // Cart 資料庫操作介面
        │               │   └── OrderRepository.java      // Order 資料庫操作介面
        │               │
        │               ├── security
        │               │   ├── CustomOAuth2UserService.java    // 負責處理 Google 登入後的資料同步邏輯
        │               │   └── OrderRepository.java            // 整個後端的安全防護網，規定誰可以進入哪裡
        │               │
        │               └── BackendApplication.java       // Spring Boot 程式入口
        │
        └── resources
            └── application.properties                    // MongoDB 連線字串、Port 設定

frontend
├── src
│   ├── assets                    // 需編譯的靜態資源
│   │   └── logo.png
│   │
│   ├── components                // 可重複使用的 UI 元件 (非完整頁面)
│   │   └── MenuItem.vue          // 例如：顯示單一菜單項目的卡片
│   │
│   ├── data                      // 存放測試用的 JSON 資料
│   │   ├── menu.json
│   │   └── StoreData.json
│   │
│   ├── models                    // 前端資料結構定義 (Class/Interface)
│   │   └── store.model.js        // 定義店家資料的格式
│   │
│   ├── router                    // 設定網址 (URL) 與頁面 (View) 的對應關係
│   │   └── index.js              // Vue Router 設定檔
│   │
│   ├── store                     // 全域資料狀態 (Vuex)，負責與後端 API 溝通
│   │   ├── index.js              // Vuex 主設定檔
│   │   ├── cart.js               // 購物車狀態 (對應後端 CartController)
│   │   ├── shops.js              // 店家列表狀態 (對應後端 StoreController)
│   │   └── user.js               // 使用者登入狀態 (對應後端 UserController)
│   │
│   ├── viewmodels                // 處理視圖邏輯 (MVVM 模式)，分離 UI 與資料處理
│   │   └── storeSettingViewModel.js
│   │
│   ├── views                     // 完整的網頁頁面
│   │   ├── CartView.vue          // 購物車頁面
│   │   ├── FavoriteView.vue      // 收藏頁面
│   │   ├── HomeView.vue          // 顧客首頁
│   │   ├── LoginView.vue         // 登入頁面
│   │   ├── RegisterView.vue      // 註冊頁面
│   │   ├── ShopView.vue          // 店家頁面
│   │   └── StoreSetting.vue      // 店家設定頁面 
│   │
│   ├── App.vue                   // 根組件 (Root Component)
│   └── main.js                   // 程式啟動點，掛載 Vue 實例
│
├── .browserslistrc               // 瀏覽器相容性設定
├── .eslintrc.js                  // 程式碼風格檢查設定
├── babel.config.js               // ES6+ 語法轉譯設定
└── package.json                  // 專案依賴套件管理
```

<!-- ### 5.3 XML / JSON 結構
（於此處描述重要的 XML / JSON 結構範例） -->

---

## <span id="section6">6. 類別圖設計 (Class Diagram)</span>
<!-- <span style="color:red">發展 UML 之 class diagram（可對應 C4 model 中的 Code diagram），明確設計系統中包含哪些類別，以及這些類別之間的關係。 若遇到非一般物件類別或特殊物件類別，如 HTML、JavaScript、JSP、Servlet 等，可用 stereotype 表達，如 <<JavaScript>>、<<Servlet>>。 可把重點放在定義程式結構：訂出所有類別名稱、拉出所有類別關係，再加入重要的 attribute/operation 即可。而特殊的類別職責設計可加上文字說明。</span>
（於此處插入 UML 類別圖，並可補充文字說明） -->

```mermaid
classDiagram
    %% ==========================
    %% 1. 資料模型 (Models)
    %% ==========================
    class User {
        -String id
        -String account
        -String password
        -String email
        -String nickname
        -String photo
        -String phone
        -List~String~ favorStores
        -List~FavorItem~ favorItems
        -List~CustomCombo~ customCombos
    }

    class FavorItem {
        -String storeId
        -String itemId
    }

    class CustomCombo {
        -String comboId
        -String comboName
        -List~FavorItem~ items
    }

    class Cart {
        -String userId
        -String storeId
        -List~CartItem~ items
        -Integer totalAmount
    }

    class CartItem {
        -String itemId
        -String itemName
        -Integer quantity
        -Integer Price
        -Integer subtotal
        -String description
    }

    class Store {
        -String id
        -String ownerId
        -String name
        -String address
        -String description
        -Boolean isActive
        -List~MenuItem~ menu
    }

    class MenuItem {
        -String id
        -String itemName
        -Integer price
        -Boolean isAvailable
    }

    class Order {
        -String id
        -String storeId
        -String customerId
        -String orderType
        -Integer totalAmount
        -String state
        -Date createAt
        -List~OrderItem~ items
        -DineInDetail dineInDetail
        -TakeoutDetail takeoutDetail
        -String paymentMethod
    }

    class OrderItem {
        -String menuItemId
        -String itemName
        -Integer quantity
        -Integer unitPrice
        -List~String~ customization
    }

    %% ==========================
    %% 2. 控制層 (Controllers)
    %% ==========================
    class UserController {
        +register(userJson)
        +login(account, password)
        +getUser(userId)
        +updateUser(userId, updateJson)
        +deleteUser(userId)
        +addFavoriteStore(userId, storeId)
        +removeFavoriteStore(userId, storeId)
        +getFavoriteStores(userId)
        +addFavoriteItem(userId, storeId, itemId)
        +removeFavoriteItem(userId, storeId, itemId)
        +getFavoriteItems(userId, storeId, itemId)
        +addCustomCombo(userId, comboJson)
        +updateCustomComboName(userId, comboId, comboJson)
        +deleteCustomCombo(userId, comboId)
        +addItemToCustomCombo(userId, comboId, storeId, itemId)
        +removeItemFromCustomCombo(userId, comboId, storeId, itemId)
        +getCustomCombos(userId)
        +getCustomCombo(userId, comboId)
    }

    class CartController {
        +getCart(userId)
        +addItemToCart(userId, cartItem)
        +removeItemFromCart(userId, itemId)
        +clearCart(userId)
    }

    class StoreController {
        +createStore(storeJson)
        +getAllStores()
        +getStoreDetail(storeId)
        +updateStoreMenu(id, menuItems)
        +searchStoreProducts(storeId, keyword)
    }

    class OrderController {
        +createOrder(orderJson)
        +getCustomerHistory(customerId)
        +getOrderDetail(orderId)
        +getStoreOrders(storeId)
        +updateOrderState(orderId, state)
        +cancelOrder(orderId)
    }

    %% ==========================
    %% 3. 服務層 (Services)
    %% ==========================
    class StoreService {
        +createNewStore(store)
        +findAllActiveStores()
        +findStoreById(storeId)
        +updateMenu(storeId, menu)
        +searchProducts(storeId, keyword)
    }

    class OrderService {
        +createOrder(order)
        +getOrdersByCustomer(customerId)
        +getOrdersByStore(storeId)
        +getOrderById(orderId)
        +updateStatus(orderId, status)
    }

    %% ==========================
    %% 4. 儲存庫 (Repositories)
    %% ==========================
    class UserRepository {
        <<interface>>
        +findByAccount(account)
        +existsByAccount(account)
    }

    class CartRepository {
        <<interface>>
        +findByUserId(userId)
    }

    class StoreRepository {
        <<interface>>
        +findByIsActiveTrue()
        +findByNameContaining(keyword)
    }

    class OrderRepository {
        <<interface>>
        +findByCustomerId(customerId)
        +findByStoreId(storeId)
    }

    %% ==========================
    %% 5. 關係連線 (Relationships)
    %% ==========================

    %% Controller 依賴 Service
    StoreController ..> StoreService
    OrderController ..> OrderService

    %% Service 依賴 Repository
    UserController ..> UserRepository
    CartController ..> CartRepository
    StoreService ..> StoreRepository
    OrderService ..> OrderRepository

    %% Repository 操作 Model
    UserRepository ..> User
    CartRepository ..> Cart
    StoreRepository ..> Store
    OrderRepository ..> Order

    %% Model 內部的組合關係 (Composition)
    User *-- FavorItem
    User *-- CustomCombo
    Cart *-- CartItem
    Store *-- MenuItem
    Order *-- OrderItem

    %% 模組間的關聯 (Association via IDs)
    Cart --> User : "userId"
    Cart --> Store : "storeId"
    Order --> User : "customerId"
    Order --> Store : "storeId"
    FavorItem --> Store : "storeId"
```
    
    
---

## <span id="section7">7. 實作方案 (Implementation Languages and Platforms)</span>

- 平台：
  - 網站（可支援電腦與手機）
- 前端：
  - 程式語言：HTML5 + CSS3 + JavaScript
  - 框架：Vue 3
- 後端：
  - 程式語言：Java
  - 框架：Spring Boot
  - 資料庫操作：MongoDB
- 主要函式庫與服務：
    - 前端：
        - Fetch API：向後端發送 HTTP 請求（登入、註冊、更新資料等）
        - Vuex：管理前端狀態
    - 後端：
        - Spring Boot Web：提供 RESTful API，負責前後端通訊
        - Spring Data MongoDB：與 MongoDB 連接，負責資料存取
        - Spring Validation：處理資料驗證（例如 電子信箱格式、電話格式）
        - Spring Security（若需要 JWT）：管理登入驗證、授權
        - bcrypt（Spring Security BCryptPasswordEncoder）：
用於使用者密碼加密
    - 資料庫:
        - MongoDB：儲存使用者、店家、商品、訂單等資料
        - MongoRepository：簡化 CRUD 操作
    - 第三方服務：Cloud Storage、Email API、OAuth 認證（Google、Facebook 登入）
- 部署方式：
    - 雲端 PaaS

---

## <span id="section8">8. 設計議題 (Design Issue)</span>

### 議題 1：後端 Controller 的職責劃分與 API 設計風格
- 議題內容：
    - 在設計後端 API 架構時，我們面臨了如何劃分 Controller 職責的選擇。這個決策將影響到程式碼的可維護性以及前後端對接的模式。
- 可能解決方案：
    - 以「功能」為中心：一個主要頁面或功能模組對應一個 Controller
    - 以「資料庫 Model」 為中心：一個資料庫 Collection 對應一個 Controller
- 最後解決方案與理由：
    - 最後選擇採用以「資料庫 Model」 為中心，此方案優點如下：
        - 方便 debug：以 Model 為中心的寫法會寫出很多基本函式，如果有問題會比較好追（錯誤來源單純）
        - 彈性較大：如上所述，會有很多基本函式拼湊成前端可用的功能
        - 降低邏輯耦合：避免多個功能寫出來的程式碼中會有重複、相近的程式碼

<!-- ### 議題 2：＿＿＿＿＿＿＿＿
- 議題內容：
- 可能解決方案：
- 最後解決方案與理由： -->