Files
violin-home/AGENT.md
T
simple321vip 4da6832b44 feat: R1 重构对称迁移 + 升级依赖 + 配置文件分离
- 命名重构: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 与后端风格对齐
2026-06-22 08:02:21 +08:00

211 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 |
| 样式 | SCSSDart 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`),导出按业务分组的函数:
```ts
import { service } from '@/utils/request'
export const getBookmarks = (params: PageQuery) =>
service({ url: '/api/v1/bookmark', method: 'get', params })
```
---
## 状态管理(Pinia
`src/store/` 下每个业务一个 storesettings、strategy、table、tenant)。**禁止**把所有状态塞进一个 store。
- `tenant` store 管当前 customer(对应后端的 customerId
- `settings` store 管用户偏好
- `strategy` store 管 CTA 策略模板
- `table` store 管通用表格筛选/分页状态
---
## 与后端子服务的对应
| 路径前缀 | 后端服务 | 端口(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-authuser 模块) | 8080 |
路由由 K8s ingress 统一反向代理;前端只关心 `VITE_APP_URL` 单一域名。
---
## 构建与运行
```bash
# 安装依赖(推荐 pnpm,yarn 也行)
npm install
# 本地 dev(启动 mock
npm run dev
# 生产构建(先类型检查,再打包)
npm run build
# 测试环境构建
npm run build:test
# 预览构建产物
npm run preview
```
Nodev18+**不要**用 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