- Add .NET 8 backend with Clean Architecture - Add React + Vite + TypeScript frontend - Implement authentication with JWT - Implement Azure Blob Storage client - Implement OCR integration - Implement supplier matching service - Implement voucher generation - Implement Fortnox provider - Add unit and integration tests - Add Docker Compose configuration
854 lines
27 KiB
Markdown
854 lines
27 KiB
Markdown
# Invoice Master - 部署指南
|
|
|
|
**版本**: v3.0
|
|
**目标平台**: Azure
|
|
**运行时**: .NET 8
|
|
**日期**: 2026-02-03
|
|
|
|
---
|
|
|
|
## 1. 架构概览
|
|
|
|
### 1.1 多会计系统架构部署图
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
│ Azure Sweden Central │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ Azure Container Apps Environment │ │
|
|
│ │ │ │
|
|
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌───────────────┐ │ │
|
|
│ │ │ Frontend App │ │ Backend API │ │ Worker │ │ │
|
|
│ │ │ (Static Web) │ │ (FastAPI) │ │ (Background) │ │ │
|
|
│ │ │ │ │ │ │ │ │ │
|
|
│ │ │ Vercel/Azure │ │ CPU: 1 vCPU │ │ CPU: 0.5 │ │ │
|
|
│ │ │ Static Web │ │ Memory: 2 GiB │ │ Memory: 1GiB │ │ │
|
|
│ │ │ │ │ Replicas: 1-5 │ │ Replicas: 1-3│ │ │
|
|
│ │ └─────────────────┘ └─────────────────┘ └───────────────┘ │ │
|
|
│ │ │ │
|
|
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
|
|
│ │ │ Azure Application Gateway (WAF) │ │ │
|
|
│ │ │ SSL Termination │ │ │
|
|
│ │ └─────────────────────────────────────────────────────────────┘ │ │
|
|
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │
|
|
│ │ PostgreSQL Flexible │ │ Azure Cache for Redis │ │
|
|
│ │ Server │ │ │ │
|
|
│ │ - SKU: Standard_B1ms │ │ - SKU: Basic C1 │ │
|
|
│ │ - Storage: 32 GB │ │ - Memory: 1 GB │ │
|
|
│ │ - Backup: 7 days │ │ │ │
|
|
│ │ - accounting_ │ │ - Multi-provider cache │ │
|
|
│ │ connections table │ │ │ │
|
|
│ └─────────────────────────┘ └─────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ Azure Blob Storage │ │
|
|
│ │ - Tier: Hot │ │
|
|
│ │ - Redundancy: LRS │ │
|
|
│ │ - Invoice PDFs (multi-tenant) │ │
|
|
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ Azure Key Vault │ │
|
|
│ │ - Encryption Keys │ │
|
|
│ │ - Fortnox Client Credentials │ │
|
|
│ │ - Visma Client Credentials (future) │ │
|
|
│ │ - Hogia Client Credentials (future) │ │
|
|
│ │ - Provider-specific configs │ │
|
|
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 1.2 多会计系统配置
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Key Vault Secrets Structure │
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ Global Secrets: │
|
|
│ ├── jwt-secret │
|
|
│ ├── encryption-key │
|
|
│ ├── db-password │
|
|
│ └── ocr-api-key │
|
|
│ │
|
|
│ Provider-Specific Secrets: │
|
|
│ ├── fortnox-client-id │
|
|
│ ├── fortnox-client-secret │
|
|
│ ├── fortnox-redirect-uri │
|
|
│ ├── visma-client-id (future) │
|
|
│ ├── visma-client-secret (future) │
|
|
│ └── visma-redirect-uri (future) │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 2. 前置要求
|
|
|
|
### 2.1 工具安装
|
|
|
|
```bash
|
|
# Azure CLI
|
|
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
|
|
|
|
# Terraform
|
|
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
|
|
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
|
|
sudo apt update && sudo apt install terraform
|
|
|
|
# kubectl (可选)
|
|
az aks install-cli
|
|
```
|
|
|
|
### 2.2 Azure 登录
|
|
|
|
```bash
|
|
# 登录 Azure
|
|
az login
|
|
|
|
# 设置订阅
|
|
az account set --subscription "Your Subscription Name"
|
|
|
|
# 创建 Service Principal (用于 Terraform)
|
|
az ad sp create-for-rbac --name "invoice-master-terraform" --role Contributor \
|
|
--scopes /subscriptions/{subscription-id}
|
|
```
|
|
|
|
---
|
|
|
|
## 3. 基础设施部署
|
|
|
|
### 3.1 Terraform 配置
|
|
|
|
```bash
|
|
cd infrastructure/terraform
|
|
|
|
# 初始化
|
|
terraform init
|
|
|
|
# 创建变量文件
|
|
cat > terraform.tfvars <<EOF
|
|
# 基础配置
|
|
environment = "production"
|
|
location = "swedencentral"
|
|
resource_group_name = "rg-invoice-master-prod"
|
|
|
|
# 数据库
|
|
db_admin_username = "dbadmin"
|
|
db_admin_password = "YourSecurePassword123!"
|
|
db_sku = "Standard_B1ms"
|
|
db_storage_mb = 32768
|
|
|
|
# Redis
|
|
redis_sku = "Basic"
|
|
redis_family = "C"
|
|
redis_capacity = 1
|
|
|
|
# Container Apps
|
|
ca_cpu = "1.0"
|
|
ca_memory = "2.0Gi"
|
|
ca_min_replicas = 1
|
|
ca_max_replicas = 5
|
|
|
|
# 域名
|
|
domain_name = "app.invoice-master.app"
|
|
EOF
|
|
|
|
# 计划
|
|
terraform plan
|
|
|
|
# 应用
|
|
terraform apply
|
|
```
|
|
|
|
### 3.2 Terraform 模块结构
|
|
|
|
```
|
|
infrastructure/terraform/
|
|
├── main.tf # 主配置
|
|
├── variables.tf # 变量定义
|
|
├── outputs.tf # 输出
|
|
├── providers.tf # 提供商配置
|
|
├── backend.tf # 远程状态
|
|
├── terraform.tfvars # 变量值 (gitignore)
|
|
│
|
|
└── modules/
|
|
├── database/ # PostgreSQL 模块
|
|
│ ├── main.tf
|
|
│ ├── variables.tf
|
|
│ └── outputs.tf
|
|
│
|
|
├── cache/ # Redis 模块
|
|
│ ├── main.tf
|
|
│ ├── variables.tf
|
|
│ └── outputs.tf
|
|
│
|
|
├── storage/ # Blob Storage 模块
|
|
│ ├── main.tf
|
|
│ ├── variables.tf
|
|
│ └── outputs.tf
|
|
│
|
|
├── container_apps/ # Container Apps 模块
|
|
│ ├── main.tf
|
|
│ ├── variables.tf
|
|
│ └── outputs.tf
|
|
│
|
|
└── keyvault/ # Key Vault 模块
|
|
├── main.tf
|
|
├── variables.tf
|
|
└── outputs.tf
|
|
```
|
|
|
|
### 3.3 主要资源清单
|
|
|
|
| 资源 | 名称 | SKU/配置 |
|
|
|------|------|----------|
|
|
| Resource Group | rg-invoice-master-prod | Sweden Central |
|
|
| PostgreSQL | psql-invoice-master-prod | Standard_B1ms |
|
|
| Redis | redis-invoice-master-prod | Basic C1 |
|
|
| Blob Storage | stinvoicemasterprod | Standard LRS |
|
|
| Container Apps Env | cae-invoice-master-prod | Consumption |
|
|
| Backend App | ca-invoice-master-api | 1 CPU, 2Gi |
|
|
| Worker App | ca-invoice-master-worker | 0.5 CPU, 1Gi |
|
|
| Key Vault | kv-invoice-master-prod | Standard |
|
|
| Log Analytics | log-invoice-master-prod | Per GB2018 |
|
|
| Application Insights | ai-invoice-master-prod | Web |
|
|
|
|
---
|
|
|
|
## 4. 应用部署
|
|
|
|
### 4.1 构建 .NET 应用
|
|
|
|
#### 4.1.1 本地发布
|
|
|
|
```bash
|
|
cd backend/src/InvoiceMaster.API
|
|
|
|
# 发布 Release 版本
|
|
dotnet publish -c Release -o ./publish \
|
|
--runtime linux-x64 \
|
|
--self-contained false
|
|
|
|
# 或者自包含(无需运行时)
|
|
dotnet publish -c Release -o ./publish \
|
|
--runtime linux-x64 \
|
|
--self-contained true \
|
|
-p:PublishSingleFile=true
|
|
```
|
|
|
|
#### 4.1.2 Docker 构建
|
|
|
|
```dockerfile
|
|
# Dockerfile
|
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
|
WORKDIR /app
|
|
EXPOSE 8080
|
|
|
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
|
WORKDIR /src
|
|
COPY ["src/InvoiceMaster.API/InvoiceMaster.API.csproj", "src/InvoiceMaster.API/"]
|
|
COPY ["src/InvoiceMaster.Core/InvoiceMaster.Core.csproj", "src/InvoiceMaster.Core/"]
|
|
COPY ["src/InvoiceMaster.Application/InvoiceMaster.Application.csproj", "src/InvoiceMaster.Application/"]
|
|
COPY ["src/InvoiceMaster.Infrastructure/InvoiceMaster.Infrastructure.csproj", "src/InvoiceMaster.Infrastructure/"]
|
|
COPY ["src/InvoiceMaster.Integrations/InvoiceMaster.Integrations.csproj", "src/InvoiceMaster.Integrations/"]
|
|
RUN dotnet restore "src/InvoiceMaster.API/InvoiceMaster.API.csproj"
|
|
COPY . .
|
|
WORKDIR "/src/src/InvoiceMaster.API"
|
|
RUN dotnet build "InvoiceMaster.API.csproj" -c Release -o /app/build
|
|
|
|
FROM build AS publish
|
|
RUN dotnet publish "InvoiceMaster.API.csproj" -c Release -o /app/publish
|
|
|
|
FROM base AS final
|
|
WORKDIR /app
|
|
COPY --from=publish /app/publish .
|
|
ENTRYPOINT ["dotnet", "InvoiceMaster.API.dll"]
|
|
```
|
|
|
|
```bash
|
|
# 构建并推送镜像
|
|
docker build -t invoice-master-api:latest -f Dockerfile .
|
|
docker tag invoice-master-api:latest {acr-name}.azurecr.io/invoice-master-api:v1.0.0
|
|
|
|
# 推送到 ACR
|
|
az acr login --name {acr-name}
|
|
docker push {acr-name}.azurecr.io/invoice-master-api:v1.0.0
|
|
```
|
|
|
|
### 4.2 配置环境变量
|
|
|
|
在 Azure Key Vault 中创建以下 secrets:
|
|
|
|
#### 全局 Secrets
|
|
|
|
| Secret Name | 说明 |
|
|
|-------------|------|
|
|
| `db-password` | PostgreSQL 密码 |
|
|
| `jwt-secret` | JWT 签名密钥 |
|
|
| `encryption-key` | AES-256 加密密钥 |
|
|
| `ocr-api-key` | Invoice Master API Key |
|
|
|
|
#### Provider-Specific Secrets
|
|
|
|
| Secret Name | 说明 | 状态 |
|
|
|-------------|------|------|
|
|
| `fortnox-client-id` | Fortnox OAuth Client ID | Required |
|
|
| `fortnox-client-secret` | Fortnox OAuth Client Secret | Required |
|
|
| `fortnox-redirect-uri` | Fortnox OAuth Redirect URI | Required |
|
|
| `visma-client-id` | Visma OAuth Client ID | Future |
|
|
| `visma-client-secret` | Visma OAuth Client Secret | Future |
|
|
| `visma-redirect-uri` | Visma OAuth Redirect URI | Future |
|
|
|
|
```bash
|
|
# 示例: 添加 global secrets
|
|
az keyvault secret set --vault-name kv-invoice-master-prod \
|
|
--name "jwt-secret" \
|
|
--value "your-256-bit-secret-key-here"
|
|
|
|
# 示例: 添加 Fortnox secrets
|
|
az keyvault secret set --vault-name kv-invoice-master-prod \
|
|
--name "fortnox-client-id" \
|
|
--value "your-fortnox-client-id"
|
|
|
|
az keyvault secret set --vault-name kv-invoice-master-prod \
|
|
--name "fortnox-client-secret" \
|
|
--value "your-fortnox-client-secret"
|
|
```
|
|
|
|
### 4.3 部署到 Container Apps
|
|
|
|
```bash
|
|
# 更新后端应用
|
|
az containerapp update \
|
|
--name ca-invoice-master-api \
|
|
--resource-group rg-invoice-master-prod \
|
|
--image {acr-name}.azurecr.io/invoice-master-api:v1.0.0 \
|
|
--set-env-vars "ENVIRONMENT=production"
|
|
```
|
|
|
|
### 4.4 数据库迁移 (EF Core)
|
|
|
|
```bash
|
|
# 方法 1: 使用 EF Core CLI (推荐开发环境)
|
|
cd backend/src/InvoiceMaster.Infrastructure
|
|
|
|
# 添加迁移
|
|
dotnet ef migrations add InitialCreate \
|
|
--startup-project ../InvoiceMaster.API
|
|
|
|
# 更新数据库
|
|
dotnet ef database update \
|
|
--startup-project ../InvoiceMaster.API \
|
|
--connection "Host=psql-invoice-master-prod.postgres.database.azure.com;Database=invoice_master;Username=dbadmin;Password=$DB_PASSWORD"
|
|
|
|
# 生成 SQL 脚本 (生产环境推荐)
|
|
dotnet ef migrations script \
|
|
--startup-project ../InvoiceMaster.API \
|
|
--output migration.sql
|
|
|
|
# 执行 SQL 脚本
|
|
psql "Host=psql-invoice-master-prod.postgres.database.azure.com;Database=invoice_master;Username=dbadmin" \
|
|
-f migration.sql
|
|
```
|
|
|
|
#### 4.4.1 生产环境迁移最佳实践
|
|
|
|
```bash
|
|
# 使用临时 Container App Job 运行迁移
|
|
az containerapp job create \
|
|
--name db-migration-job \
|
|
--resource-group rg-invoice-master-prod \
|
|
--environment cae-invoice-master-prod \
|
|
--image {acr-name}.azurecr.io/invoice-master-api:v1.0.0 \
|
|
--command "dotnet ef database update" \
|
|
--env-vars "ConnectionStrings__DefaultConnection=secretref:db-connection-string"
|
|
```
|
|
|
|
### 4.5 添加新的会计系统 Provider
|
|
|
|
当需要添加新的会计系统时:
|
|
|
|
```bash
|
|
# 1. 在 Key Vault 中添加新 Provider 的 credentials
|
|
az keyvault secret set \
|
|
--vault-name kv-invoice-master-prod \
|
|
--name "visma-client-id" \
|
|
--value "your-visma-client-id"
|
|
|
|
# 2. 更新 Container Apps 环境变量
|
|
az containerapp update \
|
|
--name ca-invoice-master-api \
|
|
--resource-group rg-invoice-master-prod \
|
|
--set-env-vars "VISMA_CLIENT_ID=secretref:visma-client-id"
|
|
|
|
# 3. 重启应用
|
|
az containerapp revision restart \
|
|
--name ca-invoice-master-api \
|
|
--resource-group rg-invoice-master-prod
|
|
```
|
|
|
|
---
|
|
|
|
## 5. 前端部署
|
|
|
|
### 5.1 构建
|
|
|
|
```bash
|
|
cd frontend
|
|
|
|
# 安装依赖
|
|
npm install
|
|
|
|
# 构建生产版本
|
|
npm run build
|
|
```
|
|
|
|
### 5.2 部署到 Azure Static Web Apps
|
|
|
|
```bash
|
|
# 使用 SWA CLI
|
|
npm install -g @azure/static-web-apps-cli
|
|
|
|
# 部署
|
|
swa deploy ./dist \
|
|
--env production \
|
|
--app-name stapp-invoice-master-prod \
|
|
--resource-group rg-invoice-master-prod
|
|
```
|
|
|
|
### 5.3 或部署到 Vercel
|
|
|
|
```bash
|
|
# 安装 Vercel CLI
|
|
npm i -g vercel
|
|
|
|
# 部署
|
|
vercel --prod
|
|
```
|
|
|
|
---
|
|
|
|
## 6. 域名和 SSL
|
|
|
|
### 6.1 配置自定义域名
|
|
|
|
```bash
|
|
# Container Apps 自定义域名
|
|
az containerapp hostname add \
|
|
--name ca-invoice-master-api \
|
|
--resource-group rg-invoice-master-prod \
|
|
--hostname api.invoice-master.app
|
|
|
|
# 绑定证书 (Managed Certificate)
|
|
az containerapp hostname bind \
|
|
--name ca-invoice-master-api \
|
|
--resource-group rg-invoice-master-prod \
|
|
--hostname api.invoice-master.app \
|
|
--environment cae-invoice-master-prod \
|
|
--validation-method CNAME
|
|
```
|
|
|
|
### 6.2 DNS 配置
|
|
|
|
在 DNS 提供商处添加以下记录:
|
|
|
|
| 类型 | 主机 | 值 |
|
|
|------|------|-----|
|
|
| CNAME | api | ca-invoice-master-api.{region}.azurecontainerapps.io |
|
|
| CNAME | app | {static-web-app-url} |
|
|
|
|
---
|
|
|
|
## 7. 监控配置
|
|
|
|
### 7.1 Application Insights
|
|
|
|
```bash
|
|
# 获取连接字符串
|
|
APP_INSIGHTS_CONN=$(az monitor app-insights component show \
|
|
--app ai-invoice-master-prod \
|
|
--resource-group rg-invoice-master-prod \
|
|
--query connectionString -o tsv)
|
|
|
|
# 配置到 Container Apps
|
|
az containerapp update \
|
|
--name ca-invoice-master-api \
|
|
--resource-group rg-invoice-master-prod \
|
|
--set-env-vars "APPLICATIONINSIGHTS_CONNECTION_STRING=$APP_INSIGHTS_CONN"
|
|
```
|
|
|
|
### 7.2 多会计系统监控
|
|
|
|
```kusto
|
|
// 查看各 Provider API 调用情况
|
|
AppRequests
|
|
| where TimeGenerated > ago(1h)
|
|
| where OperationName contains "accounting"
|
|
| summarize count(), avg(DurationMs) by Provider = tostring(CustomDimensions.provider)
|
|
| order by count_ desc
|
|
|
|
// 查看 Provider 错误率
|
|
AppExceptions
|
|
| where TimeGenerated > ago(1h)
|
|
| where ProblemId contains "fortnox" or ProblemId contains "visma"
|
|
| summarize count() by Provider = tostring(CustomDimensions.provider), bin(TimeGenerated, 5m)
|
|
| render timechart
|
|
```
|
|
|
|
### 7.3 告警规则
|
|
|
|
```bash
|
|
# 创建 CPU 使用率告警
|
|
az monitor metrics alert create \
|
|
--name "High CPU Alert" \
|
|
--resource-group rg-invoice-master-prod \
|
|
--scopes $(az containerapp show --name ca-invoice-master-api --resource-group rg-invoice-master-prod --query id -o tsv) \
|
|
--condition "avg cpu percentage > 80" \
|
|
--window-size 5m \
|
|
--evaluation-frequency 1m \
|
|
--action $(az monitor action-group show --name ag-invoice-master --resource-group rg-invoice-master-prod --query id -o tsv)
|
|
|
|
# 创建 Provider API 错误告警
|
|
az monitor metrics alert create \
|
|
--name "Provider API Errors" \
|
|
--resource-group rg-invoice-master-prod \
|
|
--scopes $(az monitor app-insights component show --name ai-invoice-master-prod --resource-group rg-invoice-master-prod --query id -o tsv) \
|
|
--condition "count exceptions > 10" \
|
|
--window-size 5m \
|
|
--evaluation-frequency 1m
|
|
```
|
|
|
|
---
|
|
|
|
## 8. 备份策略
|
|
|
|
### 8.1 数据库备份
|
|
|
|
```bash
|
|
# 配置自动备份 (已在 Terraform 中配置)
|
|
# 手动备份
|
|
az postgres flexible-server backup create \
|
|
--name manual-backup-$(date +%Y%m%d) \
|
|
--server-name psql-invoice-master-prod \
|
|
--resource-group rg-invoice-master-prod
|
|
|
|
# 备份 accounting_connections 表 (关键)
|
|
pg_dump "host=psql-invoice-master-prod.postgres.database.azure.com user=dbadmin dbname=invoice_master sslmode=require" \
|
|
--table=accounting_connections \
|
|
--table=invoices \
|
|
--table=users > critical_tables_backup.sql
|
|
```
|
|
|
|
### 8.2 Blob Storage 备份
|
|
|
|
```bash
|
|
# 启用版本控制
|
|
az storage account blob-service-properties update \
|
|
--account-name stinvoicemasterprod \
|
|
--enable-versioning true
|
|
|
|
# 配置生命周期策略
|
|
az storage account management-policy create \
|
|
--account-name stinvoicemasterprod \
|
|
--policy @lifecycle-policy.json
|
|
```
|
|
|
|
---
|
|
|
|
## 9. 安全加固
|
|
|
|
### 9.1 网络安全
|
|
|
|
```bash
|
|
# 配置防火墙规则
|
|
az postgres flexible-server firewall-rule create \
|
|
--name AllowContainerApps \
|
|
--server-name psql-invoice-master-prod \
|
|
--resource-group rg-invoice-master-prod \
|
|
--start-ip-address 0.0.0.0 \
|
|
--end-ip-address 0.0.0.0
|
|
|
|
# 启用私有链接 (可选)
|
|
```
|
|
|
|
### 9.2 Key Vault 访问策略
|
|
|
|
```bash
|
|
# 授予 Container Apps 访问 Key Vault 的权限
|
|
az keyvault set-policy \
|
|
--name kv-invoice-master-prod \
|
|
--object-id $(az containerapp show --name ca-invoice-master-api --resource-group rg-invoice-master-prod --query identity.principalId -o tsv) \
|
|
--secret-permissions get list
|
|
|
|
# 为新的 Provider 添加 secrets 时,确保权限已配置
|
|
```
|
|
|
|
### 9.3 多租户数据隔离
|
|
|
|
```sql
|
|
-- 验证数据隔离
|
|
SELECT provider, COUNT(*) as connection_count
|
|
FROM accounting_connections
|
|
GROUP BY provider;
|
|
|
|
-- 检查用户数据访问权限
|
|
SELECT u.email, ac.provider, ac.company_name
|
|
FROM users u
|
|
JOIN accounting_connections ac ON u.id = ac.user_id
|
|
WHERE u.email = 'test@example.com';
|
|
```
|
|
|
|
---
|
|
|
|
## 10. 回滚策略
|
|
|
|
### 10.1 应用回滚
|
|
|
|
```bash
|
|
# 回滚到上一个版本
|
|
az containerapp revision list \
|
|
--name ca-invoice-master-api \
|
|
--resource-group rg-invoice-master-prod
|
|
|
|
az containerapp update \
|
|
--name ca-invoice-master-api \
|
|
--resource-group rg-invoice-master-prod \
|
|
--revision-suffix {previous-revision}
|
|
```
|
|
|
|
### 10.2 数据库回滚
|
|
|
|
```bash
|
|
# 从备份恢复
|
|
az postgres flexible-server restore \
|
|
--name psql-invoice-master-prod-restored \
|
|
--resource-group rg-invoice-master-prod \
|
|
--source-server psql-invoice-master-prod \
|
|
--point-in-time "2026-02-03T10:00:00Z"
|
|
|
|
# 回滚特定 Provider 的数据 (谨慎操作)
|
|
DELETE FROM accounting_connections WHERE provider = 'fortnox';
|
|
```
|
|
|
|
### 10.3 Provider 配置回滚
|
|
|
|
```bash
|
|
# 如果新 Provider 配置出错,快速禁用
|
|
az containerapp update \
|
|
--name ca-invoice-master-api \
|
|
--resource-group rg-invoice-master-prod \
|
|
--set-env-vars "ENABLED_PROVIDERS=fortnox"
|
|
```
|
|
|
|
---
|
|
|
|
## 11. CI/CD 配置
|
|
|
|
### 11.1 GitHub Actions 工作流
|
|
|
|
```yaml
|
|
# .github/workflows/deploy.yml
|
|
name: Deploy to Azure
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
|
|
jobs:
|
|
deploy-backend:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Azure Login
|
|
uses: azure/login@v1
|
|
with:
|
|
creds: ${{ secrets.AZURE_CREDENTIALS }}
|
|
|
|
- name: Build and Push
|
|
run: |
|
|
az acr build --registry ${{ secrets.ACR_NAME }} \
|
|
--image invoice-master-api:${{ github.sha }} \
|
|
./backend
|
|
|
|
- name: Deploy
|
|
run: |
|
|
az containerapp update \
|
|
--name ca-invoice-master-api \
|
|
--resource-group rg-invoice-master-prod \
|
|
--image ${{ secrets.ACR_NAME }}.azurecr.io/invoice-master-api:${{ github.sha }}
|
|
|
|
- name: Run Migrations
|
|
run: |
|
|
# 使用临时容器运行 EF Core 迁移
|
|
az containerapp job create \
|
|
--name migration-job \
|
|
--resource-group rg-invoice-master-prod \
|
|
--image ${{ secrets.ACR_NAME }}.azurecr.io/invoice-master-api:${{ github.sha }} \
|
|
--command "dotnet ef database update --no-build"
|
|
```
|
|
|
|
### 11.2 多环境部署
|
|
|
|
```yaml
|
|
# 不同环境使用不同配置
|
|
- name: Deploy to Staging
|
|
if: github.ref == 'refs/heads/develop'
|
|
run: |
|
|
az containerapp update \
|
|
--name ca-invoice-master-api-staging \
|
|
--resource-group rg-invoice-master-staging
|
|
|
|
- name: Deploy to Production
|
|
if: github.ref == 'refs/heads/main'
|
|
run: |
|
|
az containerapp update \
|
|
--name ca-invoice-master-api \
|
|
--resource-group rg-invoice-master-prod
|
|
```
|
|
|
|
---
|
|
|
|
## 12. 成本估算
|
|
|
|
### 12.1 基础资源成本
|
|
|
|
| 资源 | 每月估算 (SEK) |
|
|
|------|----------------|
|
|
| PostgreSQL (B1ms) | ~150 |
|
|
| Redis (Basic C1) | ~100 |
|
|
| Container Apps | ~200-500 |
|
|
| Blob Storage | ~50-200 |
|
|
| Key Vault | ~30 |
|
|
| Application Insights | ~100 |
|
|
| **基础总计** | **~630-1,080 SEK** |
|
|
|
|
### 12.2 多会计系统额外成本
|
|
|
|
| 项目 | 每月估算 (SEK) | 说明 |
|
|
|------|----------------|------|
|
|
| 额外的 API 调用 | ~0-100 | 取决于 Provider 数量 |
|
|
| 额外的 Redis 缓存 | ~0-50 | Provider token 缓存 |
|
|
| 额外的日志存储 | ~0-100 | 多 Provider 日志 |
|
|
| **额外总计** | **~0-250 SEK** |
|
|
|
|
---
|
|
|
|
## 13. 故障排除
|
|
|
|
### 13.1 常见问题
|
|
|
|
**问题**: Container App 无法启动
|
|
```bash
|
|
# 查看日志
|
|
az containerapp logs show \
|
|
--name ca-invoice-master-api \
|
|
--resource-group rg-invoice-master-prod \
|
|
--follow
|
|
```
|
|
|
|
**问题**: Provider 认证失败
|
|
```bash
|
|
# 检查 Key Vault secrets
|
|
az keyvault secret list --vault-name kv-invoice-master-prod
|
|
|
|
# 验证特定 Provider 配置
|
|
curl https://api.invoice-master.app/api/v1/accounting/providers \
|
|
-H "Authorization: Bearer $TOKEN"
|
|
```
|
|
|
|
**问题**: 数据库连接失败
|
|
```bash
|
|
# 测试连接
|
|
psql "host=psql-invoice-master-prod.postgres.database.azure.com port=5432 dbname=invoice_master user=dbadmin sslmode=require"
|
|
|
|
# 检查连接表
|
|
psql $DB_URL -c "SELECT provider, COUNT(*) FROM accounting_connections GROUP BY provider;"
|
|
```
|
|
|
|
### 13.2 Provider 特定故障排除
|
|
|
|
**Fortnox OAuth 问题**:
|
|
```bash
|
|
# 检查 Fortnox 连接状态
|
|
curl https://api.invoice-master.app/api/v1/accounting/fortnox/connection \
|
|
-H "Authorization: Bearer $TOKEN"
|
|
|
|
# 重新授权
|
|
# 引导用户访问: https://api.invoice-master.app/api/v1/accounting/fortnox/auth/url
|
|
```
|
|
|
|
### 13.3 健康检查
|
|
|
|
```bash
|
|
# API 健康检查
|
|
curl https://api.invoice-master.app/health
|
|
|
|
# 详细健康检查 (包含 Provider 状态)
|
|
curl https://api.invoice-master.app/health/detailed \
|
|
-H "Authorization: Bearer $ADMIN_TOKEN"
|
|
|
|
# 预期响应:
|
|
# {
|
|
# "status": "healthy",
|
|
# "providers": {
|
|
# "fortnox": { "status": "connected", "latency_ms": 150 },
|
|
# "visma": { "status": "not_configured" }
|
|
# }
|
|
# }
|
|
```
|
|
|
|
---
|
|
|
|
## 14. 维护窗口
|
|
|
|
| 任务 | 频率 | 时间 |
|
|
|------|------|------|
|
|
| 安全更新 | 每周 | 周日 02:00-04:00 |
|
|
| 数据库备份验证 | 每月 | 第一个周日 |
|
|
| Provider API 健康检查 | 每周 | 周一 |
|
|
| 性能审查 | 每季度 | - |
|
|
| 证书续期检查 | 每月 | - |
|
|
| Provider SDK 更新检查 | 每月 | - |
|
|
|
|
---
|
|
|
|
## 15. 扩展检查清单
|
|
|
|
### 添加新 Provider 时的部署检查清单
|
|
|
|
- [ ] 在 Key Vault 中添加 Provider credentials
|
|
- [ ] 更新 Container Apps 环境变量
|
|
- [ ] 更新 DNS/防火墙规则 (如需要)
|
|
- [ ] 测试 Provider 连接
|
|
- [ ] 更新监控告警规则
|
|
- [ ] 更新文档
|
|
- [ ] 通知团队
|
|
|
|
---
|
|
|
|
## 16. 联系信息
|
|
|
|
| 角色 | 联系方式 |
|
|
|------|----------|
|
|
| 技术负责人 | tech@example.com |
|
|
| 运维团队 | ops@example.com |
|
|
| 紧急联系 | +46-xxx-xxx-xxxx |
|
|
| Provider 支持 | providers@example.com |
|
|
|
|
---
|
|
|
|
**文档历史:**
|
|
|
|
| 版本 | 日期 | 作者 | 变更 |
|
|
|------|------|------|------|
|
|
| 3.0 | 2026-02-03 | Claude Code | 重构为 .NET 8 + EF Core 部署 |
|
|
| 2.0 | 2026-02-03 | Claude Code | 更新为多会计系统架构 |
|
|
| 1.0 | 2026-02-03 | Claude Code | 初始版本 |
|