---
# System prepended metadata
title: 系統設計文件(SDD)
---
# 軟體設計文件(SDD)
- 專案名稱:海大拍賣系統
- 撰寫日期:2025/11/23
- 發展者:游承諺、王洪賢、張宸翊、蘇奕勳、蕭丞佑
---
## 版次變更記錄
| 版次 | 變更項目 | 變更日期 |
| --- | -------- | -------- |
| 0.1 | 初版 | 2025/11/23 |
| 0.2 | 修改架構圖| 2025/11/23 |
| 0.3 | 新增設計議題 | 2025/11/24 |
| 0.4 | 修改使用者畫面設計 | 2025/11/24|
| 1.0 | 補齊設計文件 | 2025/12/23 |
---
## 目錄
1. 系統模型與架構 (System Model / System Architecture)
2. 介面需求與設計 (Interface Requirement and Design)
3. 流程設計 (Process Design)
4. 使用者畫面設計 (User Interface Design)
5. 資料設計 (Data Design)
6. 類別圖設計 (Class Diagram)
7. 實作方案 (Implementation Languages and Platforms)
8. 設計議題 (Design Issue)
---
## 1. 系統模型與架構 (System Model / System Architecture)
* Container diagram

* Component diagram
* 前端

* 後端




* 模組相依圖
```mermaid
graph LR
User["👤 User"]
Product["🛍️ Product"]
Order["📦 Order"]
Cart["🛒 Cart"]
Chat["💬 Message(Chat)"]
History["📜 History"]
Coupon["🎟️ Coupon"]
Review["📝 Review"]
User -->|販售| Product
User -->|購買| Order
User -->|管理| Cart
User -->|參與| Chat
User -->|產生| History
User -->|領取| Coupon
User -->|撰寫| Review
Product -->|包含| Review
Product -->|包含| Coupon
Product -->|被加入| Cart
Product -->|被購買| Order
Product -->|被瀏覽| History
Cart -->|轉換為| Order
Order -->|記錄| History
Order -->|應用| Coupon
Review -->|記錄| History
Coupon -->|應用於| Order
%% 樣式
classDef core fill:#bbdefb,stroke:#1565c0,stroke-width:3px
classDef support fill:#f0f4c3,stroke:#f57f17,stroke-width:2px
classDef utility fill:#dcedc8,stroke:#558b2f,stroke-width:2px
class User,Product,Order core
class Cart,Chat,Review support
class History,Coupon utility
```
* 三層架構圖(MCV)
```mermaid
graph TB
subgraph API_Layer["Controller"]
UC["👤 AuthController"]
UC2["🛒 CartController"]
UC3["🛍️ ProductController"]
UC4["📦 OrderController"]
UC5["💬 ChatController"]
UC6["📜 HistoryController"]
UC7["🎟️ CouponController"]
UC8["📝 ReviewController"]
end
subgraph Service_Layer["Service"]
US["👤 UserService"]
PS["🛍️ ProductService"]
OS["📦 OrderService"]
CS["🛒 CartService"]
CHS["💬 ChatService"]
HS["📜 HistoryService"]
CPS["🎟️ CouponService"]
RS["📝 ReviewService"]
end
subgraph Repository_Layer["Repository"]
UR["👤 UserRepository"]
PR["🛍️ ProductRepository"]
OR["📦 OrderRepository"]
CR["🛒 CartRepository"]
CHR["💬 ChatRoomRepository"]
HR["📜 HistoryRepository"]
CPR["🎟️ CouponRepository"]
RR["📝 ReviewRepository"]
end
subgraph Model_Layer["Model"]
UM["👤 User"]
PM["🛍️ Product"]
OM["📦 Order"]
CM["🛒 Cart"]
CHM["💬 ChatRoom"]
HM["📜 History"]
CPM["🎟️ Coupon"]
RM["📝 Review"]
end
subgraph Database["MongoDB"]
MDB["Collections"]
end
%% 控制器 -> 服務
UC --> US
UC2 --> CS
UC3 --> PS
UC4 --> OS
UC5 --> CHS
UC6 --> HS
UC7 --> CPS
UC8 --> RS
%% 服務 -> Repository
US --> UR
PS --> PR
OS --> OR
CS --> CR
CHS --> CHR
HS --> HR
CPS --> CPR
RS --> RR
%% Repository -> Model
UR --> UM
PR --> PM
OR --> OM
CR --> CM
CHR --> CHM
HR --> HM
CPR --> CPM
RR --> RM
%% Model -> Database
UM --> MDB
PM --> MDB
OM --> MDB
CM --> MDB
CHM --> MDB
HM --> MDB
CPM --> MDB
RM --> MDB
%% 樣式
classDef controller fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef service fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef repository fill:#e0f2f1,stroke:#00796b,stroke-width:2px
classDef model fill:#fff3e0,stroke:#f57c00,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
class UC,UC2,UC3,UC4,UC5,UC6,UC7 controller
class US,PS,OS,CS,CHS,HS,CPS service
class UR,PR,OR,CR,CHR,HR,CPR,RR repository
class UM,PM,OM,CM,CHM,HM,CPM,RM model
class MDB database
```
---
## 2. 介面需求與設計 (Interface Requirement and Design)
## 使用者認證相關
| 介面名稱 | 介面提供者 | 介面使用者 | 連結方式 | 輸入資料 | 輸出資料 | 介面描述 |
| -------- | ---------- | ---------- | -------- | -------- | -------- | -------- |
|register|User module|登入頁面|POST| username, password, email | JWT token|使用者註冊並回傳 JWT token|
|login|User module|登入頁面|POST|username, password |JWT token|使用者登入並回傳 JWT token|
|getUserInfo|User module|用戶資料頁|GET|username|User所有欄位|取得指定使用者的詳細資訊|
|updateUserInfo|User module|用戶資料頁|PUT|currentUsername,要修改的欄位|User所有欄位|更新指定使用者的個人資訊|
|updatePassword|User module|用戶資料頁|PUT|username, 目前密碼,新密碼|成功 / 失敗訊息|更新使用者密碼|
## 商品相關
| 介面名稱 | 介面提供者 | 介面使用者 | 連結方式 | 輸入資料 | 輸出資料 | 介面描述 |
| -------- | ---------- | ---------- | -------- | -------- | -------- | -------- |
|getproductByPage|product module|首頁|GET|page,pageSize|Product內所有欄位|取得第x頁的特定個數商品|
|getproductByID|product module|首頁、商品頁|GET|productID|Product內所有欄位|取得特定ID商品|
|getAllproduct|product module|首頁|GET| |Product內所有欄位|取得資料庫內所有商品|
|createProduct|product module|賣家後台|POST|Product|Product內所有欄位|新增一個商品|
|editProduct | Product module|賣家後台|PUT|商品ID、UserID、要修改的欄位| Product內所有欄位 | 更新特定ID的商品 |
|uploadProduct |Product module|賣家後台|PUT|productID |Product|上架後商品狀態改為ACTIVE |
|withdrawProduct |Product module|賣家後台|PUT|productID|Product|下架後商品狀態改為 INACTIVE |
|deleteProduct |Product module|賣家後台|DELETE|productID| 成功 / 失敗訊息 | 刪除特定ID商品 |
|createAuction|auction module|賣家後台|POST|基礎價格,結束時間| productID|Product|建立拍賣商品,設定起標價與競標截止時間|
|getAllAuctionProduct|auction module|賣家後台|GET| |Product內所有欄位|取得所有拍賣中的商品|
## 競標相關
| 介面名稱 | 介面提供者 | 介面使用者 | 連結方式 | 輸入資料 | 輸出資料 | 介面描述 |
| -------- | ---------- | ---------- | -------- | -------- | -------- | -------- |
|placeBid|auction module|賣家後台|PUT|bidPrice, productID, bidderID|成功 / 失敗訊息|買家出價,需高於目前最高出價|
|terminateAuction|auction module|賣家後台|PUT|productID|Product / 成功訊息|終止拍賣並建立訂單,將商品狀態改為已售出|
## 購物車相關
| 介面名稱 | 介面提供者 | 介面使用者 | 連結方式 | 輸入資料 | 輸出資料 | 介面描述 |
| -------- | ---------- | ---------- | -------- | -------- | -------- | -------- |
|getCart|Cart module|購物車頁面|GET|username|Cart|取得使用者購物車|
|addToCart|Cart module|購物車頁面|POST|username, productId, quantity|Cart|將商品加入使用者購物車|
|updateQuantity|Cart module|購物車頁面|PUT|username, productId, quantity|Cart|更新購物車中商品數量,數量為0則移除商品|
|removeCart|Cart module|購物車頁面|DELETE|username, productId|Cart|從購物車移除指定商品|
|clearCart|Cart module|購物車頁面|DELETE|username|Cart|清空使用者購物車|
## 訂單相關
| 介面名稱 | 介面提供者 | 介面使用者 | 連結方式 | 輸入資料 | 輸出資料 | 介面描述 |
| -------- | ---------- | ---------- | -------- | -------- | -------- | -------- |
|createOrder|Order module|結帳頁面|POST|Order, buyerID, ProductTypes|Order|建立訂單,檢查與更新庫存|
|getOrderById|Order module|結帳頁面|GET|orderID|Order|取得指定訂單資訊|
## 評論相關
| 介面名稱 | 介面提供者 | 介面使用者 | 連結方式 | 輸入資料 | 輸出資料 | 介面描述 |
| -------- | ---------- | ---------- | -------- | -------- | -------- | -------- |
|createReview|Review module|商品頁|POST|Review|Review|建立評論,一個使用者對同一商品只能評論一次|
|editReview|Review module|商品頁|PUT|userID, starCount, content, imgURL|Review|編輯評論內容、星數及圖片|
## 其他
| 介面名稱 | 介面提供者 | 介面使用者 | 連結方式 | 輸入資料 | 輸出資料 | 介面描述 |
| -------- | ---------- | ---------- | -------- | -------- | -------- | -------- |
|getAllReviewHistory|Review module|商品頁|GET| |多個reviewHistory|取得所有評論歷史紀錄|
|swagger|Spring Boot|Ovral|HTTPS||JSON|前端以 orval 從後端 Swagger 自動產生 Typescript 型別與 API hooks。|
|MongoDB Atlas|MongoDB Atlas|後端|mongoDB連接字串|id name等,可以自行設計查找要傳入的參數|JSON|後端透過 Repository 操作 MongoDB Atlas,包括查詢、寫入、更新商品與使用者資料等。|
|ESLint|ESLint|前端js程式|命令列(例:npm run eslint:check)|config檔案|文字結果(例如錯誤訊息)|ESLint用於檢查Js程式碼,主要用於識別和報告潛在問題,包括語法錯誤、風格不一致等|
---
## 3. 流程設計 (Process Design)

先說明登入流程:輸入帳密後,認證模組檢查帳密與資料庫中的是否符合,是的話會回傳JWT token,並將token與username存在localstorage。若帳密錯誤回傳401
瀏覽商品:成功登入後,前端首頁呼叫商品模組,而商品頁則是透過商品id取得商品並呈現,取得商品的名稱、圖片、介紹等欄位
搜尋商品:使用者在搜尋欄輸入關鍵字,首頁呼叫商品模組,商品模組去資料庫比對結果並回傳給首頁,如果沒有結果,將"無搜尋結果"顯示出來
新增 刪除 修改商品:先檢查使用者是否登入,是否有取得token,沒有的話回傳403,如果有登入:從首頁導向用戶資料頁再導向賣家後台進行商品的操作,並檢查合法性
直購商品購買:依照先前流程進入商品頁後,在該頁面選擇商品數量後點擊加入購物車會先呼叫商品模組檢查是否可被購買,否的話導向至商品頁,是的話再檢查是否登入,是的話導引至購物車頁面,否則導引至登入頁面
拍賣商品購買:依照先前流程進入商品頁後,在該頁面設定競標價格後點擊加入競標,會先呼叫競標品模組檢查價格是否合理,否的話導向至商品頁,要求輸入合理價格,是的話再檢查是否登入,是的話檢查競標時間是否截止並導引至競標頁面,否則導引至登入頁面,在競標頁面中,確認出價最高者並建立訂單
結帳:先檢查是否登入,是的話導引至購物車頁面,否則導引至登入頁面。進入購物車頁面後,確認是否結帳,是的話呼叫訂單模組檢查商品庫存等是否允許建立訂單,否的話則返回購物車
交易:先檢查訂單是否成立,是的話導引至訊息系統,並透過訊息模組實現買賣家溝通,否的話導引至首頁

---
### 驗證流程
```mermaid
sequenceDiagram
participant Client as 客戶端
participant Server as 服務器
participant DB as 數據庫
Client ->> Server: POST /login (username, password)
Server ->> DB: 查詢用戶
DB -->> Server: 返回User對象
Server ->> Server: 驗證密碼 (BCrypt)
Server ->> Server: 生成JWT Token (JwtUtil)
Server -->> Client: 返回Token + 用戶信息
Client ->> Server: GET /api/user/me (Authorization: Bearer Token)
Server ->> Server: 驗證JWT Token (JwtAuthenticationFilter)
Server ->> Server: 解析Token獲取用戶信息
Server ->> DB: 根據userId查詢用戶
DB -->> Server: 返回用戶信息
Server -->> Client: 返回用戶數據
```
---
## 4. 使用者畫面設計 (User Interface Design)
## 主頁面

- 這是網站的主頁面,展示主要功能入口,包括熱門商品、分類瀏覽及快速連結等。
## 登入與註冊頁面


## 商品展示頁面

- 直購商品列表頁,會依據商品狀態而有不同的呈現結果。

- 拍賣商品列表頁,顯示拍賣商品的即時出價、剩餘時間及參與競標按鈕。
## 個人資料

使用者個人資料頁面,顯示基本資訊,並提供修改選項。
功能選單:優惠券提供一個輪盤讓使用者抽取,並提供其他修改密碼、歷史紀錄、管理商品功能

## 賣家後台

- 賣家後台主頁,提供建立與編輯商品、賣家評價等功能。


## 購物車

- 購物車頁面,顯示已加入的商品、數量、價格及結帳按鈕。
## 結帳

## 溝通介面

- 即時訊息溝通介面,使用者與賣家可透過此頁面進行交流與詢問商品。
## 訂單

- 訂單管理頁面,顯示使用者歷史訂單、狀態以及詳細資訊。
## 歷史紀錄

## 收藏商品

---
## 5. 資料設計 (Data Design)
### 5.1 檔案結構
* 前端
```
src/
├── api/ 集中管理api
│ ├── category.ts
│ ├── coupon.ts
│ ├── generated/
│ │ └── index.ts
│ ├── login.ts
│ ├── register.ts
│ └── search.ts
│
├── assets/
│ └── react.svg
│
├── components/
│ └── backgrounds/
│ └── LiquidEther/
│ ├── config.ts
│ ├── LiquidEther.css
│ └── LiquidEther.tsx
│
├── config/
│ └── api.ts
│
├── pages/
│ ├── Auth/
│ │ ├── login/
│ │ │ ├── index.tsx
│ │ │ └── Login.css
│ │ └── register/
│ │ ├── index.tsx
│ │ └── Register.css
│ │
│ ├── CartPage/
│ │ ├── CartFooter/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── CartHeader/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── CartItem/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── SellerSection/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── index.css
│ │ └── index.tsx
│ │
│ ├── ChatRoomPage/
│ │ ├── ChatHeader/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── ChatSidebar/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── MessageInput/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── MessageList/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── index.css
│ │ └── index.tsx
│ │
│ ├── CheckoutPage/
│ │ ├── CheckoutFooter/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── CheckoutHeader/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── CouponSelector/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── OrderSummary/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── PaymentForm/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── ShippingForm/
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ ├── index.css
│ │ └── index.tsx
│ │
│ ├── FavoriteList/
│ │ ├── ProductList/
│ │ │ └── index.tsx
│ │ ├── Search/
│ │ │ └── index.tsx
│ │ ├── FavoriteList.css
│ │ └── index.tsx
│ │
│ ├── Main/
│ │ ├── Filter/
│ │ │ ├── Filter.css
│ │ │ └── index.tsx
│ │ ├── Header/
│ │ │ ├── Header.css
│ │ │ └── index.tsx
│ │ ├── Pagination/
│ │ │ ├── index.tsx
│ │ │ └── Pagination.css
│ │ ├── Products/
│ │ │ ├── index.tsx
│ │ │ └── Products.css
│ │ ├── index.tsx
│ │ └── Main.css
│ │
│ ├── MyProfilePage/
│ │ ├── ControlPanel/
│ │ │ ├── Coupons/
│ │ │ │ ├── MyCoupons/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── MyCoupons.css
│ │ │ │ ├── SpinWheel/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── SpinWheel.css
│ │ │ │ ├── Terms/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── Terms.css
│ │ │ │ ├── Coupons.css
│ │ │ │ ├── index.tsx
│ │ │ │ └── useCoupons.ts
│ │ │ ├── ControlPanel.css
│ │ │ └── index.tsx
│ │ │
│ │ ├── SellerDashboard/
│ │ │ ├── ControlPanel/
│ │ │ │ ├── index.css
│ │ │ │ └── index.tsx
│ │ │ ├── ProductManage/
│ │ │ │ ├── index.css
│ │ │ │ └── index.tsx
│ │ │ ├── SellerInfo/
│ │ │ │ ├── index.css
│ │ │ │ └── index.tsx
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ │
│ │ ├── UserHistory/
│ │ │ ├── ControlPanel/
│ │ │ │ ├── index.css
│ │ │ │ └── index.tsx
│ │ │ ├── HistoryList/
│ │ │ │ ├── index.css
│ │ │ │ └── index.tsx
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ │
│ │ ├── UserProfile/
│ │ │ ├── index.tsx
│ │ │ ├── ProfileEditForm.css
│ │ │ ├── ProfileEditForm.tsx
│ │ │ └── UserProfile.css
│ │ │
│ │ ├── index.tsx
│ │ └── MyProfilePage.css
│ │
│ ├── OrderSuccessPage/
│ │ ├── index.css
│ │ └── index.tsx
│ │
│ ├── ProductPage/
│ │ ├── AuctionProduct/
│ │ │ ├── AuctionProduct.css
│ │ │ └── index.tsx
│ │ ├── Details/
│ │ │ ├── Details.css
│ │ │ └── index.tsx
│ │ ├── DireectProduct/
│ │ │ ├── DireectProduct.css
│ │ │ └── index.tsx
│ │ ├── Header/
│ │ │ └── index.tsx
│ │ ├── Review/
│ │ │ ├── index.tsx
│ │ │ └── Review.css
│ │ ├── Seller/
│ │ │ ├── index.tsx
│ │ │ └── Seller.css
│ │ └── index.tsx
│ │
│ ├── UserProfilePage/
│ │ ├── ProductList/
│ │ │ └── index.tsx
│ │ ├── UserProfile/
│ │ │ ├── index.tsx
│ │ │ └── UserProfile.css
│ │ ├── index.css
│ │ └── index.tsx
│ │
│ └── Shopping.tsx
│
├── types/
│ └── user.ts
│
├── App.css
├── App.tsx
└── main.tsx
```
* 後端
```
\src\main\
src/main/
├── java/
│ └── com/
│ └── ntou/
│ └── auctionSite/
│ ├── AuctionSiteApplication.java
│ │
│ ├── config/
│ │ ├── OpenApiConfig.java
│ │ ├── SecurityConfig.java
│ │ └── WebSocketConfig.java
│ │
│ ├── controller/
│ │ ├── bid/
│ │ │ ├── BidController.java
│ │ │ └── bidController說明.md
│ │ ├── cart/
│ │ │ └── CartController.java
│ │ ├── chat/
│ │ │ └── ChatController.java
│ │ ├── coupon/
│ │ │ ├── CouponController.java
│ │ │ └── UserCouponController.java
│ │ ├── history/
│ │ │ └── HistoryController.java
│ │ ├── imageUpload/
│ │ │ └── ImageUploadController.java
│ │ ├── order/
│ │ │ └── OrderController.java
│ │ ├── product/
│ │ │ └── ProductController.java
│ │ ├── review/
│ │ │ └── ReviewController.java
│ │ ├── search/
│ │ │ └── SearchController.java
│ │ └── user/
│ │ ├── AuthController.java
│ │ ├── FavoriteController.java
│ │ ├── InfoController.java
│ │ └── LotteryController.java
│ │
│ ├── dto/
│ │ ├── cart/
│ │ │ ├── AddToCartRequest.java
│ │ │ ├── CartItemDTO.java
│ │ │ ├── CartResponseDTO.java
│ │ │ └── UpdateCartQuantityRequest.java
│ │ ├── ChatRoom/
│ │ │ └── ChatRoomDto.java
│ │ ├── history/
│ │ │ ├── CreateBidHistoryRequest.java
│ │ │ ├── CreateBrowseHistoryRequest.java
│ │ │ ├── CreatePurchaseHistoryRequest.java
│ │ │ └── CreateReviewHistoryRequest.java
│ │ ├── product/
│ │ │ └── EditProductRequest.java
│ │ └── user/
│ │ ├── AuthResponse.java
│ │ ├── FavoriteItemDTO.java
│ │ ├── FavoriteResponseDTO.java
│ │ ├── LoginRequest.java
│ │ ├── PublicUserInfoResponse.java
│ │ ├── RegisterRequest.java
│ │ ├── SellerInfoResponse.java
│ │ ├── SimpleFavoriteItemDTO.java
│ │ ├── SimpleFavoriteResponseDTO.java
│ │ ├── UpdatePasswordRequest.java
│ │ ├── UpdateUserRequest.java
│ │ └── UserInfoResponse.java
│ │
│ ├── exception/
│ │ └── InvalidPasswordException.java
│ │
│ ├── model/
│ │ ├── ChatNotification.java
│ │ ├── ChatRoom.java
│ │ ├── Message.java
│ │ ├── Review.java
│ │ ├── cart/
│ │ │ └── Cart.java
│ │ ├── coupon/
│ │ │ ├── Coupon.java
│ │ │ ├── CouponType.java
│ │ │ └── UserCoupon.java
│ │ ├── history/
│ │ │ ├── bidHistory.java
│ │ │ ├── browseHistory.java
│ │ │ ├── History.java
│ │ │ ├── HistoryItem.java
│ │ │ ├── purchaseHistory.java
│ │ │ └── reviewHistory.java
│ │ ├── order/
│ │ │ ├── Order.java
│ │ │ └── OrderItem.java
│ │ ├── product/ # 产品模型
│ │ │ ├── Product.java
│ │ │ └── ProductTypes.java
│ │ └── user/ # 用户模型
│ │ ├── Favorite.java
│ │ ├── Role.java
│ │ └── User.java
│ │
│ ├── repository/ # 数据访问层
│ │ ├── CartRepository.java
│ │ ├── ChatRoomRepository.java
│ │ ├── CouponRepository.java
│ │ ├── FavoriteRepository.java
│ │ ├── MessageRepository.java
│ │ ├── OrderRepository.java
│ │ ├── ProductRepository.java
│ │ ├── ReviewRepository.java
│ │ ├── UserCouponRepository.java
│ │ ├── UserRepository.java
│ │ └── history/ # 历史记录 Repository
│ │ ├── BidHistoryRepository.java
│ │ ├── BrowseHistoryRepository.java
│ │ ├── HistoryRepository.java
│ │ ├── PurchaseHistoryRepository.java
│ │ └── ReviewHistoryRepository.java
│ │
│ ├── runner/
│ │ └── Runner.java
│ │
│ ├── security/
│ │ └── JwtAuthenticationFilter.java
│ │
│ ├── service/
│ │ ├── ChatMessageService.java
│ │ ├── ChatRoomService.java
│ │ ├── bid/
│ │ │ └── BidService.java
│ │ ├── cart/
│ │ │ └── CartService.java
│ │ ├── Coupon/
│ │ │ ├── CouponService.java
│ │ │ ├── HolidayCouponScheduler.java
│ │ │ └── UserCouponService.java
│ │ ├── GitHubUpload/
│ │ │ └── GitHubUploadService.java
│ │ ├── history/
│ │ │ └── HistoryService.java
│ │ ├── order/
│ │ │ └── OrderService.java
│ │ ├── product/
│ │ │ ├── ProductService.java
│ │ │ ├── ReviewService.java
│ │ │ └── SellingProductsService.java
│ │ ├── search/
│ │ │ └── SearchService.java
│ │ └── user/
│ │ ├── AuthService.java
│ │ ├── FavoriteService.java
│ │ ├── LotteryService.java
│ │ ├── UserDetails.java
│ │ └── UserService.java
│ │
│ └── utils/
│ └── JwtUtil.java
│
└── resources/
├── application-dev.yml
├── application-dev.yml.example
├── application-prod.yml
└── application.yml
```
### 5.2 XML / JSON 結構
```
{
"name": "User",
"fields": [
{ "name": "userID", "type": "Long", "pk": true },
{ "name": "username", "type": "String" },
{ "name": "email", "type": "String" },
{ "name": "password", "type": "String" },
{ "name": "roleID", "type": "Long", "fk": true, "references": "Role" }
]
},
{
"name": "Role",
"fields": [
{ "name": "roleID", "type": "Long", "pk": true },
{ "name": "name", "type": "String" }
]
},
{
"name": "Product",
"fields": [
{ "name": "productID", "type": "Long", "pk": true },
{ "name": "name", "type": "String" },
{ "name": "price", "type": "BigDecimal" },
{ "name": "typeID", "type": "Long", "fk": true, "references": "ProductTypes" }
]
},
{
"name": "ProductTypes",
"fields": [
{ "name": "typeID", "type": "Long", "pk": true },
{ "name": "name", "type": "String" }
]
},
{
"name": "Order",
"fields": [
{ "name": "orderID", "type": "Long", "pk": true },
{ "name": "userID", "type": "Long", "fk": true, "references": "User" },
{ "name": "total", "type": "BigDecimal" },
{ "name": "createdAt", "type": "LocalDateTime" }
]
},
{
"name": "OrderItem",
"fields": [
{ "name": "orderItemID", "type": "Long", "pk": true },
{ "name": "orderID", "type": "Long", "fk": true, "references": "Order" },
{ "name": "productID", "type": "Long", "fk": true, "references": "Product" },
{ "name": "quantity", "type": "Integer" },
{ "name": "price", "type": "BigDecimal" }
]
},
{
"name": "Cart",
"fields": [
{ "name": "cartID", "type": "Long", "pk": true },
{ "name": "userID", "type": "Long", "fk": true, "references": "User" },
{ "name": "updatedAt", "type": "LocalDateTime" }
]
},
{
"name": "Review",
"fields": [
{ "name": "reviewID", "type": "Long", "pk": true },
{ "name": "productID", "type": "Long", "fk": true, "references": "Product" },
{ "name": "userID", "type": "Long", "fk": true, "references": "User" },
{ "name": "rating", "type": "Integer" },
{ "name": "comment", "type": "String" },
{ "name": "createdAt", "type": "LocalDateTime" }
]
},
{
"name": "Message",
"fields": [
{ "name": "messageID", "type": "Long", "pk": true },
{ "name": "fromUserID", "type": "Long", "fk": true, "references": "User" },
{ "name": "toUserID", "type": "Long", "fk": true, "references": "User" },
{ "name": "content", "type": "String" },
{ "name": "sentAt", "type": "LocalDateTime" }
]
},
{
"name": "History",
"fields": [
{ "name": "historyID", "type": "Long", "pk": true },
{ "name": "userID", "type": "Long", "fk": true, "references": "User" },
{ "name": "timeStamp", "type": "LocalDateTime" },
{ "name": "type", "type": "String" }
]
},
{
"name": "bidHistory",
"fields": [
{ "name": "historyID", "type": "Long", "pk": true, "fk": true, "references": "History" },
{ "name": "productID", "type": "Long", "fk": true, "references": "Product" },
{ "name": "bidAmount", "type": "BigDecimal" }
],
"inherits": "History"
},
{
"name": "browseHistory",
"fields": [
{ "name": "historyID", "type": "Long", "pk": true, "fk": true, "references": "History" },
{ "name": "productID", "type": "Long", "fk": true, "references": "Product" }
],
"inherits": "History"
},
{
"name": "purchaseHistory",
"fields": [
{ "name": "historyID", "type": "Long", "pk": true, "fk": true, "references": "History" },
{ "name": "orderID", "type": "Long", "fk": true, "references": "Order" },
{ "name": "amount", "type": "BigDecimal" }
],
"inherits": "History"
},
{
"name": "reviewHistory",
"fields": [
{ "name": "historyID", "type": "Long", "pk": true, "fk": true, "references": "History" },
{ "name": "reviewID", "type": "Long", "fk": true, "references": "Review" }
],
"inherits": "History"
}
```
---
## 6. 類別圖設計 (Class Diagram)
[mermaid](https://mermaid.live/edit#pako:eNq9WltvG8cV_iuL1UNsRxJI6kYt8sKbagISpVCUExR8Ge4OyYG5u8zu0BKjGkjgto7Ri4NUSS8o0LRo0aYG0sAF2qZwkT9TSsq_6Fz2MrM7s2TaoH4wdudc5tzmO2eWujRt34GmZW5sbPQ92_eGaGT1PcPAY-hCy3DgEMwmOFl5AAIEBhMYMibDmAbIBcG8By9ww5_4gWW8tlZi_16TGOp-4MBAzTL0PXyK3iW7lXenF3RtOPHP7TEIcLTLLIRH4OIt5OCxZeBgBvset3cCwrCJwCgAbt9zUABtjHzP6NW5HKMbZyEMjMu-18d0beMUB8gbGcjJrpBdgg5w4b0sAboATXKrU6L7nLilVIPshx5RlaUBxwlgGOZUjX0PdmbuAAYJ6WDiA2yARzAAI9gFmPAltLaH4Yg4FbDlhj_zcEKr-_4EAs9AYR14HnTyQtQdj8g1A3DeQy4McyzUhRMfpVpfH0FMw0h9unPX4GaLxJMoGEpibYbHfoAwgiGhkyKY8DwlPCis2Tb1ouN7rYspySNVNOCeKLkOffuhzERZHvc9MfFdQlol8apMOTC0AzTlZip0H4BH1CW4amG109VDFGKDiLpJ4F8ndRErvDMNfGdm47ZzNyGTlPmPYBEHChXUwuDE_G1iSN6JRElqtW-DSRNgSEuGFjJ0alip-YTL6pU2c2cphKQmgnZTI9FRJCgiNcU8RRykcGPySYBsnWjbJScroUVW9-ZTGMYc9EWl9RST8tNobZAQjfxgnlV8igEmhRCmOui7Jrx2AMmjQ581HLOps4QDzNgha3kyE3XD88_vo9EYhrier9ZxQnGklFDBRwiey3Dj-DPSDjQ4RUUCmBei69jHYHIKJin8MByJS0QJJKdRmaghSMg4YWDopa9OnuekRJvtbqvRi99qZ41e-7hTJJ-kM1FRIzIPWvFbuyO_nx4fJqGs1zqdVvLWa3WPCHevpcYwFr78WeJhVRwlBjZNXW_THskswfZdFwop-zbqMwZId3TWPZSKIcQgkEqEJrQbuViUbYmqCF-DDBHfGkRTqEzhdd14B8-zGC2z3BUt7tGCj6uTH5uEbBOYDqitd-5q3VADNTWy7SyH77i1vzMDHkZ4Llr2ZrRWcGqO6fiW351NdYoiHMzmqirMwTxLj03-01QR0y_VkHR8OVkEaWZncjb99C0LWDjJRpYSjtF0Sqw9gFCuB-6sVBQkeMc8BMoiLUp5LMrNI3TJdH0S8sBz0uo0253vxK-N46OTw1YvBZhGrdNoHR6mC93WwVmnSd91mxQPBXJPyFaUNtlRfKdi0LVRUh0CfzYlw_1lHqrouqIKOaGzbLpTVh5kY2iuc3KVcjfjdtEyNBwUsglVqskm9zumPQCTWY7oIu9kFpA7TwhrrqR9OfBSu1xwcRYK4wyNayOKS740Uaifsm3gkUl_yWQtuCyUYbfR6iQ99KD9dlpxB91W6_R--0SpjF4sdLlFzooNLi6CZH2Q3IOIft0YS3QpW1QAJzTM0dkW4kZ1KYJGrrgPa5zIUcJR4_h9giNkNkz9XEuGLkYQinhN6e6abD8m_xFAcKdi3u_HupSYdBbq4SrWRqjSPkpfyICYc4fV4gA5mRrW4kdsKoWbcfosGlWPtcXd6RvPAPXAPw9h3tb_xaoVt47PdH7zWhCAOWsralSNVt_MgmsqJ1imGqFXaOp8wNIGJh4xcx8x2L1ChLil01otESmOlxj5y5Vn1f_-9pi7rGmvjkU5Sa4zJ4WtTZeGxhjgru-7K6EfKSecn_dC6DnSAJuk0EZTROb4lMQ6A1OiuWJxTUpiN1VXnMcjGNJu9P_xKG0BZMbVdk4KlWEWKjV-NrgmLUiGK4MkjXTHx2iIbMA-Ta7c4VaOiMtjrWh8XQic4jmihjMtjIpo7iAEiPPWE6xXDF7akzrgHxWcJf1CtpXQxR4dNQUN0hS0izrXsyRv7Gtx37zXN42NDfJQJg_sQ6JlXP_s_etfP7v940e3z15KzGWROfkyaBk3n__25sMfXl_97fbnz7lAQhSE7glCDPksY_HjHyw-fMFF4s9pGYnowwCx6qd_oDt89vHti09kCcIrXZcs49__-urm6k86ruRqITNmnaS7x8KWcfvys8XV53rO1M6Pvlj85YVopyp67EYYh5qzsaWM1uRCLMdKZQC_uhJD__rq9uXfOR9fIyzylUr2mzOptCl2jgZYwifMxsvjKMy-lvH1p79YPP9k8f0_Xz_5dPHBPyTFRXKLL35y_TQKVtzN3_ge4RVGNFKMX766fvaVikuajwoYs9NMAas8WsiMglWCV6XNTfosTgByhGUzv4lk1u5MLFWCi9__avHej_R5Ezy7-t3N1W-iXMWdPMMdt8PlxZpoIKzPn9x-8FTPmiq9-eWrr997v1ip1IRi0CgEGIr3MePi6T8XT77U78B5Yy4KuiGeE8xkvEM0mVhrcGtYGTopiWGqmpSAJCcPt-DOcCdPZglTs8QuRdQhLA0qOSoHxZiFqCjlWBJkUHNF2Ka2gcFWRLLhNrRlkmh9hsyBR61VBiy1WSlGaSzjwBERy8Mq3M8SGXxxBseGjl2Vc1qoIT4bUXJLJLnllCqcfs4wqDhDZyAwSOdczZM90WouGYTUPOLhVxucHElOtqtw1xa8jY-hmpo7euqY0vMj1qq5bo4C5JjWEExCuG66MHABfTcv6SHsm-zH-L5pkcf4J3qz7z0mclPgfZdYa1r0d_J1M_Bno3H8wj_KRz-YJxxsrmSftExrnykwrUvzwrQ2tnf3Nvd2drZ3tyqlnXJ1Z2dn3ZzT9VJls1Kt7G1t7W6Vq5VSdffxuvku27W8ub9X3a6WK_uVvcr2bml_e92EDiIxPuJ_aMD_xsB8_B88XwML)
```mermaid
classDiagram
direction TB
class User {
-String id
-String userName*
-String email*
-String password
-String userNickname
-String address
-String phoneNumber
-Float averageRating
-Integer ratingCount
-Boolean isBanned
-Integer remainingDrawTimes
-Integer userPoint
+getUsername() String
+getPassword() String
+getAuthorities() Collection
+isAccountNonExpired() boolean
+isAccountNonLocked() boolean
}
class Role {
-String id
-String name
-String description
}
class Favorite {
-String id
-String userId
-List items
+addFavorite(productId)
+removeFavorite(productId)
+isFavorite(productId) boolean
}
class FavoriteItem {
-String productId
-LocalDateTime addedAt
}
class Product {
-String productID*
-String sellerID
-String productName
-String productDescription
-int productPrice
-String productImage
-ProductTypes productType
-int productStock
-String productCategory
-ProductStatuses productStatus
-LocalDateTime createdTime
-LocalDateTime updatedTime
-LocalDateTime auctionEndTime
-int nowHighestBid
-String highestBidderID
-int viewCount
-double averageRating
-int reviewCount
-int totalSales
+getProductID() String
+getSellerID() String
+getProductPrice() int
}
class ProductTypes {
DIRECT
AUCTION
}
class ProductStatuses {
ACTIVE
INACTIVE
SOLD
BANNED
TERMINATE
}
class Review {
-String reviewID*
-String userID
-String userName
-String productID
-String comment
-LocalDateTime createdTime
-LocalDateTime updatedTime
-String imgURL
-int starCount
+getReviewID() String
+getProductID() String
}
class Cart {
-String id
-String userId
-List items
+addItem(productId, qty)
+removeItem(productId)
+getTotalPrice() double
+clearCart()
}
class CartItem {
-String itemId
-String productId
-Integer quantity
+getQuantity() int
}
class Order {
-String orderID*
-String buyerID
-String sellerID
-Cart cart
-LocalDateTime orderTime
-ProductTypes orderType
-OrderStatuses orderStatus
-double totalPrice
-double shippingFee
-List orderItems
+getOrderID() String
+getTotalPrice() double
+getOrderStatus() OrderStatuses
}
class OrderStatuses {
PENDING
COMPLETED
CANCELLED
REFUNDED
}
class OrderItem {
-String productID
-int quantity
-String sellerID
-double price
+getTotalPrice() double
}
class Coupon {
-String couponID*
-String couponName
-String description
-LocalDateTime expireTime
-int couponCount
-CouponType discountType
-Double discountValue
-Double minPurchaseAmount
-LocalDateTime createdTime
-int maxUsage
+getCouponID() String
+isExpired() boolean
+canUse() boolean
}
class CouponType {
PERCENT
FIXED
FREESHIP
}
class UserCoupon {
-String id*
-String userID
-String couponID
-boolean isUsed
-LocalDateTime usedTime
-String relatedOrderID
+isUsed() boolean
+markAsUsed(orderId)
}
class History {
#String historyID*
#String userID
#LocalDateTime timeStamp
+getHistoryID() String
+getUserID() String
+getTimeStamp() LocalDateTime
}
class BidHistory {
-int bidAmount
-String productID
-HistoryItem historyItem
+getBidAmount() int
+getProductID() String
}
class BrowseHistory {
-String productID
-HistoryItem historyItem
+getProductID() String
}
class PurchaseHistory {
-ArrayList productID
-int productQuantity
-ArrayList historyItems
+getProductQuantity() int
}
class ReviewHistory {
-String reviewID
-String actionType
+getReviewID() String
+getActionType() String
}
class HistoryItem {
-String productID
-String sellerID
-String productName
-String productCategory
-int productPrice
-int productQuantity
-int totalPrice
+getTotalPrice() int
}
class ChatRoom {
-String id*
-String chatId
-String senderId
-String recipientId
+getChatId() String
+getSenderId() String
+getRecipientId() String
}
class Message {
-String id*
-String chatId
-String senderId
-String recipientId
-String content
-LocalDateTime timestamp
+getId() String
+getContent() String
+getTimestamp() LocalDateTime
}
class ChatNotification {
-String id*
-String userId
-String senderId
-String message
-boolean isRead
-LocalDateTime createdAt
+markAsRead()
}
class Bid {
-String bidID*
-String productID
-String bidderId
-int bidAmount
-LocalDateTime bidTime
+getBidID() String
+getBidAmount() int
+getBidTime() LocalDateTime
}
User "*" -- "1" Role : 擁有角色
User "1" -- "1" Favorite : 管理收藏
Favorite "1" -- "*" FavoriteItem : 包含
Product "1" -- "*" Review : 接收評論
Product -- ProductTypes : 使用
Product -- ProductStatuses : 使用
User "1" -- "*" Product : 販售
User "1" -- "*" Review : 撰寫評論
User "1" -- "1" Cart : 擁有
Cart "1" -- "*" CartItem : 包含
User "1" -- "*" Order : 購買
Order -- OrderStatuses : 使用
Order "1" -- "*" OrderItem : 包含
Coupon -- CouponType : 使用
User "1" -- "*" UserCoupon : 領取優惠券
Coupon "1" -- "*" UserCoupon : 對應
History <|-- BidHistory : 繼承
History <|-- BrowseHistory : 繼承
History <|-- PurchaseHistory : 繼承
History <|-- ReviewHistory : 繼承
BidHistory "1" -- "0..1" HistoryItem : 包含
BrowseHistory "1" -- "0..1" HistoryItem : 包含
PurchaseHistory "1" -- "*" HistoryItem : 包含多個
User "1" -- "*" History : 產生
ChatRoom "1" -- "*" Message : 包含
User "1" -- "*" ChatRoom : 參與
User "1" -- "*" Message : 發送
User "1" -- "*" ChatNotification : 接收
Product "1" -- "*" Bid : 接收出價
User "1" -- "*" Bid : 出價
style User fill:#e3f2fd
style Role fill:#e3f2fd
style Favorite fill:#f3e5f5
style FavoriteItem fill:#f3e5f5
style Product fill:#ffe0b2
style ProductTypes fill:#fff3e0
style ProductStatuses fill:#fff3e0
style Review fill:#f3e5f5
style Cart fill:#fce4ec
style CartItem fill:#fce4ec
style Order fill:#f3e5f5
style OrderStatuses fill:#fff3e0
style OrderItem fill:#f3e5f5
style Coupon fill:#f1f8e9
style CouponType fill:#dcedc8
style UserCoupon fill:#f1f8e9
style History fill:#e0f2f1
style BidHistory fill:#b2dfdb
style BrowseHistory fill:#b2dfdb
style PurchaseHistory fill:#b2dfdb
style ReviewHistory fill:#b2dfdb
style HistoryItem fill:#e0f2f1
style ChatRoom fill:#c8e6c9
style Message fill:#c8e6c9
style ChatNotification fill:#dcedc8
style Bid fill:#ffe0b2
```
---
## 7. 實作方案 (Implementation Languages and Platforms)
- 平台: 網站
- 前端技術與框架: React+Typescript
- 後端技術與框架:
- Java Maven + Springboot + lombok
- Python Flask for RAG
- 主要函式庫與服務:
- Swagger api :自動生成API文件,方便測試與維護
- MongoDB Atlas(雲端 MongoDB):從連線字串 mongodb+srv://... 可見使用 Atlas cluster。
- Spring Security:安全性/認證設定(spring.security.debug)。
- JWT(JSON Web Token):應用端使用 JWT(jwt.secret、jwt.expiration)。
- springdoc-openapi / Swagger UI:API 文件與介面(springdoc 設定)。
- stompjs Web Socket :用於建立用戶聊天室
- Chart.js : 圖表繪製函式庫
- ESLint - 程式碼檢查工具
- axios - HTTP 客戶端(用於 API 請求)
- orval - 自動生成 API 型別與 hooks(從OpenAPI 規格)
- jsdelivr : 用於取得Github CDN的連結
- playwright: 前端自動化腳本系統測試
- 部署方式: 透過Github Workflow 做CI管理 + 自架sever部署
https://davidloman.jamessu2016.com/
---
## 8. 設計議題 (Design Issue)
### 議題 1:React Router
- 議題內容:跳轉頁面方式過於複雜
- 可能解決方案:修改頁面跳轉方式、使用React Router
- 最後解決方案與理由:使用React Router於App.tsx集中管理,擴充性較高且可以分享商品網址
### 議題 2:前端Api集中管理
- 議題內容:前後端整合過程中api修改出現問題
- 可能解決方案:使用axios管理、使用api.ts管理
- 最後解決方案與理由:後端產出swagger.json透過orval生成React前端可使用的組件,利於版本控制、自動管理。
### 議題 3:資料庫驗證使用者身分項目
- 議題內容:不須登入就能看到的api被身分驗證阻擋
- 可能解決方案:修改security config在permit all底下新增不需要驗證的api
- 最後解決方案與理由:修改security config在permit all底下新增不需要驗證的api
### 議題 4:購物車api
- 議題內容:前端覺得api/cart回傳的資訊太少了
- 可能解決方案:1.購物車只顯示商品id數量2.寫一個迴圈再去用商品id從新fetch商品詳細資訊3.修改資料結構
- 最後解決方案與理由:從新修改資料結構,因為這樣既能顯示全部資訊,又能省時間
### 其餘的放在Github issue中