- Configure Environment Variables
Rename the example environment file to active configuration:mv .env.example .env
- Start Services Launch the Docker containers:
docker compose up - Access the System
Open your browser and navigate to: http://localhost:8008
本專案使用 Django REST Framework 的 APITestCase 進行單元測試,並整合 Codecov 與 GitHub Actions 進行程式碼覆蓋率 (Code Coverage) 追蹤。
測試主要涵蓋以下核心邏輯:
- API Endpoints: 驗證
import-order與import-product的 HTTP 狀態碼與回應資料。 - Authentication: 測試 Token 驗證機制(Valid vs Invalid Token)。
- Business Logic: 驗證資料庫是否正確建立
Order與Product關聯。
本專案使用 GitHub Actions 進行自動化整合測試。當 Pull Request 建立或 Push 至 main 分支時,將觸發 ci-workflow。
流程包含以下步驟:
- Environment Setup: 在 Ubuntu 環境下建立 Python 3.12 虛擬環境,並安裝
requirements.txt。 - Quality Check: 使用 Pre-commit hooks 自動檢查程式碼格式和品質 (Linting)。
- Unit Testing: 使用
pytest執行單元測試,並搭配--cov參數生成 XML 格式的覆蓋率報告。 - Coverage Upload: 自動將測試覆蓋率報告 (
coverage.xml) 上傳至 Codecov。
- Endpoint:
POST /api/import-order/ - Feature: 匯入訂單
- Tags:
import-order - Request Body:
- Content Types:
application/json - Schema:
{ "products": [ { "product": { "uuid": "string", }, "quantity": 1, } ] }
- Content Types:
- Response
201: 成功建立- Schema:
OrderList{ "order_number": 1, "total_price": 100, "products": [ { "product": { "uuid": "string", "name": "string", "price": 100 }, "name": "string", "quantity": 1, "price": 100 } ] }
- Schema:
- Endpoint:
POST /api/import-product/ - Feature: 匯入商品
- Tags:
import-product - Request Body:
- Content Types:
application/json - Schema:
{ "name": "商品名稱", "price": 100 }
- Content Types:
- Response 201: 成功建立
- Schema:
Product{ "uuid": "string", "name": "商品名稱", "price": 100 }
- Schema:
- Endpoint:
GET /api/list-product/ - Feature: 取得所有商品列表
- Tags:
list-product - Response
200: 成功取得- Schema: 陣列
Product[ { "uuid": "string", "name": "商品名稱", "price": 100 } ]
- Schema: 陣列
- Snapshot Pattern
為了防止商品後續改名或調價影響歷史訂單紀錄,採用了 Snapshot Pattern
即使未來 Product 被修改或刪除(設為SET_NULL),使用者購買的歷史訂單的金額不會受影響,確保資料的完整性 - 寫入效能優化
在create_order的實作中,考量到批量建立訂單明細的效能:- 避免 N+1 Query:不使用迴圈逐筆查詢資料庫,而是先收集所有需要的 UUID,透過
get_product_uuid_map一次性撈取並轉為 Hash Map。
- 避免 N+1 Query:不使用迴圈逐筆查詢資料庫,而是先收集所有需要的 UUID,透過
- 資料庫鍵值設計策略
- Product (UUID):對外公開的商品資源使用 UUID,避免流水號被遍歷預測,提升安全性。
- Order (BigAutoField):內部訂單使用整數流水號,在後台管理與溝通上較為直觀,且索引效能較佳。
erDiagram
ORDER {
bigint order_number PK "訂單編號"
int total_price "訂單總價"
datetime created_at
datetime updated_at
}
PRODUCT {
uuid uuid PK "商品 UUID"
string name "商品名稱"
int price "商品價格"
datetime created_at
datetime updated_at
}
PRODUCTSNAPSHOT {
int id PK
int order_id FK "訂單"
uuid product_id FK "商品 (nullable)"
string product_name "商品名稱 (snapshot)"
int price "商品價格 (snapshot)"
int quantity "商品數量"
datetime created_at
datetime updated_at
}
ORDER ||--o{ PRODUCTSNAPSHOT : contains
PRODUCT ||--o{ PRODUCTSNAPSHOT : snapshot_of