Files
oil-formula-calculator/doc/deploy.md
Hera Zhao ee8ec23dc7 Refactor frontend to Vue 3 + Vite + Pinia + Cypress E2E
- Replace single-file 8441-line HTML with Vue 3 SPA
- Pinia stores: auth, oils, recipes, diary, ui
- Composables: useApi, useDialog, useSmartPaste, useOilTranslation
- 6 shared components: RecipeCard, RecipeDetailOverlay, TagPicker, etc.
- 9 page views: RecipeSearch, RecipeManager, Inventory, OilReference, etc.
- 14 Cypress E2E test specs (113 tests), all passing
- Multi-stage Dockerfile (Node build + Python runtime)
- Demo video generation scripts (TTS + subtitles + screen recording)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:35:00 +00:00

6.8 KiB
Raw Blame History

精油配方计算器 - 部署文档

架构

  • 前端: Vue 3 + Vite + Pinia + Vue Router构建为静态文件由 FastAPI serve
  • 后端: FastAPI + SQLite端口 8000
  • 部署: Kubernetes (k3s) on oci.euphon.net
  • 域名: https://oil.oci.euphon.net
  • TLS: Traefik + Let's Encrypt (自动)

目录结构

├── backend/
│   ├── main.py          # FastAPI 应用
│   ├── database.py      # SQLite 数据库操作
│   ├── defaults.json    # 默认精油和配方数据(首次启动时 seed
│   └── requirements.txt
├── frontend/            # Vue 3 + Vite 项目
│   ├── package.json
│   ├── vite.config.js
│   ├── index.html
│   ├── public/          # 静态资源favicon、PWA icons
│   └── src/
│       ├── main.js          # 入口文件
│       ├── App.vue          # 根组件
│       ├── router/          # Vue Router 路由配置
│       ├── stores/          # Pinia 状态管理
│       │   ├── auth.js      # 认证/用户
│       │   ├── oils.js      # 精油价格
│       │   ├── recipes.js   # 配方/标签/收藏
│       │   ├── diary.js     # 个人配方日记
│       │   └── ui.js        # UI 状态
│       ├── composables/     # 组合式函数
│       │   ├── useApi.js    # API 请求封装
│       │   ├── useDialog.js # 自定义对话框
│       │   ├── useSmartPaste.js    # 智能粘贴解析
│       │   └── useOilTranslation.js # 精油中英翻译
│       ├── components/      # 共享组件
│       │   ├── RecipeCard.vue
│       │   ├── RecipeDetailOverlay.vue
│       │   ├── TagPicker.vue
│       │   ├── LoginModal.vue
│       │   ├── UserMenu.vue
│       │   └── CustomDialog.vue
│       ├── views/           # 页面组件
│       │   ├── RecipeSearch.vue     # 配方查询
│       │   ├── RecipeManager.vue    # 管理配方
│       │   ├── Inventory.vue        # 个人库存
│       │   ├── OilReference.vue     # 精油价目
│       │   ├── Projects.vue         # 商业核算
│       │   ├── MyDiary.vue          # 我的(日记/品牌/账号)
│       │   ├── AuditLog.vue         # 操作日志
│       │   ├── BugTracker.vue       # Bug 追踪
│       │   └── UserManagement.vue   # 用户管<E688B7><E7AEA1>
│       └── assets/
│           └── styles.css   # 全局样式
├── deploy/
│   ├── namespace.yaml
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── pvc.yaml         # 1Gi 持久卷,存放 SQLite 数据库
│   ├── ingress.yaml
│   ├── setup-kubeconfig.sh
│   └── kubeconfig
├── Dockerfile           # 多阶段构建Node → Python
└── doc/deploy.md

本地开发

# 前端开发(热更新)
cd frontend
npm install
npm run dev    # 默认 http://localhost:5173自动代理 /api 到 :8000

# 后端开发
cd backend
pip install -r requirements.txt
uvicorn backend.main:app --reload --port 8000

构建

# 前端构建
cd frontend
npm run build  # 输出到 frontend/dist/

# Docker 构建(多阶段:先构建前端,再打包后端)
docker build -t oil-calculator .

首次部署

已完成,以下为记录。

# 1. SSH 到服务器
ssh fam@oci.euphon.net

# 2. 上传项目
scp oil-calc.tar.gz fam@oci.euphon.net:/tmp/
ssh fam@oci.euphon.net "mkdir -p ~/oil-calculator && cd ~/oil-calculator && tar xzf /tmp/oil-calc.tar.gz"

# 3. 构建并推送镜像
cd ~/oil-calculator
docker build -t registry.oci.euphon.net/oil-calculator:latest .
docker push registry.oci.euphon.net/oil-calculator:latest

# 4. 部署 k8s 资源
cd deploy
kubectl apply -f namespace.yaml
kubectl apply -f pvc.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml

# 5. 需要 regcred 才能拉取私有镜像(从已有 ns 复制)
kubectl get secret regcred -n guitar -o yaml | sed 's/namespace: guitar/namespace: oil-calculator/' | kubectl apply -f -

更新部署

# 在本地打包上传
cd /path/to/oil
tar czf /tmp/oil-calc.tar.gz Dockerfile backend/ frontend/ deploy/ --exclude='frontend/node_modules' --exclude='frontend/dist'
scp /tmp/oil-calc.tar.gz fam@oci.euphon.net:/tmp/

# SSH 到服务器构建并重启
ssh fam@oci.euphon.net
cd ~/oil-calculator && tar xzf /tmp/oil-calc.tar.gz
docker build -t registry.oci.euphon.net/oil-calculator:latest .
docker push registry.oci.euphon.net/oil-calculator:latest
kubectl rollout restart deploy/oil-calculator -n oil-calculator

或者使用受限 kubeconfig仅重启不含构建

KUBECONFIG=deploy/kubeconfig kubectl rollout restart deploy/oil-calculator

受限 Kubeconfig

文件位于 deploy/kubeconfig,权限范围:

  • Namespace: oil-calculator only
  • ServiceAccount: oil-calculator-deployer
  • 权限: pods, services, deployments, replicasets, ingresses, PVC, configmaps, secrets, pods/log 的完整 CRUD
  • 无法访问其他 namespace 或集群级资源

重新生成:bash deploy/setup-kubeconfig.sh

K8s 配置要点

  • Ingress class: traefik
  • TLS annotation: traefik.ingress.kubernetes.io/router.tls.certresolver: le
  • 镜像仓库: registry.oci.euphon.net(需要 regcred secret
  • 数据持久化: PVC 挂载到 /dataSQLite 数据库在 /data/oil_calculator.db

API 端点

Method Path 说明
GET /api/oils 所有精油列表
POST /api/oils 添加/更新精油
DELETE /api/oils/{name} 删除精油
GET /api/recipes 所有配方列表
POST /api/recipes 新增配方
PUT /api/recipes/{id} 更新配方
DELETE /api/recipes/{id} 删除配方
GET /api/tags 所有标签
POST /api/tags 新增标签
DELETE /api/tags/{name} 删除标签
GET /api/me 当前用户信息
POST /api/login 登录
POST /api/register 注册
GET /api/diary 个人配方列表
POST /api/diary 创建个人配方
PUT /api/diary/{id} 更新个人配方
DELETE /api/diary/{id} 删除个人配方
GET /api/favorites 收藏列表
POST /api/favorites/{id} 添加收藏
DELETE /api/favorites/{id} 取消收藏
GET /api/inventory 个人库存
POST /api/inventory 更新库存
GET /api/projects 商业项目列表
GET /api/audit-log 操作日志
GET /api/users 用户列表(管理员)
GET /api/bug-reports Bug 列表
GET /api/notifications 通知列表
GET /api/version 服务器版本