This commit is contained in:
beabigegg
2025-09-01 11:17:09 +08:00
parent 8185b609f7
commit 22a231d78c
7 changed files with 1087 additions and 350 deletions

View File

@@ -1,11 +1,11 @@
# 暫時規範管理系統 V3 - 開發者最佳實踐指南
# PANJIT To-Do System - 開發者最佳實踐指南
> **⚠️ 重要提醒**:本文件包含敏感的系統配置和最佳實踐資訊,僅供開發團隊內部使用。
> 此文件已在 .gitignore 中排除,請勿提交至版本控制系統。
## 🎯 文件目的
本文件記錄在開發暫時規範管理系統 V3 過程中遇到的技術難點及最佳解決方案,避免後續開發者重複踩坑。
本文件記錄在開發 PANJIT To-Do System 過程中遇到的技術難點及最佳解決方案包含前後端整合、資料庫設計、LDAP整合、郵件系統等關鍵技術決策,避免後續開發者重複踩坑。
---
@@ -541,18 +541,549 @@ tar -czf uploads_${DATE}.tar.gz uploads/
---
---
## 🎨 前端開發最佳實踐
### 1. Next.js + TypeScript 架構
**關鍵發現**App Router 架構提供更好的開發體驗和效能。
#### 推薦的專案結構
```
frontend/src/
├── app/ # Next.js 13+ App Router
│ ├── (auth)/ # Route Groups
│ ├── dashboard/ # Dashboard 路由
│ ├── todos/ # 待辦事項頁面
│ ├── layout.tsx # 根版面
│ └── page.tsx # 首頁
├── components/ # React 組件
│ ├── layout/ # 版面組件
│ ├── todos/ # 待辦事項組件
│ └── ui/ # 通用 UI 組件
├── lib/ # 工具函數
├── store/ # Redux 狀態管理
├── types/ # TypeScript 類型定義
└── providers/ # Context Providers
```
#### TypeScript 最佳實踐
```typescript
// types/todo.ts - 完整的類型定義
export interface TodoItem {
id: string;
title: string;
description?: string;
status: 'NEW' | 'DOING' | 'BLOCKED' | 'DONE';
priority: 'LOW' | 'MEDIUM' | 'HIGH' | 'URGENT';
due_date?: string;
created_at: string;
creator_ad: string;
starred: boolean;
is_public: boolean;
tags: string[];
responsible_users: string[];
followers: string[];
}
// API 回應類型
export interface ApiResponse<T> {
data: T;
message?: string;
total?: number;
}
```
### 2. Material-UI 整合
**關鍵發現**:主題系統和組件客制化是關鍵。
#### 主題設計
```typescript
// providers/ThemeProvider.tsx
import { createTheme, ThemeProvider } from '@mui/material/styles';
const lightTheme = createTheme({
palette: {
mode: 'light',
primary: {
main: '#3b82f6', // 藍色主題
},
secondary: {
main: '#10b981', // 綠色輔助
},
},
typography: {
fontFamily: '"Noto Sans TC", "Roboto", sans-serif',
},
});
const darkTheme = createTheme({
palette: {
mode: 'dark',
primary: {
main: '#60a5fa',
},
background: {
default: '#0f172a',
paper: '#1e293b',
},
},
});
```
#### 響應式設計
```typescript
// hooks/useResponsive.ts
import { useTheme, useMediaQuery } from '@mui/material';
export const useResponsive = () => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const isTablet = useMediaQuery(theme.breakpoints.between('md', 'lg'));
const isDesktop = useMediaQuery(theme.breakpoints.up('lg'));
return { isMobile, isTablet, isDesktop };
};
```
### 3. 狀態管理策略
**關鍵發現**Redux Toolkit + React Query 組合提供最佳的開發體驗。
#### Redux Store 設計
```typescript
// store/todoSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
interface TodoState {
filterMode: 'all' | 'created' | 'responsible' | 'following';
appliedFilters: TodoFilters;
selectedItems: string[];
viewMode: 'list' | 'card' | 'calendar';
}
const todoSlice = createSlice({
name: 'todo',
initialState,
reducers: {
setFilterMode: (state, action: PayloadAction<FilterMode>) => {
state.filterMode = action.payload;
},
toggleSelectItem: (state, action: PayloadAction<string>) => {
const id = action.payload;
if (state.selectedItems.includes(id)) {
state.selectedItems = state.selectedItems.filter(item => item !== id);
} else {
state.selectedItems.push(id);
}
},
},
});
```
#### React Query 集成
```typescript
// lib/api/todos.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
export const useTodos = (filters: TodoFilters) => {
return useQuery({
queryKey: ['todos', filters],
queryFn: () => fetchTodos(filters),
staleTime: 30000, // 30秒內數據視為新鮮
});
};
export const useCreateTodo = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createTodo,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] });
toast.success('待辦事項建立成功!');
},
onError: (error) => {
toast.error(error.message || '建立失敗');
},
});
};
```
---
## 🔄 後端 API 設計最佳實踐
### 1. Flask 應用架構
**關鍵發現**Blueprint 和工廠模式提供最佳的可維護性。
#### 應用程式工廠模式
```python
# app.py - 推薦的應用程式結構
def create_app(config_name=None):
if config_name is None:
config_name = os.environ.get('FLASK_ENV', 'development')
app = Flask(__name__)
app.config.from_object(config[config_name])
# 初始化擴展
db.init_app(app)
migrate.init_app(app, db)
jwt.init_app(app)
mail.init_app(app)
CORS(app, origins=app.config['CORS_ORIGINS'])
# 註冊 Blueprint
from routes import register_blueprints
register_blueprints(app)
# 設定錯誤處理
setup_error_handlers(app)
return app
```
#### RESTful API 設計
```python
# routes/todos.py - 標準化的 API 結構
@todos_bp.route('', methods=['GET'])
@jwt_required()
def get_todos():
try:
# 參數驗證
page = request.args.get('page', 1, type=int)
per_page = min(request.args.get('per_page', 20, type=int), 100)
# 業務邏輯
todos, total = todo_service.get_user_todos(
user_ad=get_jwt_identity(),
page=page,
per_page=per_page,
filters=request.args
)
# 統一回應格式
return jsonify({
'data': [todo.to_dict() for todo in todos],
'pagination': {
'page': page,
'per_page': per_page,
'total': total,
'pages': (total + per_page - 1) // per_page
}
}), 200
except ValidationError as e:
return jsonify({'error': str(e)}), 400
except Exception as e:
logger.error(f"Error getting todos: {str(e)}")
return jsonify({'error': 'Internal server error'}), 500
```
### 2. 資料驗證策略
**關鍵發現**:輸入驗證和序列化分離提供更好的可維護性。
```python
# validators/todo.py
from marshmallow import Schema, fields, validate
class CreateTodoSchema(Schema):
title = fields.Str(required=True, validate=validate.Length(min=1, max=200))
description = fields.Str(missing=None, validate=validate.Length(max=2000))
status = fields.Str(missing='NEW', validate=validate.OneOf(['NEW', 'DOING', 'BLOCKED', 'DONE']))
priority = fields.Str(missing='MEDIUM', validate=validate.OneOf(['LOW', 'MEDIUM', 'HIGH', 'URGENT']))
due_date = fields.Date(missing=None)
responsible_users = fields.List(fields.Str(), missing=list)
followers = fields.List(fields.Str(), missing=list)
tags = fields.List(fields.Str(), missing=list)
is_public = fields.Bool(missing=False)
starred = fields.Bool(missing=False)
# 使用裝飾器進行驗證
def validate_json(schema):
def decorator(f):
def wrapper(*args, **kwargs):
try:
data = schema.load(request.json or {})
return f(data, *args, **kwargs)
except ValidationError as e:
return jsonify({'error': e.messages}), 400
return wrapper
return decorator
@todos_bp.route('', methods=['POST'])
@jwt_required()
@validate_json(CreateTodoSchema())
def create_todo(data):
# 已驗證的資料直接使用
todo = todo_service.create_todo(
creator_ad=get_jwt_identity(),
**data
)
return jsonify({'data': todo.to_dict()}), 201
```
### 3. 服務層架構
**關鍵發現**:業務邏輯分離到服務層提供更好的測試性。
```python
# services/todo_service.py
class TodoService:
def __init__(self):
self.logger = get_logger(__name__)
def create_todo(self, creator_ad: str, **kwargs) -> TodoItem:
"""建立新的待辦事項"""
try:
# 驗證負責人帳號
if kwargs.get('responsible_users'):
valid_users = validate_ad_accounts(kwargs['responsible_users'])
if len(valid_users) != len(kwargs['responsible_users']):
invalid_users = set(kwargs['responsible_users']) - set(valid_users.keys())
raise ValidationError(f"無效的負責人帳號: {', '.join(invalid_users)}")
# 建立待辦事項
todo = TodoItem(
title=kwargs['title'],
description=kwargs.get('description'),
status=kwargs.get('status', 'NEW'),
priority=kwargs.get('priority', 'MEDIUM'),
due_date=kwargs.get('due_date'),
creator_ad=creator_ad,
is_public=kwargs.get('is_public', False),
starred=kwargs.get('starred', False),
tags=kwargs.get('tags', [])
)
# 設定使用者資訊
user_info = get_user_info(creator_ad)
if user_info:
todo.creator_display_name = user_info['display_name']
todo.creator_email = user_info['email']
db.session.add(todo)
db.session.flush() # 取得 ID
# 新增負責人和追蹤者
self._add_users_to_todo(todo.id, kwargs.get('responsible_users', []), 'responsible')
self._add_users_to_todo(todo.id, kwargs.get('followers', []), 'follower')
db.session.commit()
# 發送通知
self._send_assignment_notifications(todo)
# 記錄稽核日誌
self._log_audit(todo.id, creator_ad, 'CREATE', '建立待辦事項')
return todo
except Exception as e:
db.session.rollback()
self.logger.error(f"Error creating todo: {str(e)}")
raise
```
---
## 📊 Excel 處理最佳實踐
### 1. 安全的檔案處理
**關鍵發現**:檔案上傳和處理需要多層驗證。
```python
# utils/excel_utils.py
import pandas as pd
from openpyxl import load_workbook
import tempfile
import os
class ExcelProcessor:
ALLOWED_EXTENSIONS = {'.xlsx', '.xls', '.csv'}
MAX_FILE_SIZE = 16 * 1024 * 1024 # 16MB
MAX_ROWS = 10000
def validate_file(self, file):
"""檔案安全驗證"""
# 檔案大小檢查
if len(file.read()) > self.MAX_FILE_SIZE:
raise ValidationError("檔案大小超過限制 (16MB)")
file.seek(0) # 重置檔案指針
# 檔案類型檢查
filename = secure_filename(file.filename)
if not any(filename.lower().endswith(ext) for ext in self.ALLOWED_EXTENSIONS):
raise ValidationError("不支援的檔案格式")
return filename
def parse_excel_file(self, file):
"""安全的 Excel 解析"""
try:
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
file.save(temp_file.name)
# 使用 pandas 讀取檔案
if temp_file.name.endswith('.csv'):
df = pd.read_csv(temp_file.name, encoding='utf-8')
else:
df = pd.read_excel(temp_file.name)
# 行數限制
if len(df) > self.MAX_ROWS:
raise ValidationError(f"資料列數超過限制 ({self.MAX_ROWS})")
return self.validate_and_transform_data(df)
finally:
# 清理暫存檔案
if 'temp_file' in locals():
os.unlink(temp_file.name)
def validate_and_transform_data(self, df):
"""資料驗證和轉換"""
required_columns = ['標題', '負責人']
missing_columns = [col for col in required_columns if col not in df.columns]
if missing_columns:
raise ValidationError(f"缺少必要欄位: {', '.join(missing_columns)}")
validated_data = []
errors = []
for index, row in df.iterrows():
try:
todo_data = self.validate_row(row, index + 2) # +2 因為標題行
validated_data.append(todo_data)
except ValidationError as e:
errors.append(f"第 {index + 2} 行: {str(e)}")
return {
'data': validated_data,
'errors': errors,
'total': len(df)
}
```
### 2. 模板生成
**關鍵發現**:動態模板生成提供更好的使用者體驗。
```python
# routes/excel.py
@excel_bp.route('/template', methods=['GET'])
@jwt_required()
def download_template():
"""生成並下載 Excel 匯入模板"""
try:
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment
from openpyxl.worksheet.datavalidation import DataValidation
wb = Workbook()
ws = wb.active
ws.title = "待辦事項匯入模板"
# 標題行
headers = [
'標題*', '描述', '狀態', '優先級',
'到期日', '負責人*', '追蹤人員', '標籤', '備註'
]
# 設定標題樣式
title_font = Font(bold=True, color='FFFFFF')
title_fill = PatternFill(start_color='366092', end_color='366092', fill_type='solid')
for col, header in enumerate(headers, 1):
cell = ws.cell(row=1, column=col, value=header)
cell.font = title_font
cell.fill = title_fill
cell.alignment = Alignment(horizontal='center')
# 資料驗證
status_validation = DataValidation(
type="list",
formula1='"NEW,DOING,BLOCKED,DONE"',
showErrorMessage=True,
errorTitle="狀態錯誤",
error="請選擇: NEW, DOING, BLOCKED, DONE"
)
priority_validation = DataValidation(
type="list",
formula1='"LOW,MEDIUM,HIGH,URGENT"',
showErrorMessage=True,
errorTitle="優先級錯誤",
error="請選擇: LOW, MEDIUM, HIGH, URGENT"
)
ws.add_data_validation(status_validation)
ws.add_data_validation(priority_validation)
status_validation.add(f'C2:C{MAX_ROWS}')
priority_validation.add(f'D2:D{MAX_ROWS}')
# 範例資料
sample_data = [
['完成月報撰寫', '包含各部門數據統計和分析', 'NEW', 'HIGH', '2024/01/15', 'user1', 'manager1', '報告,月度', '請於期限內完成'],
['系統維護檢查', '定期檢查伺服器狀態', 'DOING', 'MEDIUM', '2024/01/20', 'user2', 'user1,user3', 'IT,維護', ''],
]
for row, data in enumerate(sample_data, 2):
for col, value in enumerate(data, 1):
ws.cell(row=row, column=col, value=value)
# 調整欄寬
column_widths = [20, 30, 12, 12, 12, 15, 20, 15, 20]
for col, width in enumerate(column_widths, 1):
ws.column_dimensions[ws.cell(row=1, column=col).column_letter].width = width
# 生成檔案
from io import BytesIO
output = BytesIO()
wb.save(output)
output.seek(0)
return send_file(
output,
as_attachment=True,
download_name=f'todo_import_template_{datetime.now().strftime("%Y%m%d")}.xlsx',
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
except Exception as e:
logger.error(f"Error generating template: {str(e)}")
return jsonify({'error': '模板生成失敗'}), 500
```
---
## 📝 總結
本文件記錄了開發暫時規範管理系統 V3 過程中的關鍵技術決策和最佳實踐。這些經驗可以幫助後續開發者:
本文件記錄了開發 PANJIT To-Do System 過程中的關鍵技術決策和最佳實踐。這些經驗可以幫助後續開發者:
1. **避免常見陷阱**:特別是 LDAP 配置和 SMTP 設定
2. **提升開發效率**:使用經過驗證的架構模式
3. **確保系統穩定性**:採用完整的錯誤處理和監控機制
4. **簡化部署流程**:使用 Docker 和自動化腳本
1. **避免常見陷阱**:特別是 LDAP 配置、前後端整合、Excel 處理
2. **提升開發效率**:使用經過驗證的架構模式和工具鏈
3. **確保程式碼品質**:遵循 TypeScript、Python 最佳實踐
4. **提升使用者體驗**:響應式設計、效能優化、錯誤處理
5. **簡化維護工作**:清晰的架構分離、完整的日誌記錄
**重要技術決策總結**
- **前端**Next.js 14 App Router + TypeScript + Material-UI + Redux Toolkit
- **後端**Flask + SQLAlchemy + Celery + Redis + JWT
- **資料庫**MySQL 8.0 + 適當索引設計
- **部署**Docker + Nginx + 健康檢查
**重要提醒**:本文件包含敏感資訊,請勿外洩或提交至公開版本控制系統。
---
*最後更新2025年1月*
*文件版本V1.0*
*文件版本V2.0*
*適用系統PANJIT To-Do System v1.0*