feat: Extract hardcoded configs to environment variables

- Add environment variable configuration for backend and frontend
- Backend: DB_POOL_SIZE, JWT_EXPIRE_HOURS, timeout configs, directory paths
- Frontend: VITE_API_BASE_URL, VITE_UPLOAD_TIMEOUT, Whisper configs
- Create deployment script (scripts/deploy-backend.sh)
- Create 1Panel deployment guide (docs/1panel-deployment.md)
- Update DEPLOYMENT.md with env var documentation
- Create README.md with project overview
- Remove obsolete PRD.md, SDD.md, TDD.md (replaced by OpenSpec)
- Keep CORS allow_origins=["*"] for Electron EXE distribution

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
egg
2025-12-14 14:31:55 +08:00
parent 43c413c5ce
commit 01aee1fd0d
19 changed files with 1460 additions and 311 deletions

439
scripts/deploy-backend.sh Executable file
View File

@@ -0,0 +1,439 @@
#!/bin/bash
#
# Meeting Assistant Backend - Deployment Script
# 用於在 1Panel 或其他 Linux 服務器上部署後端服務
#
set -e
# 顏色定義
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 預設配置
DEFAULT_INSTALL_DIR="/opt/meeting-assistant"
DEFAULT_USER="meeting"
DEFAULT_PORT="8000"
# 函數:印出訊息
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[OK]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 函數:顯示幫助
show_help() {
echo ""
echo "Meeting Assistant Backend 部署腳本"
echo ""
echo "用法: $0 [命令] [選項]"
echo ""
echo "命令:"
echo " install 安裝後端服務"
echo " update 更新後端服務"
echo " uninstall 移除後端服務"
echo " status 顯示服務狀態"
echo " logs 顯示服務日誌"
echo " help 顯示此幫助訊息"
echo ""
echo "選項:"
echo " --dir DIR 安裝目錄 (預設: $DEFAULT_INSTALL_DIR)"
echo " --user USER 運行服務的用戶 (預設: $DEFAULT_USER)"
echo " --port PORT 服務端口 (預設: $DEFAULT_PORT)"
echo ""
echo "範例:"
echo " $0 install --port 8080"
echo " $0 update"
echo " $0 status"
echo ""
}
# 函數:檢查是否為 root
check_root() {
if [ "$EUID" -ne 0 ]; then
log_error "請使用 root 權限執行此腳本"
log_info "使用: sudo $0 $@"
exit 1
fi
}
# 函數:檢查依賴
check_dependencies() {
log_info "檢查系統依賴..."
local missing=()
# 檢查 Python 3.10+
if command -v python3 &> /dev/null; then
local py_version=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
log_success "Python: $py_version"
else
missing+=("python3")
fi
# 檢查 pip
if ! command -v pip3 &> /dev/null; then
missing+=("python3-pip")
fi
# 檢查 venv
if ! python3 -c "import venv" &> /dev/null 2>&1; then
missing+=("python3-venv")
fi
if [ ${#missing[@]} -gt 0 ]; then
log_error "缺少依賴: ${missing[*]}"
log_info "請先安裝: apt install ${missing[*]}"
exit 1
fi
log_success "所有依賴已滿足"
}
# 函數:創建系統用戶
create_user() {
local username=$1
if id "$username" &>/dev/null; then
log_info "用戶 $username 已存在"
else
log_info "創建系統用戶: $username"
useradd --system --no-create-home --shell /bin/false "$username"
log_success "用戶 $username 已創建"
fi
}
# 函數:安裝後端
install_backend() {
local install_dir=$1
local username=$2
local port=$3
log_info "開始安裝 Meeting Assistant Backend..."
log_info "安裝目錄: $install_dir"
log_info "服務用戶: $username"
log_info "服務端口: $port"
echo ""
# 檢查依賴
check_dependencies
# 創建用戶
create_user "$username"
# 創建目錄
log_info "創建安裝目錄..."
mkdir -p "$install_dir"
mkdir -p "$install_dir/logs"
mkdir -p "$install_dir/templates"
mkdir -p "$install_dir/records"
# 複製後端代碼
log_info "複製後端代碼..."
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local source_dir="$(dirname "$script_dir")/backend"
if [ ! -d "$source_dir" ]; then
log_error "找不到後端源碼目錄: $source_dir"
exit 1
fi
cp -r "$source_dir/app" "$install_dir/"
cp "$source_dir/requirements.txt" "$install_dir/"
# 複製 .env.example 如果 .env 不存在
if [ ! -f "$install_dir/.env" ]; then
if [ -f "$source_dir/.env.example" ]; then
cp "$source_dir/.env.example" "$install_dir/.env"
log_warn "已創建 .env 檔案,請編輯配置: $install_dir/.env"
fi
fi
# 複製模板檔案
if [ -d "$source_dir/templates" ]; then
cp -r "$source_dir/templates/"* "$install_dir/templates/" 2>/dev/null || true
fi
# 創建虛擬環境
log_info "創建 Python 虛擬環境..."
python3 -m venv "$install_dir/venv"
# 安裝依賴
log_info "安裝 Python 依賴..."
"$install_dir/venv/bin/pip" install --upgrade pip
"$install_dir/venv/bin/pip" install -r "$install_dir/requirements.txt"
# 更新 .env 中的端口配置
if [ -f "$install_dir/.env" ]; then
sed -i "s/^BACKEND_PORT=.*/BACKEND_PORT=$port/" "$install_dir/.env"
fi
# 設置權限
log_info "設置檔案權限..."
chown -R "$username:$username" "$install_dir"
chmod 750 "$install_dir"
chmod 640 "$install_dir/.env" 2>/dev/null || true
# 創建 systemd 服務
create_systemd_service "$install_dir" "$username" "$port"
# 啟動服務
log_info "啟動服務..."
systemctl daemon-reload
systemctl enable meeting-assistant-backend
systemctl start meeting-assistant-backend
# 等待啟動
sleep 3
# 檢查狀態
if systemctl is-active --quiet meeting-assistant-backend; then
log_success "Meeting Assistant Backend 安裝成功!"
echo ""
echo "=========================================="
echo " 安裝完成"
echo "=========================================="
echo ""
echo " 服務狀態: systemctl status meeting-assistant-backend"
echo " 查看日誌: journalctl -u meeting-assistant-backend -f"
echo " API 地址: http://localhost:$port"
echo " API 文件: http://localhost:$port/docs"
echo ""
echo " 配置檔案: $install_dir/.env"
echo " 請確保已正確配置數據庫和 API 密鑰"
echo ""
else
log_error "服務啟動失敗,請檢查日誌"
journalctl -u meeting-assistant-backend --no-pager -n 20
exit 1
fi
}
# 函數:創建 systemd 服務檔案
create_systemd_service() {
local install_dir=$1
local username=$2
local port=$3
log_info "創建 systemd 服務..."
cat > /etc/systemd/system/meeting-assistant-backend.service << EOF
[Unit]
Description=Meeting Assistant Backend API
After=network.target
[Service]
Type=simple
User=$username
Group=$username
WorkingDirectory=$install_dir
Environment="PATH=$install_dir/venv/bin"
EnvironmentFile=$install_dir/.env
ExecStart=$install_dir/venv/bin/uvicorn app.main:app --host 0.0.0.0 --port $port
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=$install_dir/logs $install_dir/records $install_dir/templates
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
log_success "systemd 服務已創建"
}
# 函數:更新後端
update_backend() {
local install_dir=$1
log_info "更新 Meeting Assistant Backend..."
if [ ! -d "$install_dir" ]; then
log_error "安裝目錄不存在: $install_dir"
exit 1
fi
# 停止服務
log_info "停止服務..."
systemctl stop meeting-assistant-backend || true
# 備份配置
log_info "備份配置..."
cp "$install_dir/.env" "$install_dir/.env.backup" 2>/dev/null || true
# 複製新代碼
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local source_dir="$(dirname "$script_dir")/backend"
log_info "更新代碼..."
rm -rf "$install_dir/app"
cp -r "$source_dir/app" "$install_dir/"
cp "$source_dir/requirements.txt" "$install_dir/"
# 更新依賴
log_info "更新依賴..."
"$install_dir/venv/bin/pip" install -r "$install_dir/requirements.txt"
# 恢復配置
if [ -f "$install_dir/.env.backup" ]; then
mv "$install_dir/.env.backup" "$install_dir/.env"
fi
# 重新設置權限
local username=$(stat -c '%U' "$install_dir")
chown -R "$username:$username" "$install_dir"
# 重啟服務
log_info "重啟服務..."
systemctl daemon-reload
systemctl start meeting-assistant-backend
sleep 2
if systemctl is-active --quiet meeting-assistant-backend; then
log_success "更新完成!"
else
log_error "服務重啟失敗"
exit 1
fi
}
# 函數:移除後端
uninstall_backend() {
local install_dir=$1
log_warn "即將移除 Meeting Assistant Backend"
read -p "確定要繼續嗎?(y/N) " confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
log_info "取消移除"
exit 0
fi
# 停止並禁用服務
log_info "停止服務..."
systemctl stop meeting-assistant-backend 2>/dev/null || true
systemctl disable meeting-assistant-backend 2>/dev/null || true
# 刪除 systemd 服務
log_info "移除 systemd 服務..."
rm -f /etc/systemd/system/meeting-assistant-backend.service
systemctl daemon-reload
# 詢問是否刪除數據
read -p "是否刪除安裝目錄 $install_dir(y/N) " delete_dir
if [ "$delete_dir" = "y" ] || [ "$delete_dir" = "Y" ]; then
log_info "刪除安裝目錄..."
rm -rf "$install_dir"
else
log_info "保留安裝目錄: $install_dir"
fi
log_success "Meeting Assistant Backend 已移除"
}
# 函數:顯示狀態
show_status() {
echo ""
echo "=========================================="
echo " Meeting Assistant Backend 狀態"
echo "=========================================="
echo ""
if systemctl is-active --quiet meeting-assistant-backend; then
log_success "服務狀態: 運行中"
systemctl status meeting-assistant-backend --no-pager | grep -E "(Active|Main PID|Memory|CPU)"
else
log_warn "服務狀態: 未運行"
fi
echo ""
}
# 函數:顯示日誌
show_logs() {
journalctl -u meeting-assistant-backend -f
}
# 解析參數
INSTALL_DIR=$DEFAULT_INSTALL_DIR
SERVICE_USER=$DEFAULT_USER
SERVICE_PORT=$DEFAULT_PORT
COMMAND=""
while [[ $# -gt 0 ]]; do
case $1 in
install|update|uninstall|status|logs|help)
COMMAND=$1
shift
;;
--dir)
INSTALL_DIR="$2"
shift 2
;;
--user)
SERVICE_USER="$2"
shift 2
;;
--port)
SERVICE_PORT="$2"
shift 2
;;
*)
log_error "未知參數: $1"
show_help
exit 1
;;
esac
done
# 執行命令
case $COMMAND in
install)
check_root
install_backend "$INSTALL_DIR" "$SERVICE_USER" "$SERVICE_PORT"
;;
update)
check_root
update_backend "$INSTALL_DIR"
;;
uninstall)
check_root
uninstall_backend "$INSTALL_DIR"
;;
status)
show_status
;;
logs)
show_logs
;;
help|"")
show_help
;;
*)
log_error "未知命令: $COMMAND"
show_help
exit 1
;;
esac