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:
439
scripts/deploy-backend.sh
Executable file
439
scripts/deploy-backend.sh
Executable 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
|
||||
Reference in New Issue
Block a user