- 命名重构:tenant → customer(对齐后端 R1 重构) - Tenant → Customer / tenant_id → customerId - tenantStore → customerStore / getTenant/setTenant → getCustomer/setCustomer - cookie key tenant → customer, HTTP header tenantId → customerId - 后端契约更新:AuthResponse 加 sub 字段 - 接口 URL 修复:/auth/oidc/callback → /api/v1/auth/oidc/callback - 依赖升级:vue 3.5 / element-plus 2.8 / vite 5 / typescript 5.6 / sass 1.79 - 删 node-sass / scss / sass-loader / moment / mock/index.ts - 配置文件拆分:.env.development / .env.production / .env.example - 删除冗余 view/auth/auth/callback.vue 副本 - .gitignore 增加 dist / .opencode / tmp - 新增 AGENT.md 与后端风格对齐
7.7 KiB
AGENT.md — violin-home
面向 AI agent 的工程导览:模块关系、路由约定、与后端的契约、扩展点。 代码即事实,本文件是索引;如代码与本文档冲突,以代码为准。
项目定位
violin-home 是 violin 微服务套件的统一前端门户,部署在 https://www.violin-home.cn/。
- 认证:Authentik OIDC,回调路径
/auth/callback,前端把 code POST 到violin-auth服务换 token - 后端:依赖 violin-auth(认证)/ violin-bookmark(书签)/ violin-calendar(日历)/ violin-onenote / violin-cloud / 等子服务
- 域名:生产
https://www.violin-home.cn/;本地 dev 走.env.development的VITE_APP_URL
技术栈
| 维度 | 选型 |
|---|---|
| 框架 | Vue 3.5 + Composition API (<script setup>) |
| 构建 | Vite 5 |
| 语言 | TypeScript 5.6 |
| UI | Element Plus 2.8 + Icons |
| 状态 | Pinia 2.2 |
| 路由 | vue-router 4.4(memory history,不是 hash / web) |
| HTTP | axios 1.7 |
| 图表 | ECharts 5 |
| Markdown | md-editor-v3 4 |
| 日期 | dayjs(已废弃 moment) |
| Mock | vite-plugin-mock 3(仅 dev 启用) |
| 拖拽 | vuedraggable 4 |
| 样式 | SCSS(Dart Sass 1.79,已删除 node-sass) |
目录结构
violin-home/
├── public/ 静态资源(不打包)
│ ├── blog/*.ts 博客元数据(按业务模块拆分)
│ └── reset/ Authentik reset 入口(reset.html 等)
├── src/
│ ├── api/ axios 接口封装(每个业务一个文件)
│ ├── components/ 公共组件
│ │ ├── common/ 通用组件
│ │ ├── layout/ 顶层布局
│ │ ├── login/ 登录 / 注册 / sorryPage
│ │ ├── cloud/ 云盘 + aplayer 音乐
│ │ ├── illustration/ 插画
│ │ ├── customPic/ 自定义图片
│ │ └── operate/ 操作组件
│ ├── const/ 全局常量
│ ├── entity/ 实体类型(TypeScript interface)
│ ├── router/ 路由表(**统一指向 @/view/**)
│ ├── service/ 服务层(独立于 axios 的工具服务)
│ ├── store/ Pinia stores
│ ├── style/ 全局样式(mixin.scss 在 vite.config.ts 里自动注入)
│ ├── types/ 类型声明(*.d.ts)
│ ├── utils/ 工具函数(auth 令牌管理、request axios 封装、date、number)
│ ├── view/ **页面视图(业务页)** — 单数 view
│ ├── App.vue
│ ├── env.d.ts
│ ├── main.ts
│ └── permission.ts 路由守卫
├── mock/ vite-plugin-mock 的 mock 数据
├── authentik-deploy/ Authentik 部署相关(helm values、reset 脚本)
├── .env.development 本地开发
├── .env.test 测试环境
├── .env.production 生产环境
├── Dockerfile
├── Jenkinsfile
├── nginx.conf
├── vite.config.ts
└── tsconfig.json
路由约定
全部路由指向 @/view/(单数),包括 /auth/callback:
router/index.ts是唯一的路由表- 路由 meta.name 是侧边栏展示的中文名
/auth/callback由view/auth/callback.vue处理 OIDC 回调(拿 code → POST/auth/oidc/callback到 violin-auth → 存 token)
禁止新建 views/(复数)目录。
认证流程(OIDC)
浏览器 → Authentik 登录页(不在本工程)
↓ 回调到 https://www.violin-home.cn/auth/callback?code=...&state=...
↓
view/auth/callback.vue
↓ POST { code, redirect_uri } → VITE_APP_URL + '/auth/oidc/callback'
↓
violin-auth 服务(cn.violin.auth.service.OAuthService.oidcAuthorize)
↓ 返回 { token, user_id, name }
↓
utils/auth.setToken / setTenant 存到 cookie + localStorage
↓ 跳到 /
关键约定:
redirect_uri必须和 Authentik 应用的配置完全一致(VITE_OIDC_REDIRECT_URI)state必须校验(防 CSRF),前后端都用sessionStorage.oidc_state缓存- token 由
setToken()存到 cookie(js-cookie),后续 axios 请求拦截器自动加Authorization: Bearer <token>
HTTP 封装(utils/request.ts)
baseURL=import.meta.env.VITE_APP_URL- 请求拦截器:从
js-cookie读 token,加到 header - 响应拦截器:401 → 跳
/login;5xx → ElMessage 报错
每个业务模块在 src/api/ 下有自己的文件(如 api/bookmark.ts),导出按业务分组的函数:
import { service } from '@/utils/request'
export const getBookmarks = (params: PageQuery) =>
service({ url: '/api/v1/bookmark', method: 'get', params })
状态管理(Pinia)
src/store/ 下每个业务一个 store(settings、strategy、table、tenant)。禁止把所有状态塞进一个 store。
tenantstore 管当前 customer(对应后端的 customerId)settingsstore 管用户偏好strategystore 管 CTA 策略模板tablestore 管通用表格筛选/分页状态
与后端子服务的对应
| 路径前缀 | 后端服务 | 端口(K8s 内) |
|---|---|---|
/auth/** |
violin-auth | 8080 |
/api/v1/bookmark/** |
violin-bookmark | 8081 |
/api/v1/calendar/** |
violin-calendar | 8082 |
/api/v1/onenote/** |
violin-onenote | 8083 |
/api/v1/cloud/** |
violin-cloud | 8084 |
/api/v1/trader/** |
violin-trader | 8085 |
/api/v1/user/** |
violin-auth(user 模块) | 8080 |
路由由 K8s ingress 统一反向代理;前端只关心 VITE_APP_URL 单一域名。
构建与运行
# 安装依赖(推荐 pnpm,yarn 也行)
npm install
# 本地 dev(启动 mock)
npm run dev
# 生产构建(先类型检查,再打包)
npm run build
# 测试环境构建
npm run build:test
# 预览构建产物
npm run preview
Node:v18+(不要用 v14/16,老的 sass-loader/node-sass 不兼容)。
已知坑(不要"清理"它们)
1. view/ 单数 vs views/ 复数
永远只创建 view/ 单数目录。views/ 是历史遗物,已删除过又留下空目录。
2. node-sass 已废弃
package.json 里没有 node-sass。如果你看到 npm install 报 node-sass 相关错误,是因为旧依赖被缓存,不要手动加回 node-sass,用 Dart Sass(sass: ^1.79)即可。
3. axios 0.x → 1.x
升级到 axios 1.7 后,axios.create() 配置有少量变化(如 paramsSerializer)。如果你看到 interceptor is not a function 之类的报错,看下拦截器是否还兼容旧签名。
4. Vue Router 4 用 memory history
createMemoryHistory() 而非 createWebHistory() / createWebHashHistory()。刷新页面会丢路由——如果要做刷新保留路由,需要切到 createWebHistory() 并配合 K8s ingress 重写。
5. vite-plugin-mock 仅 dev 启用
生产构建不会带 mock(localEnabled: command === 'serve')。如果发现生产缺数据,看下是不是依赖了 mock。
相关项目
violin-auth— 认证服务(OIDC + JWT 签发)violin-bookmark/violin-calendar/violin-onenote/violin-cloud/violin-trader— 业务子服务violin-common/violin-core— 后端共享框架violin-parent— 后端父 POM