diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/im_manager.iml b/.idea/im_manager.iml
new file mode 100644
index 0000000..5e764c4
--- /dev/null
+++ b/.idea/im_manager.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..ba0a7e2
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..d843143
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,960 @@
+# HotGo 项目开发规范
+
+**生成或修改任何代码前,必须完整阅读本文档。**
+本规范是项目唯一事实来源,所有新增代码必须严格对齐现有模块风格,不得自创新的代码模式。
+
+---
+
+## 技术栈
+
+| 层 | 技术 |
+|----|----------------------------------------------------------------|
+| 后端语言 | Go,module 名 `hotgo` |
+| 后端框架 | GoFrame v2(gdb、ghttp、gcron、gerror、gctx、gerror、gjson、gvar) |
+| 前端框架 | Vue 3 + Vite + TypeScript |
+| UI 组件库 | **Naive UI**(优先使用,未经允许不得引入其他 UI 库) |
+| 状态管理 | Pinia |
+| HTTP 客户端 | 项目封装 `@/utils/http/axios`(`http.request`),禁止直接使用 axios |
+
+---
+
+## 后端目录结构
+
+```
+server/
+├── addons/ # 插件模块(每个插件独立微架构,见"插件开发"章节)
+│ ├── modules/ # 隐式注册文件(每个插件一个 .go,仅含 import)
+│ └── / # 插件目录,与主模块结构镜像
+├── api/admin// # 主模块 HTTP 契约:Req/Res + g.Meta 路由声明
+├── internal/
+│ ├── consts/ # 全局常量与字典选项(枚举在此定义并注册)
+│ ├── global/ # 全局公用变量(谨慎添加,尽量少用)
+│ ├── controller/admin/sys/ # 薄控制器,只做参数透传,不含业务逻辑
+│ ├── crons/ # 主模块定时任务注册与处理
+│ ├── queues/ # 主模块消息队列消费者注册与处理
+│ ├── logic/sys/ # 业务实现(sSysXxx),init() 注册到 service
+│ ├── library/ # 内部基础库(addons、dict、hgorm、cache、queue、cron 等)
+│ ├── service/ # 接口声明(ISysXxx)+ 注册函数
+│ ├── dao/ # 对外 DAO;internal/dao/internal/ 为 CLI 生成,禁止手改
+│ ├── model/
+│ │ ├── entity/ # 表结构体(CLI 生成,禁止手改)
+│ │ ├── do/ # ORM 写入结构(CLI 生成,禁止手改)
+│ │ └── input/sysin/ # 业务入参、出参、过滤结构
+│ └── router/
+│ ├── admin.go # 主路由,末尾调用 genrouter.Register()
+│ └── genrouter/ # 每个生成模块一个文件,init() 追加到 LoginRequiredRouter
+├── resource/
+│ ├── generate/default/curd/ # 主模块 CRUD 代码生成模板(参考,禁止直接修改)
+│ └── generate/default/addon/ # 插件脚手架代码生成模板(参考,禁止直接修改)
+└── utility/ # 通用工具:convert、excel、validate 等
+```
+
+---
+
+## 后端分层约定
+
+### 分层职责(禁止跨层调用)
+
+```
+api(HTTP契约) → controller(参数透传) → service(接口) → logic(业务实现) → dao(数据访问)
+```
+
+- **controller 层**:不写任何业务逻辑,只转调 service
+- **logic 层**:不出现 HTTP 相关代码,所有校验通过 `Filter()` 或 `g.Validator()` 完成
+- **dao 层**:`internal/dao/internal/` 由 CLI 自动生成,禁止手改
+
+---
+
+### 1. API 层 `api/admin//.go`
+
+- 每个接口一对 `XxxReq` / `XxxRes`,`g.Meta` 声明路由
+- GET 接口用 `method:"get"`,写操作用 `method:"post"`
+- 请求体嵌入 `sysin.XxxInp`,响应体嵌入对应 Model 或空 `struct{}`
+
+```go
+type ListReq struct {
+ g.Meta `path:"/xxxModule/list" method:"get" tags:"XXX模块" summary:"获取XXX列表"`
+ sysin.XxxListInp
+}
+type ListRes struct {
+ form.PageRes
+ List []*sysin.XxxListModel `json:"list" dc:"数据列表"`
+}
+```
+
+### 2. Controller 层 `internal/controller/admin/sys/.go`
+
+- 变量:`var XxxModule = cXxxModule{}`,类型:`type cXxxModule struct{}`
+- 只做参数转发和结果组装,禁止直接操作 dao 或写业务逻辑
+
+```go
+func (c *cXxxModule) List(ctx context.Context, req *xxxmodule.ListReq) (res *xxxmodule.ListRes, err error) {
+ list, totalCount, err := service.SysXxxModule().List(ctx, &req.XxxListInp)
+ if err != nil {
+ return
+ }
+ if list == nil {
+ list = []*sysin.XxxListModel{}
+ }
+ res = new(xxxmodule.ListRes)
+ res.List = list
+ res.PageRes.Pack(req, totalCount)
+ return
+}
+```
+
+### 3. Service 层 `internal/service/sys.go`
+
+- 在已有文件中**追加**接口声明和注册函数,禁止新建文件
+- 声明 `ISysXxxModule` 接口,提供 `SysXxxModule()` 获取函数和 `RegisterSysXxxModule()` 注册函数
+
+### 4. Logic 层 `internal/logic/sys/.go`
+
+- 结构体:`type sSysXxxModule struct{}`
+- `init()` 里调用 `service.RegisterSysXxxModule(NewSysXxxModule())`
+- `Model()` 方法:`return handler.Model(dao.XxxTable.Ctx(ctx), option...)`
+- 列名引用必须用 `dao.XxxTable.Columns().FieldName`,禁止硬编码字符串字段名
+- `Edit` 方法以 `in.Id > 0` 区分更新/新增,更新用 `XxxUpdateFields`,新增用 `XxxInsertFields`
+- 字段校验在 `sysin` 的 `Filter(ctx)` 方法完成,logic 层不重复校验
+
+### 5. Model 层 `internal/model/input/sysin/.go`
+
+| 类型 | 用途 |
+|------|------|
+| `XxxUpdateFields` | 更新时字段白名单 |
+| `XxxInsertFields` | 新增时字段白名单 |
+| `XxxEditInp` | 嵌入 `entity.XxxTable`,含 `Filter()` 校验方法 |
+| `XxxListInp` | 列表查询入参,嵌入 `form.PageInp` |
+| `XxxListModel` | 列表返回字段 |
+| `XxxViewInp` / `XxxViewModel` | 详情入参/出参 |
+| `XxxDeleteInp` | 删除入参(通常含 `Ids []int64`) |
+| `XxxStatusInp`、`XxxMaxSortInp` 等 | 其他操作 |
+
+### 6. 路由注册 `internal/router/genrouter/.go`
+
+```go
+package genrouter
+
+import "hotgo/internal/controller/admin/sys"
+
+func init() {
+ LoginRequiredRouter = append(LoginRequiredRouter, sys.XxxModule) // XXX模块
+}
+```
+
+新建此文件即可,`genrouter/init.go` 通过 `init()` 链自动加载,无需修改 `admin.go`。
+
+---
+
+## 字典与枚举规范
+
+**字典由后端统一维护**,前端通过固定接口拉取,禁止在前端硬编码枚举值。
+
+### 后端:定义与注册(`internal/consts/` 下对应文件)
+
+```go
+// 1. 定义常量
+const (
+ XxxStatusEnabled = 1 // 启用
+ XxxStatusDisable = 2 // 禁用
+)
+
+// 2. 定义选项(选择合适的样式函数)
+var XxxStatusOptions = []*model.Option{
+ dict.GenSuccessOption(XxxStatusEnabled, "启用"),
+ dict.GenWarningOption(XxxStatusDisable, "禁用"),
+}
+
+// 3. 在 init() 中注册(同文件)
+func init() {
+ dict.RegisterEnums("XxxStatusOptions", "XXX状态选项", XxxStatusOptions)
+}
+```
+
+**样式函数选择规则:**
+
+| 函数 | 适用场景 |
+|------|---------|
+| `dict.GenSuccessOption` | 正常、启用、成功 |
+| `dict.GenWarningOption` | 待处理、禁用、警告 |
+| `dict.GenErrorOption` | 失败、封禁、危险 |
+| `dict.GenInfoOption` | 信息类、中性状态 |
+| `dict.GenPrimaryOption` | 主要操作、强调 |
+| `dict.GenDefaultOption` | 默认、无特殊含义 |
+| `dict.GenHashOption` | 不确定数量的动态枚举 |
+
+### 后端:Logic 层中使用字典
+
+```go
+// 获取标签文本
+label := dict.GetOptionLabel(consts.XxxStatusOptions, in.Status)
+
+// 校验是否为合法值
+if !dict.HasOptionKey(consts.XxxStatusOptions, in.Status) {
+ return gerror.New("状态值不合法")
+}
+```
+
+### 前端:加载与使用字典
+
+**加载**(在 `model.ts` 的 `loadOptions()` 中):
+
+```ts
+export function loadOptions() {
+ dict.loadOptions(['XxxStatusOptions', 'sys_normal_disable']);
+}
+```
+
+**在 `model.ts` 的 columns 中渲染字典标签:**
+
+```ts
+import { useDictStore } from '@/store/modules/dict';
+const dict = useDictStore();
+
+// columns 中
+{
+ title: '状态',
+ key: 'status',
+ render(row) {
+ return dict.getLabel('XxxStatusOptions', row.status);
+ }
+}
+```
+
+**在搜索表单 schemas 中使用字典下拉:**
+
+```ts
+{
+ field: 'status',
+ component: 'NSelect',
+ label: '状态',
+ componentProps: {
+ options: computed(() => dict.getOptions('XxxStatusOptions')),
+ placeholder: '请选择状态',
+ },
+}
+```
+
+---
+
+## 插件(Addon)开发规范
+
+> 定位:独立、临时性、工具类型的功能推荐插件化开发,例如小游戏、广告管理、文章管理、小程序、微商城等。插件之间完全隔离,方便多项目复用。
+
+### 插件目录结构
+
+每个插件拥有完整的独立微架构,与主模块结构镜像,但 **包路径前缀为 `hotgo/addons//`**:
+
+```
+server/addons//
+├── main.go # 插件入口:定义 module 结构体,实现 Module 接口,init() 注册
+├── global/
+│ ├── global.go # 插件级全局变量
+│ └── init.go # Init(ctx, skeleton),GetSkeleton() 方法
+├── api/
+│ ├── admin/ # 后台接口契约(同主模块 api 写法)
+│ ├── api/ # 前台 API 接口契约
+│ └── home/ # 首页接口契约(如有)
+├── controller/
+│ ├── admin/sys/ # 后台薄控制器
+│ ├── api/ # 前台控制器
+│ └── home/ # 首页控制器(如有)
+├── logic/
+│ ├── logic.go # 匿名导入各 logic 子包触发 init()
+│ └── sys/ # 业务实现(同主模块 logic 写法)
+├── service/ # 插件内接口声明与注册(独立,不与主模块 service 混用)
+├── model/
+│ └── input/sysin/ # 插件内入参/出参(调用主模块服务时继承主模块 input 结构)
+├── router/
+│ ├── admin.go # 注册后台路由,使用 addons.RouterPrefix() 获取路由前缀
+│ ├── api.go # 注册前台路由
+│ ├── home.go # 注册首页路由(如有)
+│ ├── websocket.go # 注册 WebSocket 路由(如有)
+│ └── genrouter/
+│ ├── init.go # 插件版 genrouter:Register() 使用插件前缀
+│ └── *.go # 每个生成模块一个文件,追加到插件 LoginRequiredRouter
+├── consts/ # 插件内常量与字典(同主模块 consts 写法)
+├── crons/ # 插件定时任务(可选)
+├── queues/ # 插件消息队列消费者(可选)
+└── resource/ # 插件静态资源与模板(可选)
+```
+
+**对应前端目录:**
+
+```
+web/src/
+├── api/addons// # 插件前端 API 封装
+└── views/addons// # 插件前端页面
+```
+
+### 插件入口 `main.go`
+
+```go
+package
+
+import (
+ "context"
+ "github.com/gogf/gf/v2/net/ghttp"
+ _ "hotgo/addons//crons"
+ "hotgo/addons//global"
+ _ "hotgo/addons//logic"
+ _ "hotgo/addons//queues"
+ "hotgo/addons//router"
+ "hotgo/internal/library/addons"
+ "hotgo/internal/service"
+ "sync"
+)
+
+type module struct {
+ skeleton *addons.Skeleton
+ ctx context.Context
+ sync.Mutex
+}
+
+func init() { newModule() }
+
+func newModule() {
+ m := &module{
+ skeleton: &addons.Skeleton{
+ Label: "插件显示名",
+ Name: "", // 与目录名一致
+ Group: 1,
+ Brief: "简介",
+ Description: "详细描述",
+ Author: "作者",
+ Version: "v1.0.0",
+ },
+ ctx: gctx.New(),
+ }
+ addons.RegisterModule(m)
+}
+
+func (m *module) Start(option *addons.Option) (err error) {
+ global.Init(m.ctx, m.skeleton)
+ option.Server.Group("/", func(group *ghttp.RouterGroup) {
+ group.Middleware(service.Middleware().Addon)
+ router.Admin(m.ctx, group)
+ router.Api(m.ctx, group)
+ })
+ return
+}
+// 其余方法:Stop、Ctx、GetSkeleton、Install、Upgrade、UnInstall(默认留空)
+```
+
+### 插件路由前缀规则
+
+```
+后台:/admin//接口路径 → 对应 controller/admin/sys/
+前台:/api//接口路径 → 对应 controller/api/
+首页:/home//接口路径 → 对应 controller/home/
+WebSocket:/socket//接口路径
+```
+
+路由前缀通过 `addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name)` 自动生成,**禁止在路由文件里硬编码路径前缀**。
+
+### 插件 genrouter 与主模块的区别
+
+插件 `genrouter/init.go` 的 `Register()` 函数需要传入 `ctx` 和 `group`,并使用插件路由前缀:
+
+```go
+// 插件 genrouter/init.go
+func Register(ctx context.Context, group *ghttp.RouterGroup) {
+ prefix := addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name)
+ group.Group(prefix, func(group *ghttp.RouterGroup) {
+ group.Middleware(service.Middleware().AdminAuth)
+ if len(LoginRequiredRouter) > 0 {
+ group.Bind(LoginRequiredRouter...)
+ }
+ })
+}
+
+// 插件 genrouter/.go
+func init() {
+ LoginRequiredRouter = append(LoginRequiredRouter, sys.XxxModule)
+}
+```
+
+参考实现:`server/addons/hgexample/router/genrouter/`
+
+### 插件调用主模块服务
+
+**在插件 input 层继承主模块 input 结构,解耦参数依赖**,避免 import cycle:
+
+```go
+// 插件 model/input/sysin/config.go
+package sysin
+
+import "hotgo/internal/model/input/sysin"
+
+type UpdateConfigInp struct {
+ sysin.UpdateAddonsConfigInp
+}
+```
+
+```go
+// 插件 logic 中调用主模块服务
+import isc "hotgo/internal/service"
+
+func (s *sSysConfig) UpdateConfigByGroup(ctx context.Context, in sysin.UpdateConfigInp) error {
+ in.UpdateAddonsConfigInp.AddonName = global.GetSkeleton().Name
+ return isc.SysAddonsConfig().UpdateConfigByGroup(ctx, in.UpdateAddonsConfigInp)
+}
+```
+
+### 插件获取自身信息
+
+```go
+// 插件内部
+global.GetSkeleton()
+
+// 任意位置判断当前请求是否为插件请求
+contexts.IsAddonRequest(ctx)
+contexts.GetAddonName(ctx)
+```
+
+### 插件隐式注册
+
+在 `server/addons/modules/` 下新建 `.go`,内容仅含一行匿名导入:
+
+```go
+package modules
+
+import _ "hotgo/addons/"
+```
+
+### 新增插件检查清单
+
+**后端:**
+- [ ] `addons//main.go` — 插件入口,实现 Module 接口
+- [ ] `addons//global/` — global.go + init.go
+- [ ] `addons/modules/.go` — 隐式注册
+- [ ] `addons//service/` — 插件内接口声明(独立包)
+- [ ] `addons//logic/logic.go` — 匿名导入触发 init()
+- [ ] `addons//logic/sys/.go` — 业务实现
+- [ ] `addons//model/input/sysin/.go` — 入参/出参
+- [ ] `addons//api/admin//.go` — API 契约
+- [ ] `addons//controller/admin/sys/.go` — 薄控制器
+- [ ] `addons//router/admin.go` — 路由注册
+- [ ] `addons//router/genrouter/init.go` — 插件 genrouter
+- [ ] `addons//router/genrouter/.go` — 模块路由追加
+
+**前端:**
+- [ ] `web/src/api/addons//index.ts` — API 封装
+- [ ] `web/src/views/addons//model.ts` — State、schemas、columns
+- [ ] `web/src/views/addons//index.vue` — 列表页
+- [ ] `web/src/views/addons//edit.vue` — 编辑页
+
+参考实现:`server/addons/hgexample/`(完整插件示例)、`server/resource/generate/default/addon/`(生成模板)
+
+---
+
+## 标准 CRUD 接口清单
+
+| 接口 | method | 说明 |
+|------|--------|------|
+| `/xxx/list` | GET | 分页列表 |
+| `/xxx/view` | GET | 详情 |
+| `/xxx/edit` | POST | 新增/编辑(id>0 为编辑) |
+| `/xxx/delete` | POST | 删除(支持批量,传 ids) |
+| `/xxx/status` | POST | 启用/禁用状态切换 |
+| `/xxx/switch` | POST | 开关字段切换 |
+| `/xxx/maxSort` | GET | 获取最大排序值 |
+| `/xxx/export` | GET | 导出列表 |
+
+按实际需求裁剪,不强制全部实现。
+
+---
+
+## 前端目录结构
+
+```
+web/src/
+├── api//index.ts # HTTP 请求封装
+├── views//
+│ ├── index.vue # 列表页
+│ ├── edit.vue # 新增/编辑弹窗
+│ └── model.ts # State 类、rules、schemas、columns、loadOptions
+├── components/ # 通用组件(BasicTable、BasicForm、BasicModal 等)
+├── store/modules/dict.ts # 字典 store(loadOptions、getLabel、getOptions)
+└── utils/
+ ├── http/axios.ts # HTTP 封装(http.request / jumpExport)
+ └── dateUtil.ts # 日期工具(defRangeShortcuts 等)
+```
+
+---
+
+## 前端编码约定
+
+### API 文件 `api//index.ts`
+
+- 使用 `http.request`,禁止直接使用 axios
+- 函数名与接口语义一致:`List`、`Edit`、`Delete`、`View`、`Status`、`Switch`、`Export`、`MaxSort`
+- 导出接口用 `jumpExport('/xxx/export', params)`
+
+```ts
+import { http, jumpExport } from '@/utils/http/axios';
+
+export function List(params) {
+ return http.request({ url: '/xxxModule/list', method: 'get', params });
+}
+export function Edit(params) {
+ return http.request({ url: '/xxxModule/edit', method: 'POST', params });
+}
+export function Export(params) {
+ jumpExport('/xxxModule/export', params);
+}
+```
+
+### model.ts 结构
+
+- `class State`:属性与后端 entity 字段对应,提供合理默认值
+- `newState()`:工厂函数,支持深拷贝(`cloneDeep`)
+- `rules`:Naive UI 表单校验规则
+- `schemas`:搜索栏 `FormSchema[]`(`ref` 包装)
+- `columns`:表格列定义,含权限守卫的操作用 `hasPermission(['/xxx/edit'])`
+- `loadOptions()`:调用 `dict.loadOptions([...])`,预加载字典数据
+
+### 组件使用规范
+
+**必须优先使用 Naive UI 原生组件**,能用 Naive UI 实现的禁止自行封装替代组件:
+
+| 场景 | 必须使用的组件 |
+|------|--------------|
+| 表格 | 项目封装 `BasicTable`(基于 Naive UI) |
+| 表单 | 项目封装 `BasicForm`(基于 Naive UI) |
+| 弹窗 | `n-modal` 或项目封装 `BasicModal` |
+| 按钮 | `n-button`,类型用 `primary`/`default`/`error` 等语义值 |
+| 选择器 | `n-select`(字典下拉)、`n-tree-select`(树形) |
+| 开关 | `n-switch`,配合 Switch 接口 |
+| 输入框 | `n-input` |
+| 日期选择 | `n-date-picker`,范围选择配合 `defRangeShortcuts()` |
+| 图片渲染 | `renderImage(url)` |
+| 文件渲染 | `renderFile(url)` |
+| 成员信息 | `renderPopoverMemberSumma(summa)` |
+
+**禁止行为:**
+- 禁止引入 Element Plus、Ant Design Vue 等其他 UI 库
+- 禁止使用内联 style(使用 Naive UI 的 props 或 class)
+- 禁止在模板里硬编码字典值文本,必须通过 `dict.getLabel()` 渲染
+
+### 权限控制
+
+```ts
+import { usePermission } from '@/hooks/web/usePermission';
+const { hasPermission } = usePermission();
+
+// 模板中
+v-if="hasPermission(['/xxxModule/edit'])"
+
+// columns 中开关操作
+disabled: !hasPermission(['/xxxModule/switch'])
+```
+
+权限标识与后端路由路径保持一致,**路由由后端菜单数据驱动,禁止在源码里硬编码路由路径**。
+
+### Vue 3 代码规范
+
+- 使用 Composition API(`