Files
TODO_list_system/BEST_PRACTICES.md
beabigegg b0c86302ff 1ST
2025-08-29 16:25:46 +08:00

558 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 暫時規範管理系統 V3 - 開發者最佳實踐指南
> **⚠️ 重要提醒**:本文件包含敏感的系統配置和最佳實踐資訊,僅供開發團隊內部使用。
> 此文件已在 .gitignore 中排除,請勿提交至版本控制系統。
## 🎯 文件目的
本文件記錄在開發暫時規範管理系統 V3 過程中遇到的技術難點及最佳解決方案,避免後續開發者重複踩坑。
---
## 🔐 LDAP/Active Directory 整合最佳實踐
### 1. LDAP 連接配置
**關鍵發現**LDAP 連接的穩定性很大程度取決於正確的配置參數組合。
#### 正確的配置模式
```python
# config.py - 推薦配置
LDAP_SERVER = "ldap://dc.company.com" # 或使用 IP
LDAP_PORT = 389 # 標準 LDAP port
LDAP_USE_SSL = False # 內網環境通常不需要 SSL
LDAP_SEARCH_BASE = "DC=company,DC=com"
LDAP_BIND_USER_DN = "CN=ServiceAccount,OU=ServiceAccounts,DC=company,DC=com"
LDAP_USER_LOGIN_ATTR = "userPrincipalName" # AD 環境必須使用此屬性
```
#### 常見錯誤及解決方案
**錯誤 1**:使用 `sAMAccountName` 作為登入屬性
```python
# ❌ 錯誤做法
LDAP_USER_LOGIN_ATTR = "sAMAccountName"
# ✅ 正確做法
LDAP_USER_LOGIN_ATTR = "userPrincipalName"
```
**錯誤 2**:服務帳號權限不足
```python
# 服務帳號至少需要以下權限:
# - Read permission on the search base
# - List Contents permission
# - Read All Properties permission
```
### 2. LDAP 搜尋最佳化
**關鍵發現**:正確的搜尋篩選器可以大幅提升效能並避免權限問題。
#### 用戶搜尋最佳實踐
```python
# ldap_utils.py - 優化後的搜尋篩選器
def search_ldap_principals(search_term):
# 多屬性搜尋,提高命中率
search_filter = f"""
(&
(objectClass=person)
(objectCategory=person)
(!(userAccountControl:1.2.840.113556.1.4.803:=2)) # 排除已停用帳號
(|
(displayName=*{search_term}*)
(mail=*{search_term}*)
(sAMAccountName=*{search_term}*)
(userPrincipalName=*{search_term}*)
)
)
"""
```
**關鍵技巧**
1. 使用 `objectCategory=person` 而不是只用 `objectClass=user`
2. 排除停用帳號避免無效結果
3. 多屬性搜尋提高使用者體驗
4. 限制搜尋結果數量避免效能問題
#### 群組搜尋最佳實踐
```python
# 同時支援 AD 群組和 OU
def get_ldap_group_members(group_name):
# 先嘗試搜尋 AD 群組
group_filter = f"(&(objectClass=group)(cn={group_name}))"
# 如果找不到群組,嘗試搜尋 OU
if not found:
ou_filter = f"(&(objectClass=organizationalUnit)(name=*{group_name}*))"
```
### 3. LDAP 連接穩定性
**關鍵發現**:連接池和重試機制對生產環境至關重要。
```python
# ldap_utils.py - 連接重試機制
def create_ldap_connection(retries=3):
for attempt in range(retries):
try:
server = Server(ldap_server, port=ldap_port, use_ssl=use_ssl)
conn = Connection(server, user=bind_dn, password=bind_password, auto_bind=True)
return conn
except Exception as e:
if attempt == retries - 1:
raise e
time.sleep(1) # 短暫等待後重試
```
---
## 📧 SMTP 郵件系統最佳實踐
### 1. 多種 SMTP 配置支援
**關鍵發現**:企業環境中可能遇到多種 SMTP 配置需求,系統必須具備彈性。
#### 配置架構設計
```python
# config.py - 彈性 SMTP 配置
class Config:
SMTP_SERVER = os.getenv('SMTP_SERVER', 'mail.company.com')
SMTP_PORT = int(os.getenv('SMTP_PORT', 25))
SMTP_USE_TLS = os.getenv('SMTP_USE_TLS', 'false').lower() in ['true', '1', 't']
SMTP_USE_SSL = os.getenv('SMTP_USE_SSL', 'false').lower() in ['true', '1', 't']
SMTP_AUTH_REQUIRED = os.getenv('SMTP_AUTH_REQUIRED', 'false').lower() in ['true', '1', 't']
SMTP_SENDER_EMAIL = os.getenv('SMTP_SENDER_EMAIL', 'temp-spec-system@company.com')
SMTP_SENDER_PASSWORD = os.getenv('SMTP_SENDER_PASSWORD', '')
```
#### 智能連接邏輯
```python
# utils.py - 智能 SMTP 連接
def send_email(to_addrs, subject, body):
# 根據 port 和配置自動選擇連接方式
if use_ssl and smtp_port == 465:
server = smtplib.SMTP_SSL(smtp_server, smtp_port)
else:
server = smtplib.SMTP(smtp_server, smtp_port)
if use_tls and smtp_port == 587:
server.starttls()
# 只在需要認證時才登入
if auth_required and sender_password:
server.login(sender_email, sender_password)
```
### 2. 郵件發送可靠性
**關鍵發現**:詳細的日誌和錯誤處理對於診斷郵件問題至關重要。
```python
# utils.py - 完整的錯誤處理
def send_email(to_addrs, subject, body):
try:
# ... 發送邏輯 ...
result = server.sendmail(sender_email, to_addrs, msg.as_string())
# 檢查發送結果
if result:
# 某些收件者失敗
print(f"[EMAIL WARNING] 部分收件者發送失敗: {result}")
else:
print(f"[EMAIL SUCCESS] 郵件成功發送至: {', '.join(to_addrs)}")
return True
except smtplib.SMTPAuthenticationError as e:
print(f"[EMAIL ERROR] SMTP 認證失敗: {e}")
return False
except smtplib.SMTPConnectError as e:
print(f"[EMAIL ERROR] SMTP 連接失敗: {e}")
return False
# ... 其他異常處理 ...
```
### 3. 郵件內容最佳化
**關鍵發現**HTML 格式郵件必須考慮各種郵件客戶端的相容性。
```python
# 推薦的 HTML 郵件格式
def create_email_body(spec, action):
body = f"""
<html>
<head>
<meta charset="utf-8">
<style>
body {{ font-family: Arial, sans-serif; }}
.header {{ color: #2c3e50; border-bottom: 2px solid #3498db; }}
.content {{ margin: 20px 0; }}
.highlight {{ background-color: #f8f9fa; padding: 10px; }}
</style>
</head>
<body>
<div class="header">
<h2>[暫規通知] 規範 '{spec.spec_code}' 已{action}</h2>
</div>
<div class="content">
<p>您好,</p>
<!-- 內容... -->
</div>
</body>
</html>
"""
return body
```
---
## 🗄️ 資料庫設計最佳實踐
### 1. 資料庫遷移策略
**關鍵發現**:平滑的資料庫升級對於生產環境至關重要。
#### 遷移腳本模板
```python
# migrate_*.py - 標準遷移腳本結構
def migrate_database():
engine = create_engine(Config.SQLALCHEMY_DATABASE_URI)
try:
with engine.connect() as conn:
# 檢查是否已經遷移
result = conn.execute(text("""
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'table_name' AND COLUMN_NAME = 'new_column'
AND TABLE_SCHEMA = DATABASE()
"""))
if result.fetchone():
print("✓ 遷移已完成,無需重複執行")
return True
# 執行遷移
conn.execute(text("ALTER TABLE table_name ADD COLUMN new_column TYPE"))
conn.commit()
# 驗證遷移結果
# ...
except Exception as e:
print(f"✗ 遷移失敗:{str(e)}")
return False
```
### 2. 資料模型設計
**關鍵發現**:適當的索引和關聯設計可以大幅提升查詢效能。
```python
# models.py - 最佳實踐
class TempSpec(db.Model):
__tablename__ = 'ts_temp_spec'
# 主鍵
id = db.Column(db.Integer, primary_key=True)
# 業務鍵,建立索引
spec_code = db.Column(db.String(20), nullable=False, index=True)
# 常用查詢欄位,建立索引
status = db.Column(db.Enum(...), nullable=False, index=True)
end_date = db.Column(db.Date, index=True) # 用於到期查詢
# 新功能擴展欄位
notification_emails = db.Column(db.Text, nullable=True)
# 正確的關聯設置
uploads = db.relationship('Upload', back_populates='spec',
cascade='all, delete-orphan')
```
---
## 🔄 Flask 應用架構最佳實踐
### 1. 藍圖Blueprint組織
**關鍵發現**:良好的模組分離有助於維護和擴展。
```python
# 推薦的路由組織結構
routes/
├── __init__.py # 藍圖註冊
├── auth.py # 認證相關
├── api.py # API 介面
├── temp_spec.py # 核心業務邏輯
├── admin.py # 管理功能
└── upload.py # 檔案處理
```
### 2. 錯誤處理策略
```python
# app.py - 全局錯誤處理
@app.errorhandler(403)
def forbidden(error):
return render_template('403.html'), 403
@app.errorhandler(404)
def not_found(error):
return render_template('404.html'), 404
@app.errorhandler(500)
def internal_error(error):
db.session.rollback()
return render_template('500.html'), 500
```
### 3. 配置管理
```python
# config.py - 環境配置分離
class DevelopmentConfig(Config):
DEBUG = True
TESTING = False
class ProductionConfig(Config):
DEBUG = False
TESTING = False
# 生產環境特定設定
class TestingConfig(Config):
TESTING = True
# 測試環境設定
```
---
## 🏗️ 前端整合最佳實踐
### 1. ONLYOFFICE 整合要點
**關鍵發現**Docker 環境下的網路配置是最大的挑戰。
```python
# routes/temp_spec.py - URL 修正邏輯
def edit_spec(spec_id):
doc_url = get_file_uri(doc_filename)
callback_url = url_for('temp_spec.onlyoffice_callback', spec_id=spec_id, _external=True)
# Docker 環境 URL 修正
if '127.0.0.1' in doc_url or 'localhost' in doc_url:
doc_url = doc_url.replace('127.0.0.1', 'host.docker.internal')
doc_url = doc_url.replace('localhost', 'host.docker.internal')
callback_url = callback_url.replace('127.0.0.1', 'host.docker.internal')
callback_url = callback_url.replace('localhost', 'host.docker.internal')
```
### 2. 前端元件最佳化
**關鍵發現**Tom Select 元件需要正確配置才能提供良好的使用者體驗。
```javascript
// 推薦的 Tom Select 配置
const recipientSelect = new TomSelect('#recipients', {
valueField: 'value',
labelField: 'text',
searchField: 'text',
placeholder: '請輸入姓名或 Email 來搜尋...',
plugins: ['remove_button'],
maxItems: null,
create: false,
load: function(query, callback) {
if (!query || query.length < 2) {
callback();
return;
}
// 實作搜尋邏輯...
}
});
```
---
## 🚀 部署最佳實踐
### 1. Docker 配置優化
```yaml
# docker-compose.yml - 生產環境配置
version: '3.8'
services:
app:
build: .
environment:
- FLASK_ENV=production
- PYTHONUNBUFFERED=1
volumes:
- ./uploads:/app/uploads
- ./logs:/app/logs
restart: unless-stopped
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_NAME}
volumes:
- mysql_data:/var/lib/mysql
restart: unless-stopped
volumes:
mysql_data:
```
### 2. 日誌管理
```python
# app.py - 生產環境日誌配置
if not app.debug:
if not os.path.exists('logs'):
os.mkdir('logs')
file_handler = RotatingFileHandler('logs/tempspec.log',
maxBytes=10240000, backupCount=10)
file_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
))
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
```
### 3. 安全性配置
```python
# 推薦的安全標頭設置
@app.after_request
def after_request(response):
response.headers['X-Content-Type-Options'] = 'nosniff'
response.headers['X-Frame-Options'] = 'DENY'
response.headers['X-XSS-Protection'] = '1; mode=block'
return response
```
---
## 🐛 除錯與監控
### 1. 開發階段除錯
```python
# 推薦的除錯配置
DEBUG_LDAP = os.getenv('DEBUG_LDAP', 'false').lower() == 'true'
DEBUG_EMAIL = os.getenv('DEBUG_EMAIL', 'false').lower() == 'true'
DEBUG_DATABASE = os.getenv('DEBUG_DATABASE', 'false').lower() == 'true'
def debug_log(category, message):
if category == 'ldap' and DEBUG_LDAP:
print(f"[LDAP DEBUG] {message}")
elif category == 'email' and DEBUG_EMAIL:
print(f"[EMAIL DEBUG] {message}")
# ...
```
### 2. 生產環境監控
```python
# tasks.py - 健康檢查任務
@scheduler.task('cron', id='health_check', hour='*/1')
def health_check():
try:
# 檢查資料庫連接
db.session.execute(text('SELECT 1'))
# 檢查 LDAP 連接
test_ldap_connection()
# 檢查 SMTP 連接
test_smtp_connection()
app.logger.info("Health check passed")
except Exception as e:
app.logger.error(f"Health check failed: {e}")
```
---
## 📊 效能優化要點
### 1. 資料庫查詢優化
```python
# 推薦的查詢模式
def get_active_specs_expiring_soon():
return TempSpec.query.filter(
TempSpec.status == 'active',
TempSpec.end_date <= datetime.now().date() + timedelta(days=7)
).options(
joinedload(TempSpec.uploads) # 預載關聯資料
).all()
```
### 2. 快取策略
```python
# 推薦使用 Flask-Caching
from flask_caching import Cache
cache = Cache(app, config={'CACHE_TYPE': 'simple'})
@cache.memoize(timeout=300) # 5分鐘快取
def get_ldap_group_members(group_name):
# LDAP 查詢邏輯...
```
---
## 🔧 維護與升級
### 1. 版本控制策略
```bash
# 推薦的版本標籤格式
git tag v3.2.0-rc1 # 發布候選版本
git tag v3.2.0 # 正式版本
git tag v3.2.1 # 修正版本
```
### 2. 備份策略
```bash
#!/bin/bash
# backup.sh - 定期備份腳本
DATE=$(date +%Y%m%d_%H%M%S)
# 資料庫備份
mysqldump -u $DB_USER -p$DB_PASSWORD $DB_NAME > backup_${DATE}.sql
# 檔案備份
tar -czf uploads_${DATE}.tar.gz uploads/
```
---
## 📝 總結
本文件記錄了開發暫時規範管理系統 V3 過程中的關鍵技術決策和最佳實踐。這些經驗可以幫助後續開發者:
1. **避免常見陷阱**:特別是 LDAP 配置和 SMTP 設定
2. **提升開發效率**:使用經過驗證的架構模式
3. **確保系統穩定性**:採用完整的錯誤處理和監控機制
4. **簡化部署流程**:使用 Docker 和自動化腳本
**重要提醒**:本文件包含敏感資訊,請勿外洩或提交至公開版本控制系統。
---
*最後更新2025年1月*
*文件版本V1.0*