Compare commits

157 Commits
Author SHA1 Message Date
Your Name ba837f4cae fix: use production logging profile
Deploy im-manager production / deploy (push) Successful in 4m33s
2026-10-19 01:58:31 +08:00
Your Name 0553424ef9 ci: deploy pro with docker compose
Deploy im-manager production / deploy (push) Successful in 10m56s
2026-10-18 20:11:07 +08:00
Austin 64037863ef feat: 添加毛隅管理模块的后台接口与菜单权限 2026-10-15 18:20:26 +08:00
Austin db2eb62277 fix: 删除过时的im_filemsglinks_msgid_bigint.sql文件
该文件是用于修复msgid字段类型从INT改为BIGINT的遗留SQL脚本,在完成数据库字段变更后已不再需要,删除后可避免后续误用该过时脚本。
2026-10-13 17:07:30 +08:00
Austin a3527a6d22 fix: 将 im_filemsglinks.msgid 字段类型从 INT 修改为 BIGINT
该字段原类型为 INT,最大值仅为 2147483647,而消息 ID 是雪花算法生成的 int64 类型值,插入时会超出范围导致失败。失败的 Kafka 消息持久化消费者会无限重试,阻塞分区及后续消息的持久化。此修改适用于 2026-10-13 之前部署的所有环境,全局非租户分片表仅需执行一次。
2026-10-13 15:39:49 +08:00
Austin 8d6618dac1 feat: 新增毛隅手记服务内部管理接口客户端及配置
新增 maoyuAdminApi 配置段到模板和示例配置,实现 maoyuadmin 客户端,包含请求签名、响应解析等功能,配套单元测试
2026-10-12 17:40:59 +08:00
Austin 2c5995073f feat: 新增禾圃集应用版本更新管理功能
新增禾圃集应用(appCode=garden)的版本策略管理功能,包括后端接口、前端API、页面路由、数据库迁移及相关常量配置,支持对不同平台和渠道的版本策略进行增删改查操作,与现有讯工捷使(appCode=im)版本管理功能保持一致的架构和交互逻辑。
2026-10-12 15:31:11 +08:00
Austin 315d97895b docs(cultivate/flowers): 更新阶段规则相关文本描述
修正了非 bloom 阶段规则的校验注释和错误提示文本,同时更新了编辑页的输入标签和占位符文本,使表述更准确对应后端校验逻辑。
2026-10-10 11:57:03 +08:00
Austin 3834af70b5 style(flowers): update modal selector to fix style priority issue
修改弹窗样式选择器,提升优先级以覆盖 naive-ui 运行时注入的固定宽度样式,解决 Teleport 弹窗的样式覆盖问题。
2026-10-10 10:26:02 +08:00
Austin 667e62e97e feat(cultivate): 添加花朵阶段中文标题并优化编辑页展示
新增阶段中文名映射及转换函数,用于显示更友好的阶段名称
在编辑页中应用阶段标题,同时调整下一阶段输入框为只读展示
优化弹窗宽度样式,适配不同屏幕尺寸
2026-10-10 10:08:22 +08:00
Austin 55ae8b2acd feat(cultivate-flower): 新增等待时长字段并更新阶段规则校验逻辑 2026-10-08 12:47:17 +08:00
Austin 5a7d8407bc refactor(web): 注释通知相关代码并添加临时注释说明
注释右上角通知铃铛及实时推送相关代码,添加说明后续恢复时取消注释
2026-09-30 15:37:33 +08:00
richjohnrambo 837a03a87e fix: cap mysql connection pool 2026-09-27 18:36:00 +08:00
richjohnrambo 0edbc63bc1 fix: keep tenant option list request 2026-09-25 23:31:33 +08:00
richjohnrambo 9e01f95a61 fix: allow bound tenant option loading 2026-09-25 23:27:11 +08:00
Austin fce8dbbe32 fix: backfill tenant via useForm channel and skip empty-tenant watch on search reset
- imSearchReset now receives setFieldsValue from useForm() instead of the
  template ref instance method, which was unreliable for backfilling tenantId
- imUser/imSensitiveWord watches skip tenantId<=0 so reset no longer fires
  policy-group/group requests that get rejected with empty tenant
- loadImTenantOptions wraps platform-branch TenantList in try/catch so a
  failed request no longer aborts page initialization
2026-09-24 20:32:32 +08:00
Austin 43f3581b1c fix: restore tenant filter on search reset in IM pages
BasicForm resetFields clears tenantId along with other fields, so the
auto-query after reset hit the empty-list guard (or was rejected by the
backend). Add a shared imSearchReset handler in imTenantOptions.ts that
refills the tenant select with its first option (bound users keep their
own tenant) before reloading, and wire it into the 9 IM list pages whose
reset did not already refill the tenant condition.
2026-09-24 17:02:08 +08:00
richjohnrambo 9924c1e522 fix: restore lockscreen timeout to 72 hours 2026-09-24 01:31:41 +08:00
richjohnrambo e87ac92cd1 Revert "refactor: 移除锁屏功能相关代码"
This reverts commit e002e45f82.
2026-09-24 01:30:49 +08:00
richjohnrambo e24a04a920 fix: prevent admin bootstrap merge helper race 2026-09-24 01:20:59 +08:00
richjohnrambo 32017a2fbf fix: avoid stale admin asset cache 2026-09-24 01:01:57 +08:00
richjohnrambo 369898bd7c feat: integrate cultivate admin internal APIs 2026-09-24 00:02:27 +08:00
Austin e002e45f82 refactor: 移除锁屏功能相关代码 2026-09-23 17:39:18 +08:00
richjohnrambo abadcceb19 feat: initialize shared tenant workbench data 2026-09-23 17:04:30 +08:00
Austin 5a07f63716 feat: 添加实时锁定状态控制解锁按钮显示
添加实时锁定状态字段到登录失败日志模型
并修改解锁按钮仅在账户当前仍锁定时显示
2026-09-23 13:18:35 +08:00
richjohnrambo 6c338626d6 fix: validate im registration platform role 2026-09-23 02:51:58 +08:00
richjohnrambo 22adc13acf feat: shard tenant topic and membership tables 2026-09-23 02:14:13 +08:00
richjohnrambo 432e7ac51a fix: keep only realname review policy on tenant 2026-09-23 02:06:52 +08:00
richjohnrambo dd12dbfe07 fix: cache admin permissions in redis 2026-09-23 00:30:40 +08:00
richjohnrambo 4fbc896d75 fix: sync tenant entry menu casbin rules 2026-09-23 00:07:20 +08:00
richjohnrambo 603e89e204 fix: query tenant entry tables without prefix 2026-09-22 23:52:08 +08:00
richjohnrambo abd5eb162a feat: add tenant entry application pages 2026-09-22 23:17:55 +08:00
Austin 935bfe17a0 fix(admin/member): 允许校验租户时包含初始化状态
修改租户校验逻辑,将允许的租户状态从仅活跃态扩展至包含初始化态,确保新建商户创建管理员操作正常完成
2026-09-22 19:38:54 +08:00
Austin 671ac2e1f7 fix(security-policy): 修复策略保存时租户行更新时间与事件投递阻塞问题
调整策略保存时的租户表更新逻辑,显式赋值updated_at避免自动填充干扰
修改策略变更事件投递逻辑,失败时仅告警审计不阻塞主流程
新增租户无策略时加载模板初始化配置的逻辑,提升默认策略灵活性
2026-09-22 19:08:53 +08:00
Austin dc3c45cd53 feat: 将安全策略模板化,新建商户时自动复制初始策略 2026-09-22 18:32:08 +08:00
richjohnrambo 9a9e30f94e feat: add tenant list id sorting 2026-09-22 17:32:08 +08:00
richjohnrambo 85b564e2ac refactor: merge tenant configuration into tenant registry 2026-09-22 16:47:40 +08:00
richjohnrambo 851eca97ed feat: support shared tenant database sharding 2026-09-22 15:21:34 +08:00
Austin 0596599db9 feat: add tenant bound restriction for IM dashboard and management pages
1. extract isTenantBound utility from user store logic
2. add disabled state to tenant select components across all IM pages
3. update policy tenant options logic to hide global option for bound tenants
4. add backend scope validation for IM admin operations
2026-09-22 11:34:40 +08:00
Austin 40ac52923e feat(imTenant): 新增商户管理员账号查看与密码修改功能
1.  新增编辑页管理员账号展示与密码修改字段,仅编辑态可见
2.  新增商户管理员密码重置逻辑,完善编辑场景密码校验
3.  补充超管可见控制:业务库、连接串、管理员信息非超管脱敏
4.  修复schema未使用响应式值的问题
2026-09-21 18:44:37 +08:00
Austin c9673ca871 feat: 新增商户管理员账号自动创建功能,优化租户权限控制
1.  后端实现租户创建时自动绑定创建管理员账号,支持超管/普通管理员权限区分
2.  前端适配超管权限控制业务库名、连接串等敏感字段展示与编辑
3.  优化租户数据库回退逻辑,未配置独立库时自动回落默认库
4.  调整租户列表与详情页的权限数据脱敏逻辑
2026-09-21 17:50:38 +08:00
Austin 197c6c86f4 fix: 修复多页面租户未就绪时表格提前请求问题,优化登录审计相关文案与列宽
1. 为imSensitiveWord、imUserPolicyGroup、imSecurityPolicy页面添加租户ID校验,避免表格挂载时因租户默认值未就绪发起无效请求
2. 更新imLoginFailureLog、imUserLoginHistory的搜索占位符与账号列宽
3. 修正后端登录审计相关结构体的字段注释描述
2026-09-21 16:25:12 +08:00
Austin a2f328f97e style(im/registrationInvite): 调整绑定用户提示的插槽封装与样式
将绑定用户未验证提示调整为插槽形式,并移除冗余的样式配置
2026-09-21 14:57:49 +08:00
Austin c4ab970fb7 fix(im/registrationInvite): add input verification for bound user search
1. add computed state to check if bind user input is unverified
2. disable confirm button and show warning tip when input is unverified
3. track last searched keyword to validate user input
4. add submission guard to prevent unvalidated submissions
2026-09-21 14:45:10 +08:00
Austin 8fad32e396 docs: update IM login lock error prompt copy and description
修正登录锁定错误提示文案,补充完整的时长格式化规则,更新示例文案匹配新规则
2026-09-21 13:57:53 +08:00
Austin 6f331a07fc style(imTenant): adjust action column width to 320px
widen the operation column to fit longer action buttons properly
2026-09-21 13:27:52 +08:00
Austin b4174a6412 feat: 新增IM联系我们字典配置,优化用户搜索与邀请绑定功能
1. 优化IM用户列表搜索逻辑,支持长数字用户ID精确匹配
2. 修复前端雪花ID精度丢失问题,改用字符串传输用户ID
3. 新增邀请码批量绑定用户功能,支持搜索绑定指定用户
4. 新增字典配置接口,新增联系我们字典SQL脚本
5. 完善字典数据变更事件推送,优化弹窗关闭与页面刷新逻辑
2026-09-21 13:11:08 +08:00
Austin 0381984939 Merge branch 'dev' of https://git.118im.com/im_team/im_manager into dev 2026-09-21 09:28:09 +08:00
Austin 6348ace38e feat(im security): add login failure lockout configuration feature
1. add APIs for login lockout config get and save
2. add backend service and controller for login lockout config
3. refactor frontend to separate login lockout config from main policy
4. update default login lockout policy values
5. add permission sql and docking documentation
2026-09-21 09:28:03 +08:00
richjohnrambo e8dd1eaa7d feat: 增加商户消息加密密钥管理 2026-09-20 23:43:33 +08:00
richjohnrambo 42cfe232fe fix: IM设置菜单更名为平台设置 2026-09-20 22:43:57 +08:00
richjohnrambo 4ae69706a5 fix: 区分IM系统设置菜单标题 2026-09-20 22:31:54 +08:00
richjohnrambo 3ef328a5a3 fix: 隐藏内置超管时保留角色树 2026-09-20 22:03:51 +08:00
richjohnrambo 2b93d27a4e fix: 角色列表隐藏内置超管 2026-09-20 21:53:38 +08:00
richjohnrambo 97990785cb fix: 平台超管权限走角色配置 2026-09-20 21:50:43 +08:00
richjohnrambo b68c048383 fix: 平台超管可管理后台角色 2026-09-20 21:48:10 +08:00
richjohnrambo f154b9e3c3 fix: 按角色规范后台用户商户绑定 2026-09-20 21:03:54 +08:00
richjohnrambo e2ca0607af fix: 平台超管拥有全部商户数据范围 2026-09-20 20:05:08 +08:00
richjohnrambo 6afeb65b91 feat: add tenant realname review policy 2026-09-20 18:31:46 +08:00
richjohnrambo e5ab79c40d fix: 拆分商户新增和编辑权限 2026-09-20 17:08:50 +08:00
Austin 8675fe333d feat(imLoginFailureLog): 用户登录密码错误次数锁定与解锁能力(管理端)
- 安全策略登录限频由 JSON 文本改为结构化表单(次数/锁定分钟/窗口分钟),编辑校验同步扩展
- 失败日志新增解锁入口:/imLoginFailureLog/unlock 经 internal 通道调用 im-server 释放锁定
- 失败日志模型补充 accountHash 字段,解锁按钮按 risk_action=account_locked 展示
- 租户业务库初始化模板补充 im_login_lockouts 等表;新增解锁按钮菜单权限 SQL
2026-09-20 17:04:19 +08:00
richjohnrambo fd4ff85191 fix: 限制IM租户列表为当前租户 2026-09-20 16:53:38 +08:00
richjohnrambo 6bf364ec0b fix: 修复养成管理接口参数过滤 2026-09-20 16:53:38 +08:00
Austin 47ed097923 refactor(imWorkOrder): 优化工单分类和目标类型的展示逻辑
将工单分类和目标类型的格式化逻辑抽离到model文件中,统一处理字典映射展示,替换原有的硬编码空值占位,同时修复列表页和详情页的展示不一致问题
2026-09-20 10:53:41 +08:00
Austin e5cfc80916 chore(imFile): 临时隐藏用途相关功能
注释掉页面、表单和列表中的用途相关代码,后续需要时可恢复
2026-09-20 10:44:27 +08:00
richjohnrambo c7265252d8 feat: 完善养成管理后台功能 2026-09-19 17:07:47 +08:00
richjohnrambo f6766d3dbd feat: 新增养成管理后台 2026-09-19 14:36:30 +08:00
richjohnrambo 7c8b4d9b7c feat: add friend add and curfew controls 2026-09-18 10:55:33 +08:00
richjohnrambo 348cbcaf96 fix: allow multiple config api service names 2026-09-17 22:55:21 +08:00
richjohnrambo 2a35cb4358 fix: update uid encryption key seed 2026-09-17 16:59:47 +08:00
richjohnrambo be6c5b525c fix: seed uid encryption config 2026-09-17 15:56:23 +08:00
richjohnrambo 9ed8aaf142 refactor: reuse global aliyun moderation config 2026-09-17 00:25:04 +08:00
richjohnrambo 4ed54ca392 test: initialize admin member service in scope tests 2026-09-16 23:45:21 +08:00
richjohnrambo 5173bc0aad fix: return default moderation policy when unpublished 2026-09-16 23:30:10 +08:00
richjohnrambo fec2a43b9c feat: add tenant content moderation controls 2026-09-16 22:21:42 +08:00
Austin 32491e9cdd fix: repair healthz mysql check and im tenant creation
- healthz: Scan(new(int)) is not supported by GoFrame, use .One() so
  the mysql check no longer reports a false failure
- im_tenant: set updated_by on insert for both im_tenant and
  im_tenant_config, otherwise new tenant creation fails with
  "Field 'updated_by' doesn't have a default value"
- gitignore: exclude .trae/ local debugging artifacts
2026-09-16 18:45:37 +08:00
richjohnrambo fe5c7af7e2 fix: show bound tenant in im menus 2026-09-16 16:54:12 +08:00
richjohnrambo 156e8b9c9f fix: align workbench default secret 2026-09-16 16:05:39 +08:00
richjohnrambo f8aaae42ff fix: use workbench service dns 2026-09-16 15:41:32 +08:00
richjohnrambo 82379b8823 fix: configure workbench service secret fallback 2026-09-16 15:21:28 +08:00
richjohnrambo 3e40554229 fix: fallback workbench admin secret 2026-09-16 14:28:42 +08:00
richjohnrambo e159f9a88e feat: proxy workbench admin through service 2026-09-16 14:03:58 +08:00
richjohnrambo c258e0473b fix: resolve bound im tenant for company admins 2026-09-16 13:19:55 +08:00
richjohnrambo 5dbbf39cce chore: update test environment defaults 2026-09-15 11:59:14 +08:00
richjohnrambo 50a2781b23 fix: avoid gf cli install in docker build 2026-09-14 14:27:23 +08:00
richjohnrambo a6f7ac41b0 fix: remove duplicate IM frontend API exports 2026-09-14 14:13:39 +08:00
richjohnrambo c1a6a41575 fix: update admin test environment config 2026-09-14 14:06:41 +08:00
Your NameandClaude Sonnet 5 f44e8adb72 ci: bring k3s deploy workflow over from main
This commit only ever landed on main (from when main was still the
default branch); dev's copy was still the stale blue-green version.
Bringing main's file over as-is before making dev the default branch,
so neither branch ends up missing it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 12:28:55 +08:00
richjohnrambo bd19a594ae Merge branch 'main' into dev
# Conflicts:
#	docs/backstage/IM-Kafka接入方案.md
#	docs/backstage/IM-Kafka接入范围识别.md
#	server/api/admin/imconfiginternal/im_config.go
#	server/api/admin/imuser/im_user.go
#	server/internal/consts/im_kafka.go
#	server/internal/controller/admin/sys/im_user.go
#	server/internal/controller/internalapi/imconfig/im_config.go
#	server/internal/library/imadmin/client.go
#	server/internal/library/imadmin/client_test.go
#	server/internal/library/imadmin/internal.go
#	server/internal/library/imkafka/command.go
#	server/internal/library/imtenant/db.go
#	server/internal/library/imtenant/db_test.go
#	server/internal/library/queue/kafkamq.go
#	server/internal/library/queue/queue.go
#	server/internal/logic/admin/member.go
#	server/internal/logic/sys/im_dead_letter.go
#	server/internal/logic/sys/im_group.go
#	server/internal/logic/sys/im_invite.go
#	server/internal/logic/sys/im_kafka_audit.go
#	server/internal/logic/sys/im_kafka_command.go
#	server/internal/logic/sys/im_tenant.go
#	server/internal/logic/sys/im_user.go
#	server/internal/model/input/sysin/im_group.go
#	server/internal/model/input/sysin/im_invite.go
#	server/internal/model/input/sysin/im_user.go
#	server/internal/queues/im_admin_command_result.go
#	server/internal/queues/im_audit_event.go
#	server/internal/queues/im_dead_letter.go
#	server/internal/service/sys.go
#	server/manifest/config/config.example.yaml
#	server/storage/data/generate/im_group_menu.sql
#	server/storage/data/generate/im_user_menu.sql
#	server/storage/data/im_registration_invite_hotgo.sql
#	web/src/views/im/registrationInvite/BatchViewModal.vue
#	web/src/views/im/registrationInvite/index.vue
#	web/src/views/im/registrationInvite/model.ts
#	web/src/views/imDeadLetter/index.vue
#	web/src/views/imDeadLetter/model.ts
#	web/src/views/imGroup/governance.vue
#	web/src/views/imGroup/members.vue
#	web/src/views/imKafkaAudit/model.ts
#	web/src/views/imKafkaAudit/view.vue
#	web/src/views/imKafkaCommand/index.vue
#	web/src/views/imKafkaCommand/model.ts
#	web/src/views/imKafkaCommand/view.vue
#	web/src/views/imUser/ResetPasswordModal.vue
#	web/src/views/imUser/governance.vue
#	web/src/views/imUser/index.vue
#	web/src/views/imUser/model.ts
#	web/src/views/imUser/view.vue
2026-09-13 23:43:51 +08:00
richjohnrambo 7aee265721 im 管理后台 2026-09-13 23:39:18 +08:00
richjohnrambo 8b30b8241c feat: refine IM admin management workflows 2026-09-13 23:25:53 +08:00
richjohnrambo 6e65935e3c feat: manage global app release policies 2026-09-12 17:08:10 +08:00
richjohnrambo 2fb5102add feat: add invite user binding 2026-09-11 10:46:20 +08:00
richjohnrambo 68d9bafbdd fix: show sensitive word action column 2026-09-11 01:20:41 +08:00
richjohnrambo d3d2235ca3 fix: refine sensitive word table actions 2026-09-11 01:11:35 +08:00
richjohnrambo 26e511113b feat: add short IM user numbers 2026-09-10 21:51:23 +08:00
richjohnrambo 047df08f84 feat: separate workbench admin features 2026-09-10 01:02:35 +08:00
richjohnrambo 27a368b386 feat: 统一IM后台商户文案和默认选择 2026-09-09 14:28:44 +08:00
richjohnrambo da60b52be2 feat: improve group owner and status display 2026-09-09 11:10:59 +08:00
richjohnrambo 964746c19b feat: add tenant login IP whitelist management 2026-09-09 09:39:55 +08:00
richjohnrambo 99307f1c98 fix: 完善IM用户状态与分组展示 2026-09-08 22:16:51 +08:00
richjohnrambo 7d54bf785a feat: 完善IM用户管理与治理操作 2026-09-08 10:54:01 +08:00
richjohnrambo 5f3f6913b8 feat: 优化群聊消息手动查询 2026-09-07 21:52:00 +08:00
richjohnrambo af2803ef1f data: 增加中文敏感词测试词库 2026-09-07 21:43:26 +08:00
richjohnrambo fdc86ea6bf fix: 允许IM平台管理员选择租户 2026-09-07 21:11:20 +08:00
richjohnrambo 5fac9a0669 feat: 重组IM后台菜单层级 2026-09-07 20:33:09 +08:00
richjohnrambo e5b8db41ea fix: 兼容租户标准MySQL连接串 2026-09-07 18:47:50 +08:00
richjohnrambo 845f19fd1c fix: 修复多级菜单页面无法打开 2026-09-07 17:25:36 +08:00
richjohnrambo ed9cc03514 test: 记录IM后台发布复测结果 2026-09-07 17:03:00 +08:00
richjohnrambo 7839dce0e6 fix: 修正IM策略页面字典选项调用 2026-09-07 16:47:09 +08:00
richjohnrambo 37d708c5a1 test: 补充IM后台测试用例与问题记录 2026-09-07 16:31:50 +08:00
richjohnrambo 16cc4567da fix: 修正IM内部接口启动示例配置 2026-09-07 12:06:10 +08:00
richjohnrambo bb87d01644 feat: 完成鸽达达后台安全与审计改造 2026-09-07 11:50:29 +08:00
richjohnrambo 0a21d7289e Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	server/api/admin/imgroup/im_group.go
#	server/api/admin/imuser/im_user.go
#	server/internal/controller/admin/sys/im_group.go
#	server/internal/controller/admin/sys/im_user.go
#	server/internal/library/imtenant/db.go
#	server/internal/logic/admin/member.go
#	server/internal/logic/sys/im_admin_scope.go
#	server/internal/logic/sys/im_group.go
#	server/internal/logic/sys/im_invite.go
#	server/internal/logic/sys/im_registration.go
#	server/internal/logic/sys/im_tenant.go
#	server/internal/logic/sys/im_user.go
#	server/internal/model/input/sysin/im_group.go
#	server/internal/model/input/sysin/im_invite.go
#	server/internal/model/input/sysin/im_user.go
#	server/internal/router/genrouter/im_invite.go
#	server/internal/router/genrouter/im_registration.go
#	server/internal/service/sys.go
#	server/manifest/config/config.example.yaml
#	server/storage/data/generate/im_audit_log_menu.sql
#	server/storage/data/generate/im_group_menu.sql
#	server/storage/data/generate/im_realname_menu.sql
#	server/storage/data/generate/im_tenant_menu.sql
#	server/storage/data/generate/im_user_menu.sql
#	server/storage/data/generate/im_work_order_menu.sql
#	server/storage/data/im_registration_invite_hotgo.sql
#	web/src/api/imGroup/index.ts
#	web/src/api/imUser/index.ts
#	web/src/views/im/registrationInvite/BatchViewModal.vue
#	web/src/views/im/registrationInvite/CreateModal.vue
#	web/src/views/im/registrationInvite/index.vue
#	web/src/views/im/registrationInvite/model.ts
#	web/src/views/imGroup/governance.vue
#	web/src/views/imGroup/members.vue
#	web/src/views/imUser/index.vue
#	web/src/views/imUser/model.ts
#	web/src/views/imUser/view.vue
#	web/src/views/system/config/ImRegistrationSetting.vue
2026-09-04 12:01:22 +08:00
richjohnrambo f7f8cc0ef0 feat: add im kafka admin integration 2026-09-04 11:57:38 +08:00
Your NameandClaude Sonnet 5 ab2b84c9fa ci: 部署时透传 imAdminApi/imInternalApi/imConfigApi secret
commit 25abba8 把 config.template 里 imAdminApi/imInternalApi/imConfigApi
三段的 baseUrl/serviceId/serviceName/secret 从硬编码改成了环境变量占位符,
但 deploy workflow 没有跟着传这几个 secret。这次改动和 im-server 那边
commit 7193ba2 是同一批,im-server 侧已经因为漏传导致容器反复重启(本次
故障);这几个 secret 已经在 Gitea 里配好,提前补上避免下次部署 im-manager
时重演同样的问题。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 22:37:09 +08:00
richjohnrambo 25abba8eeb feat: 完善IM后台Kafka与组织架构管理 2026-09-03 17:11:29 +08:00
richjohnrambo 5a2ed4b2a4 fix: use existing dict option API in im views 2026-09-03 14:53:26 +08:00
richjohnrambo 82675c7500 fix: add im missing menu patch 2026-08-28 16:30:02 +08:00
richjohnrambo 1b86314c5f test: guard im tables from default db prefix 2026-08-28 16:19:32 +08:00
richjohnrambo eff2f54641 fix: use unprefixed kafka audit tables 2026-08-28 16:16:25 +08:00
richjohnrambo ed4f186d8e fix: normalize kafka version config 2026-08-28 15:36:56 +08:00
richjohnrambo a938c6cb23 fix: enable kafka in root docker image 2026-08-28 15:19:50 +08:00
richjohnrambo cd354e9e1b fix: enable kafka in admin docker defaults 2026-08-28 15:09:36 +08:00
richjohnrambo 6b5ef0a911 fix: query im kafka tables with gf raw helpers 2026-08-28 14:56:02 +08:00
richjohnrambo f98f3e146b fix: use unprefixed im kafka tables 2026-08-28 14:44:00 +08:00
richjohnrambo cde4480b51 feat: publish password reset via kafka 2026-08-28 14:18:27 +08:00
richjohnrambo 6e08013fd1 fix: stringify im admin json fields 2026-08-28 13:34:40 +08:00
richjohnrambo d7578efa2b fix: return im user ids as strings 2026-08-28 13:07:17 +08:00
richjohnrambo da880bc6d6 chore: log im internal query transport errors 2026-08-28 11:55:27 +08:00
richjohnrambo 673806ba2a fix: keep im api settings in config 2026-08-28 01:56:51 +08:00
richjohnrambo 1a515ef183 fix: configure im internal api from env 2026-08-28 01:44:30 +08:00
richjohnrambo a04abb0cc8 fix: set admin frontend cache headers 2026-08-28 01:42:14 +08:00
richjohnrambo 296c9a22a8 fix: stabilize kafka queue startup 2026-08-28 01:23:36 +08:00
richjohnrambo f93b935ea5 chore: use internal im service url 2026-08-28 01:08:51 +08:00
richjohnrambo e3751d9fa6 chore: use public im internal api 2026-08-28 00:48:42 +08:00
richjohnrambo a6f6f23422 chore: configure im internal api auth 2026-08-28 00:40:40 +08:00
richjohnrambo 8c54914f9a chore: configure test kafka queue 2026-08-28 00:35:10 +08:00
richjohnrambo 33bf0f8625 feat: support kafka scram queue config 2026-08-28 00:31:08 +08:00
richjohnrambo 4779214591 feat: add im kafka admin integration 2026-08-28 00:05:54 +08:00
richjohnrambo d53b0c1b62 feat: add IM admin P2 configuration modules 2026-08-22 00:36:38 +08:00
richjohnrambo 5c3f6ae58d feat: add IM file policy and org exports 2026-08-21 23:07:06 +08:00
richjohnrambo 204f96e07a feat: add IM org and notification admin 2026-08-21 17:54:54 +08:00
richjohnrambo c89e35d0e0 feat: add IM admin P1 operations 2026-08-21 17:25:19 +08:00
richjohnrambo 77b19a8157 feat: complete IM group governance actions 2026-08-21 16:34:55 +08:00
richjohnrambo 21a5b97ac8 feat: add IM governance admin enhancements 2026-08-21 16:06:29 +08:00
richjohnrambo 543c7b624e feat: expand IM admin controls 2026-08-21 15:09:39 +08:00
richjohnrambo a2abaef3a6 feat: add IM admin management 2026-08-21 01:06:19 +08:00
richjohnrambo c3676f9744 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	web/pnpm-workspace.yaml
2026-08-19 00:50:10 +08:00
richjohnrambo 89ba6bcff8 feat: add tenant-aware IM management console 2026-08-19 00:31:09 +08:00
richjohnrambo 642b7ec5da im 管理后台 2026-08-17 09:52:02 +08:00
Your Name 5ac3a5b96c 修复容器崩溃: hggen初始化需要hack/config.yaml, 运行时镜像未拷贝
hotgo/internal/library/hggen.InIt()在HTTP命令初始化时会读取hack/config.yaml
(在线代码生成功能依赖), 之前只拷贝了manifest目录导致运行时找不到该文件而致命退出
2026-08-12 11:40:13 +08:00
Your Name 616d11202e 修复容器崩溃循环: alpine运行时镜像缺少tzdata
现象:容器起来后一直重启,日志显示
"time.LoadLocation failed for zone Asia/Shanghai: unknown time zone"。
alpine默认不带IANA时区数据库,补上tzdata包解决。
2026-08-12 11:32:37 +08:00
Your Name b315d20197 新增Gitea Actions蓝绿发布workflow
手动触发(workflow_dispatch),构建镜像后调用宿主机上的
/opt/apps/im-manager/deploy.sh完成蓝绿切换。
2026-08-12 11:26:48 +08:00
Your Name f711fec00b 接入Docker蓝绿部署:自包含多阶段构建、配置外部化
- 新增根目录Dockerfile:多阶段构建(Vue前端 + Go后端),包含main.go依赖的
  internal/packed资源打包步骤(原来依赖gf build外部产出,未提交进仓库)
- 新增server/manifest/config/config.template:数据库/Redis连接串、
  token密钥等敏感配置改为占位符,运行时通过entrypoint.sh用envsubst生成
  真正的config.yaml,不再需要在仓库里维护包含真实密码的config.yaml
- entrypoint.sh改为先渲染配置再启动
- 修复web/pnpm-lock.yaml与package.json不同步的问题(有依赖被加进
  package.json但没重新生成锁文件)
- 新增web/pnpm-workspace.yaml:较新版本pnpm默认禁止依赖包运行构建脚本
  (供应链安全特性),需要显式在这里批准esbuild/@swc/core等的构建脚本,
  否则CI环境下frozen-lockfile安装会直接失败
2026-08-12 11:26:13 +08:00
richjohnrambo 331a55751d im 管理后台 2026-08-11 23:13:51 +08:00
richjohnrambo 0397fe5f22 Initial commit 2026-08-11 15:11:11 +00:00
2164 changed files with 244142 additions and 1 deletions
Vendored
BIN
View File
Binary file not shown.
+68
View File
@@ -0,0 +1,68 @@
name: Deploy im-manager production
on:
push:
branches:
- pro
workflow_dispatch:
concurrency:
group: production-im-manager
cancel-in-progress: false
permissions:
contents: read
env:
REGISTRY: git.olns.shop
IMAGE: git.olns.shop/pro/im_manager
SERVICE: im-manager
DEPLOY_HOST: 145.223.69.9
DEPLOY_USER: olns-deploy
jobs:
deploy:
runs-on: deploy-host
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- name: Log in to Gitea Container Registry
env:
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
run: |
set -euo pipefail
printf '%s' "$REGISTRY_TOKEN" | docker login "$REGISTRY" -u admin --password-stdin
- name: Build and push image
env:
GITHUB_SHA: ${{ github.sha }}
run: |
set -euo pipefail
SHORT_SHA="$(printf '%.12s' "$GITHUB_SHA")"
docker build -t "${IMAGE}:pro" -t "${IMAGE}:${SHORT_SHA}" .
docker push "$IMAGE:pro"
docker push "$IMAGE:$SHORT_SHA"
- name: Deploy Compose service
env:
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
DEPLOY_KNOWN_HOSTS: ${{ secrets.DEPLOY_KNOWN_HOSTS }}
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
run: |
set -euo pipefail
install -d -m 700 "$HOME/.ssh"
KEY_FILE="$(mktemp "$HOME/.ssh/olns-deploy.XXXXXX")"
cleanup() {
shred -u "$KEY_FILE" 2>/dev/null || true
}
trap cleanup EXIT
printf '%s\n' "$DEPLOY_SSH_KEY" > "$KEY_FILE"
chmod 600 "$KEY_FILE"
printf '%s\n' "$DEPLOY_KNOWN_HOSTS" > "$HOME/.ssh/known_hosts"
chmod 600 "$HOME/.ssh/known_hosts"
SSH_ARGS=(-i "$KEY_FILE" -o BatchMode=yes -o StrictHostKeyChecking=yes)
printf '%s' "$REGISTRY_TOKEN" | ssh "${SSH_ARGS[@]}" "$DEPLOY_USER@$DEPLOY_HOST" \
"docker login git.olns.shop -u admin --password-stdin"
ssh "${SSH_ARGS[@]}" "$DEPLOY_USER@$DEPLOY_HOST" \
"cd /opt/olns && docker compose pull im-manager && docker compose up -d --no-deps --wait im-manager"
+3
View File
@@ -163,3 +163,6 @@ dist
.yarn/install-state.gz
.pnp.*
# Trae local debugging artifacts
.trae/
+8
View File
@@ -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
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/im_manager.iml" filepath="$PROJECT_DIR$/.idea/im_manager.iml" />
</modules>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+960
View File
@@ -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)
│ └── <addonName>/ # 插件目录,与主模块结构镜像
├── api/admin/<module>/ # 主模块 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/<module>/<module>.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/<module>.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/<module>.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/<module>.go`
| 类型 | 用途 |
|------|------|
| `XxxUpdateFields` | 更新时字段白名单 |
| `XxxInsertFields` | 新增时字段白名单 |
| `XxxEditInp` | 嵌入 `entity.XxxTable`,含 `Filter()` 校验方法 |
| `XxxListInp` | 列表查询入参,嵌入 `form.PageInp` |
| `XxxListModel` | 列表返回字段 |
| `XxxViewInp` / `XxxViewModel` | 详情入参/出参 |
| `XxxDeleteInp` | 删除入参(通常含 `Ids []int64`) |
| `XxxStatusInp`、`XxxMaxSortInp` 等 | 其他操作 |
### 6. 路由注册 `internal/router/genrouter/<module>.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/<addonName>/`**:
```
server/addons/<addonName>/
├── 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/<addonName>/ # 插件前端 API 封装
└── views/addons/<addonName>/ # 插件前端页面
```
### 插件入口 `main.go`
```go
package <addonName>
import (
"context"
"github.com/gogf/gf/v2/net/ghttp"
_ "hotgo/addons/<addonName>/crons"
"hotgo/addons/<addonName>/global"
_ "hotgo/addons/<addonName>/logic"
_ "hotgo/addons/<addonName>/queues"
"hotgo/addons/<addonName>/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: "<addonName>", // 与目录名一致
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/<addonName>/接口路径 → 对应 controller/admin/sys/
前台:/api/<addonName>/接口路径 → 对应 controller/api/
首页:/home/<addonName>/接口路径 → 对应 controller/home/
WebSocket:/socket/<addonName>/接口路径
```
路由前缀通过 `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/<module>.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/` 下新建 `<addonName>.go`,内容仅含一行匿名导入:
```go
package modules
import _ "hotgo/addons/<addonName>"
```
### 新增插件检查清单
**后端:**
- [ ] `addons/<addonName>/main.go` — 插件入口,实现 Module 接口
- [ ] `addons/<addonName>/global/` — global.go + init.go
- [ ] `addons/modules/<addonName>.go` — 隐式注册
- [ ] `addons/<addonName>/service/` — 插件内接口声明(独立包)
- [ ] `addons/<addonName>/logic/logic.go` — 匿名导入触发 init()
- [ ] `addons/<addonName>/logic/sys/<module>.go` — 业务实现
- [ ] `addons/<addonName>/model/input/sysin/<module>.go` — 入参/出参
- [ ] `addons/<addonName>/api/admin/<module>/<module>.go` — API 契约
- [ ] `addons/<addonName>/controller/admin/sys/<module>.go` — 薄控制器
- [ ] `addons/<addonName>/router/admin.go` — 路由注册
- [ ] `addons/<addonName>/router/genrouter/init.go` — 插件 genrouter
- [ ] `addons/<addonName>/router/genrouter/<module>.go` — 模块路由追加
**前端:**
- [ ] `web/src/api/addons/<addonName>/index.ts` — API 封装
- [ ] `web/src/views/addons/<addonName>/model.ts` — State、schemas、columns
- [ ] `web/src/views/addons/<addonName>/index.vue` — 列表页
- [ ] `web/src/views/addons/<addonName>/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/<module>/index.ts # HTTP 请求封装
├── views/<module>/
│ ├── 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/<module>/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(`<script setup>`)
- 响应式数据用 `ref` / `reactive`,计算属性用 `computed`
- 字典选项传给组件时用 `computed(() => dict.getOptions('XxxOptions'))`,保持响应式
---
## 新增 CRUD 模块检查清单
**后端(必须全部完成,顺序建议从下往上):**
- [ ] `internal/consts/<module>.go` — 常量定义、选项变量、`init()` 注册字典
- [ ] 使用 goframe CLI 生成:`entity`、`do`、`dao/internal`、`dao`(禁止手写)
- [ ] `internal/model/input/sysin/<module>.go` — 入参/出参/过滤模型
- [ ] `internal/service/sys.go` — 追加接口声明与注册函数
- [ ] `internal/logic/sys/<module>.go` — 业务实现
- [ ] `internal/controller/admin/sys/<module>.go` — 薄控制器
- [ ] `api/admin/<module>/<module>.go` — API 契约
- [ ] `internal/router/genrouter/<module>.go` — 路由注册(`LoginRequiredRouter` 追加)
**前端(必须全部完成):**
- [ ] `web/src/api/<module>/index.ts` — HTTP 封装
- [ ] `web/src/views/<module>/model.ts` — State、schemas、columns、rules、loadOptions
- [ ] `web/src/views/<module>/index.vue` — 列表页
- [ ] `web/src/views/<module>/edit.vue` — 编辑页
---
## 参考实现
**所有新模块必须严格对齐以下文件的风格,生成前请逐一阅读:**
**主模块 CRUD 参考:**
| 文件 | 说明 |
|------|------|
| `server/internal/consts/status.go` | 字典常量定义与注册标准写法 |
| `server/api/admin/curddemo/curddemo.go` | API 契约标准写法 |
| `server/internal/controller/admin/sys/curd_demo.go` | 薄控制器标准写法 |
| `server/internal/logic/sys/curd_demo.go` | Logic 标准写法(含关联查询、导出、字段过滤) |
| `server/internal/model/input/sysin/curd_demo.go` | 入参/出参模型标准写法 |
| `server/internal/router/genrouter/curd_demo.go` | 主模块路由注册标准写法 |
| `web/src/api/curdDemo/index.ts` | 前端 API 封装标准写法 |
| `web/src/views/curdDemo/model.ts` | 前端 model 标准写法(含字典加载) |
| `web/src/views/curdDemo/index.vue` | 列表页标准写法 |
| `web/src/views/curdDemo/edit.vue` | 编辑页标准写法 |
**插件参考(以 hgexample 为标准):**
| 文件 | 说明 |
|------|------|
| `server/addons/hgexample/main.go` | 插件入口标准写法 |
| `server/addons/hgexample/global/init.go` | 插件 global 标准写法 |
| `server/addons/hgexample/router/admin.go` | 插件路由注册标准写法 |
| `server/addons/hgexample/router/genrouter/init.go` | 插件 genrouter 标准写法 |
| `server/addons/hgexample/router/genrouter/tenant_order.go` | 插件模块路由追加标准写法 |
| `server/addons/hgexample/logic/sys/tenant_order.go` | 插件业务逻辑标准写法 |
| `server/addons/hgexample/logic/sys/config.go` | 插件调用主模块服务标准写法 |
代码生成模板:
- 主模块 CRUD:`server/resource/generate/default/curd/`
- 插件脚手架:`server/resource/generate/default/addon/`
以上模板可参考逻辑,**禁止直接修改模板文件**。
---
## 错误处理规范
### 基本原则
- 业务错误直接用 `gerror.New("描述清晰的中文信息")` 返回,GoFrame 框架会统一处理响应码
- 错误信息要面向用户,清晰说明**发生了什么**,而不是堆栈路径
### 错误创建方式
```go
import "github.com/gogf/gf/v2/errors/gerror"
// 普通业务错误(最常用)
return gerror.New("用户名已存在")
// 包装底层错误,追加上下文(调用第三方/dao 层出错时使用)
if err := dao.User.Ctx(ctx).Data(data).Insert(); err != nil {
return gerror.Wrap(err, "创建用户失败")
}
// 带格式化参数
return gerror.Newf("订单 %d 状态不合法,当前状态:%d", in.Id, order.Status)
```
### 错误传递原则
- **logic 层**:遇到底层错误用 `gerror.Wrap` 追加上下文后返回;纯业务校验失败用 `gerror.New` 直接返回
- **controller 层**:直接 `return` 透传 logic 的 error,**不再包装**,不打印日志(框架统一处理)
- **禁止**在 controller 层 `fmt.Println(err)` 或 `g.Log().Error` 打印已经会被框架记录的错误
---
## 缓存使用规范
### 统一使用 `cache.Instance()`
**禁止直接调用 `g.Redis().Do()`**,项目统一通过 `cache.Instance()` 操作缓存,底层适配器(Memory / Redis / File)由配置决定,业务层无需关心。
```go
import (
"hotgo/internal/library/cache"
"github.com/gogf/gf/v2/os/gcache"
"time"
)
// 设置缓存(带过期时间)
err := cache.Instance().Set(ctx, "user:info:1", userInfo, 30*time.Minute)
// 获取缓存
val, err := cache.Instance().Get(ctx, "user:info:1")
if err != nil || val.IsNil() {
// 缓存未命中,查数据库
}
// 删除缓存
_, err = cache.Instance().Remove(ctx, "user:info:1")
// GetOrSet:缓存不存在时自动执行函数并写入(推荐用于只读类缓存)
val, err := cache.Instance().GetOrSet(ctx, "user:info:1", func(ctx context.Context) (interface{}, error) {
return dao.AdminMember.Ctx(ctx).Where(...).One()
}, 30*time.Minute)
```
### 缓存 Key 命名规范
- 格式:`模块:实体:唯一标识`,例如:`user:info:1`、`config:site:basic`、`dict:options:XxxStatus`
- 同一模块的 Key 统一在 `internal/consts/cache.go`(或对应模块的 consts 文件)中定义为常量,禁止散落在 logic 里硬编码
- 插件缓存 Key 加插件名前缀:`hgexample:order:1`
### 缓存使用原则
- 更新或删除数据后,**主动清除**相关缓存,不依赖过期自动失效
- 缓存时间:频繁更新的数据(配置、状态)用较短时间(5~30 分钟);基本不变的数据(字典、枚举)可用更长时间
- 缓存穿透场景:查询结果为空时也写入短时缓存(如 1 分钟)防止击穿
---
## 日志规范
### 日志级别选择
| 级别 | 方法 | 适用场景 |
|------|------|---------|
| Info | `g.Log().Info` / `g.Log().Infof` | 正常业务流程的关键节点(登录成功、订单创建、支付回调等) |
| Warning | `g.Log().Warning` / `g.Log().Warningf` | **遇到错误但不影响主流程**(重试、降级、外部服务异常、非致命校验失败) |
| Panic | `g.Log().Panic` / `g.Log().Panicf` | 极其严重、必须立即终止的情况(配置缺失、核心依赖不可用) |
### 使用示例
```go
// Info:记录正常流程关键事件
g.Log().Infof(ctx, "用户登录成功 uid:%d ip:%s", member.Id, ip)
// Info:记录外部调用结果
g.Log().Info(ctx, "支付回调处理完成", g.Map{"orderId": orderId, "status": status})
// Warning:外部接口失败但已降级处理
g.Log().Warningf(ctx, "短信发送失败,已跳过 mobile:%s err:%+v", mobile, err)
// Warning:业务异常但不中断流程
g.Log().Warning(ctx, "用户余额不足,跳过自动扣款", g.Map{"uid": uid, "balance": balance})
// Panic:启动时核心配置缺失
g.Log().Panicf(ctx, "缓存未初始化,无法启动: %+v", err)
```
### 日志上下文原则
- 日志**必须传入 `ctx`**(第一个参数),便于链路追踪
- 关键日志需携带足够的业务字段(uid、orderId、requestId 等),用 `g.Map{}` 附加结构化信息
- **禁止**用 `fmt.Println` 替代日志,禁止在 logic/controller 层裸打印调试信息
---
## 数据库建表约定
建表时遵循以下字段命名约定,代码生成器和 ORM hook 会自动识别并处理:
| 字段名 | 类型 | 说明 |
|--------|------|------|
| `id` | bigint(20) NOT NULL AUTO_INCREMENT | 主键,必须 |
| `created_at` | datetime | 创建时间,**自动写入**,禁止手动赋值 |
| `updated_at` | datetime | 更新时间,**自动维护**,禁止手动赋值 |
| `deleted_at` | datetime | 软删除时间,存在时查询自动加 `IS NULL`,删除只更新此字段 |
| `created_by` | bigint(20) | 创建者 ID,**自动写入** |
| `updated_by` | bigint(20) | 更新者 ID,**自动维护** |
| `deleted_by` | bigint(20) | 删除者 ID,**自动写入** |
| `status` | tinyint | 状态字段,默认使用系统字典 `sys_normal_disable` |
| `sort` | int | 排序字段,存在时编辑表单自动获取最大值+1填充 |
| `pid` | bigint(20) | 树表上级ID(树表必须) |
| `level` | int | 树等级(树表必须,自动维护) |
| `tree` | varchar(512) | 关系树(树表必须,自动维护) |
| `tenant_id` | bigint(20) | 租户ID(多租户场景按需加) |
**特殊字段查询方式(代码生成器默认生成):**
- `string` 类型字段 → `LIKE` 模糊查询
- `int/uint/int64` → `=` 精确查询
- `created_by`/`updated_by`/`deleted_by` → 关键词查询(ID/用户名/手机号匹配),调用 `service.AdminMember().GetIdsByKeyword()`
**数据类型 → Go 类型映射(影响生成代码的字段类型):**
- `tinyint/int/smallint` → `int`;加 `unsigned` → `uint`
- `bigint` → `int64`;加 `unsigned` → `uint64`
- `varchar/text/char` → `string`
- `datetime/timestamp` → `*gtime.Time`
- `json/jsonb` → `*gjson.Json`
- `decimal/float/double` → `float64`
---
## 数据权限(权限过滤)
业务查询中如需过滤数据权限(仅自己/所属部门/下级等),在 ORM 链式调用中加入 handler:
```go
import "hotgo/internal/library/hgorm/handler"
// 按登录用户的数据权限范围过滤(表需含 created_by 或 member_id 字段)
dao.XxxTable.Ctx(ctx).Handler(handler.FilterAuth).Scan(&res)
// 表中无标准字段时,指定自定义字段
dao.XxxTable.Ctx(ctx).Handler(handler.FilterAuthWithField("custom_field")).Scan(&res)
// 多租户数据权限过滤(表需含 tenant_id 字段)
// 在 Model() 方法中通过 handler.Option 开启
func (s *sSysXxx) Model(ctx context.Context, option ...*handler.Option) *gdb.Model {
if len(option) == 0 {
option = append(option, &handler.Option{FilterTenant: true})
}
return handler.Model(dao.XxxTable.Ctx(ctx), option...)
}
```
多租户增改时自动维护租户关系,在 ORM 操作后加 `.Hook(hook.SaveTenant)`:
```go
import "hotgo/internal/library/hgorm/hook"
// 新增时自动写入 tenant_id/merchant_id/user_id
dao.XxxTable.Ctx(ctx).Fields(sysin.XxxInsertFields{}).Hook(hook.SaveTenant).Data(in).Insert()
// 更新时自动维护
s.Model(ctx).Fields(sysin.XxxUpdateFields{}).WherePri(in.Id).Data(in).Hook(hook.SaveTenant).Update()
```
---
## 定时任务(Crons)
定时任务通过实现接口 + `init()` 注册,在后台「系统设置 → 定时任务」中配置执行策略:
**主模块**:新建 `server/internal/crons/<name>.go`
**插件**:新建 `server/addons/<addonName>/crons/<name>.go`
```go
package crons
import (
"context"
"hotgo/internal/library/cron"
)
func init() {
cron.Register(MyTask)
}
var MyTask = &cMyTask{name: "myTask"} // name 与后台配置的任务名称一致
type cMyTask struct{ name string }
func (c *cMyTask) GetName() string { return c.name }
func (c *cMyTask) Execute(ctx context.Context, parser *cron.Parser) (err error) {
parser.Logger.Infof(ctx, "任务执行:%v", ...)
return
}
```
---
## 消息队列(Queues)
队列采用接口 + `init()` 注册,topic 统一定义在 `internal/consts/queue.go`(或对应模块 consts 文件)。
**主模块**:新建 `server/internal/queues/<name>.go`
**插件**:新建 `server/addons/<addonName>/queues/<name>.go`
```go
package queues
import (
"context"
"encoding/json"
"hotgo/internal/consts"
"hotgo/internal/library/queue"
)
func init() {
queue.RegisterConsumer(MyConsumer)
}
var MyConsumer = &qMyConsumer{}
type qMyConsumer struct{}
func (q *qMyConsumer) GetTopic() string { return consts.QueueMyTopic }
func (q *qMyConsumer) Handle(ctx context.Context, mqMsg queue.MqMsg) (err error) {
var data MyData
if err = json.Unmarshal(mqMsg.Body, &data); err != nil {
return
}
// 处理消息...
return
}
```
**发送消息:**
```go
// 即时消息
queue.Push(consts.QueueMyTopic, data)
// 延迟消息(仅 redis/rocketmq 驱动支持)
queue.SendDelayMsg(consts.QueueMyTopic, data, 10) // redis: 延迟秒数;rocketmq: 延迟级别
```
---
## 工具库使用规范
**后端(`server/utility/`)优先使用已有工具,禁止重复造轮子:**
| 包 | 用途 |
|----|------|
| `utility/convert` | 数据类型转换 |
| `utility/encrypt` | 加密/解密 |
| `utility/excel` | 电子表格导出/导入(导出接口用此包) |
| `utility/validate` | 数据验证工具 |
| `utility/tree` | 树形结构处理 |
| `utility/simple` | 简捷函数集合 |
| `utility/format` | 数据格式化 |
**前端(`web/src/utils/`)优先使用已有工具:**
| 工具 | 用途 |
|------|------|
| `@/utils/http/axios`(`http.request`) | HTTP 请求,**唯一入口** |
| `@/utils/dateUtil`(`defRangeShortcuts`) | 日期范围快捷选项 |
| `@/utils`(`renderImage`、`renderFile`、`renderPopoverMemberSumma`) | 表格渲染工具函数 |
| `@/store/modules/dict`(`useDictStore`) | 字典数据加载与渲染 |
| `@/hooks/web/usePermission`(`hasPermission`) | 权限判断 |
---
## 树表(Tree CRUD)特殊约定
树表在普通 CRUD 基础上有以下差异:
- 表中必须含 `pid`、`level`、`tree` 字段(参见建表约定)
- `pid`/`level`/`tree` 字段**由系统自动维护**,禁止在编辑表单中手动设置这三个字段
- 前端列表页使用树形表格(`BasicTable` 的 `childrenKey` 或 `treeData` 模式),而非普通分页列表
- 参考实现:`server/internal/logic/sys/tree_demo.go`、`web/src/views/develop/curd/treeDemo/`
---
## 响应格式约定
所有接口统一响应格式(由框架中间件自动处理,**无需在 controller 手动包装**):
```json
{ "code": 0, "message": "操作成功", "timestamp": 1234567890, "traceID": "xxx", "data": {} }
```
- 成功状态码:`0`;失败状态码:`-1`(GoFrame 内置,无需手动设置)
- `gerror.Wrap(err, "用户友好的提示")` → 客户端只看到最外层提示,开发者日志可见完整堆栈
- 禁止在 controller 层手动 `Write`/`WriteJSON` 等直接写响应(破坏统一格式)
---
## 常见错误禁止清单
**后端:**
- 禁止在 controller 层直接调用 dao
- 禁止硬编码字段名字符串(用 `dao.Table.Columns().Field`)
- 禁止手改 `entity/`、`do/`、`dao/internal/` 目录下的文件
- 禁止在 logic 层重复做 `Filter()` 已完成的校验
- 禁止在 `internal/service/sys.go` 之外新建主模块 service 文件(同文件追加)
- 禁止插件 import 另一个插件的包(插件间完全隔离,通过主模块 service 通信)
- 禁止在插件路由文件里硬编码路由前缀(用 `addons.RouterPrefix()` 生成)
- 禁止在 `internal/library/` 下修改基础库(如需扩展,提 issue 或在 utility/ 添加)
**前端:**
- 禁止直接使用 axios,必须用 `http.request`
- 禁止硬编码字典值文本,必须用 `dict.getLabel()` 渲染
- 禁止引入 Naive UI 以外的 UI 框架
- 禁止内联 style
- 禁止在源码里硬编码菜单路由路径
+80
View File
@@ -0,0 +1,80 @@
# ---- Stage 1: build the Vue frontend ----
FROM node:22-alpine AS web-build
WORKDIR /web
ENV CI=true
RUN npm install -g pnpm
COPY web/package.json web/pnpm-lock.yaml web/pnpm-workspace.yaml ./
RUN pnpm install --frozen-lockfile
COPY web/ .
RUN pnpm run build
# ---- Stage 2: build the Go backend, embedding the frontend build ----
FROM golang:1.24-alpine AS server-build
RUN apk add --no-cache git
WORKDIR /src
COPY server/go.mod server/go.sum ./
RUN go mod download
COPY server/ .
# Same layout the project's own Makefile produces: built frontend goes into
# resource/public/admin/ before packing/building the backend.
RUN rm -rf resource/public/admin && mkdir -p resource/public/admin
COPY --from=web-build /web/dist/ ./resource/public/admin/
# main.go imports internal/packed. Generate the packed resource file directly
# through GoFrame's library API instead of installing the full gf CLI in CI.
RUN printf '%s\n' \
'package main' \
'import "github.com/gogf/gf/v2/os/gres"' \
'func main() {' \
' if err := gres.PackToGoFileWithOption("resource", "internal/packed/packed.go", "packed", gres.Option{}); err != nil { panic(err) }' \
'}' > /tmp/pack.go \
&& go run /tmp/pack.go \
&& rm /tmp/pack.go
RUN CGO_ENABLED=0 go build -o /out/hotgo main.go
# ---- Stage 3: runtime ----
FROM alpine:3.22
RUN apk add --no-cache ca-certificates gettext bash tzdata
WORKDIR /app
ENV QUEUE_DRIVER=kafka
ENV KAFKA_ADDRESS=kafka.118im.com:30835
ENV KAFKA_VERSION=2.4.0
ENV KAFKA_USERNAME=
ENV KAFKA_PASSWORD=
ENV KAFKA_SASL_MECHANISM=
ENV MYSQL_DSN=
ENV REDIS_ADDR=redis.118im.com:30637
ENV REDIS_DB=2
ENV REDIS_PASSWORD=
ENV TOKEN_SECRET_KEY=hotgo123
ENV IM_ADMIN_API_BASE_URL=https://api.118im.com
ENV IM_ADMIN_API_SERVICE_ID=hotgo-admin
ENV IM_ADMIN_API_SECRET=
ENV IM_INTERNAL_API_BASE_URL=https://api.118im.com
ENV IM_INTERNAL_API_SERVICE_NAME=hotgo-admin
ENV IM_INTERNAL_API_SECRET=
ENV IM_WORKBENCH_API_BASE_URL=http://im-workbench.workbench-system.svc.cluster.local:6061
ENV IM_WORKBENCH_API_SERVICE_NAME=hotgo-admin
ENV IM_WORKBENCH_API_SECRET=hotgo-workbench-internal
ENV IM_CONFIG_API_SERVICE_NAME=im-server
ENV IM_CONFIG_API_SECRET=
COPY --from=server-build /src/manifest ./manifest
COPY --from=server-build /src/hack ./hack
COPY --from=server-build /out/hotgo .
COPY server/manifest/docker/entrypoint.sh .
RUN mkdir -p storage/logs storage/data storage/cache storage/diskqueue \
&& chmod +x entrypoint.sh hotgo
HEALTHCHECK --interval=1m --timeout=3s --start-period=20s \
CMD wget -q -O /dev/null http://localhost:8000/healthz || exit 1
EXPOSE 8000
ENTRYPOINT ["./entrypoint.sh"]
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-present HotGo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+166 -1
View File
@@ -1,2 +1,167 @@
# im_manager
# HotGo-V2
<div align="center">
<img width="140px" src="https://gmycos.facms.cn/hotgo/logo.sig.png">
<p>
<h1>HotGo V2</h1>
</p>
<p align="center">
<a href="https://goframe.org/pages/viewpage.action?pageId=1114119" target="_blank">
<img src="https://img.shields.io/badge/goframe-2.10.0-green" alt="goframe">
</a>
<a href="https://v3.vuejs.org/" target="_blank">
<img src="https://img.shields.io/badge/vue.js-vue3.4-green" alt="vue">
</a>
<a href="https://www.naiveui.com" target="_blank">
<img src="https://img.shields.io/badge/naiveui-%3E2.44.1-blue" alt="naiveui">
</a>
<a href="https://www.tslang.cn/" target="_blank">
<img src="https://img.shields.io/badge/typescript-%3E4.0.0-blue" alt="typescript">
</a>
<a href="https://vitejs.dev/" target="_blank">
<img src="https://img.shields.io/badge/vite-%3E5.4.2-yellow" alt="vite">
</a>
<a href="https://github.com/bufanyun/hotgo/blob/v2.0/LICENSE" target="_blank">
<img src="https://img.shields.io/badge/license-MIT-success" alt="license">
</a>
</p>
</div>
## 平台简介
* 基于 GoFrame2 + Vue3 + NaiveUI + uniapp 的企业级全栈框架,为二次开发而生。
* 前端采用 Naive-Ui-Admin、Vue、Naive UI、uniapp。
* 企业级 AI 赋能基础开发平台,内置 AI 开发规范,适配主流 AI 开发工具,实现人机协同开发,大幅提升开发效率。
## 演示地址
- [https://hotgo.facms.cn/admin](https://hotgo.facms.cn/admin)
> 账号:admin 密码:123456
### 使用文档
[安装文档](docs/guide-zh-CN/start-installation.md) · [本地文档](docs/guide-zh-CN/README.md) · [更新历史](docs/guide-zh-CN/start-update-log.md) · [常见问题](docs/guide-zh-CN/start-issue.md)
## 特征
* 高生产率:极强的可扩展性,应用化、模块化、插件化机制敏捷开发,几分钟即可搭建一个应用开发骨架。
* 多应用入口:多入口分为 Admin (后台)、Home (前台页面)、Api (对外通用接口)、WebSocket (即时通讯接口),不同的业务,进入不同的应用入口。
* 极致的插件化: 微核架构,功能隔离,高可定制性,可以渐进式开发,亦可以多人协同开发。支持一键创建插件模板、一键安装、更新、卸载插件、可以非常方便的将插件迁移到新项目中。
* 快速生成代码:无需编写代码,只需创建表进行简单配置就能生成一个完善的 CURD、树表等常用的开发代码,其中所需表单控件也是勾选即可直接生成。
* 认证机制:采用 JWT 的用户状态认证及 casbin 的权限认证
* 路由模式:得益于 GoFrame 提供了规范化的路由注册方式,无需注解自动生成api文档
* 模块化设计,面向接口开发
## 内置功能
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
2. 部门管理:配置系统组织机构(公司、部门、岗位),树结构展现支持数据权限。
3. 岗位管理:配置系统用户所属担任职务。
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
5. 角色管理:角色菜单权限分配、设置角色按机构或按上下级关系进行数据范围权限划分。
6. 字典管理:对系统中经常使用的一些特定数据进行维护,支持枚举字典和自定义方法字典。
7. 配置管理:对系统动态配置常用参数。
8. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
9. 登录日志:系统登录日志记录查询包含登录异常。
10. 服务日志:服务端运行所产生的警告、异常、崩溃日志的详细数据和堆栈信息。
11. 支付网关:集成支付宝、微信支付、QQ支付等多种支付方式,只需简单配置即可使用。
12. 资金管理:支持在线充值、订单申请/原路退款、资金提现、资金/积分变动明细等通用模块。
13. 在线用户:当前系统中活跃用户状态监控。
14. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
15. 代码生成:支持自动化生成前后端代码。CURD关联表、树表、消息队列、定时任务一键生成等。
16. 插件应用:支持一键生成插件模板,每个插件之间开发隔离,拥有独立多应用入口、独立配置。完美支持多人协同开发、插件插拔不会对原系统产生影响等。
17. 服务监控:监视当前系统CPU、内存、磁盘、网络、堆栈等相关信息。
18. 附件管理:文件图片上传,大文件分片上传、断点续传,支持本地、阿里云oss、腾讯云cos、ucloud对象存储、七牛云对象存储、minio等多种上传驱动,后台一键切换配置,并集成了文件选择器。
19. TCP服务:基于gtcp的服务应用,支持长连接、断线重连、服务认证、路由分发、RPC消息、拦截器和数据绑定等。简化和规范了服务器开发流程。
20. 消息队列:同时兼容 kafka、redis、rocketmq、磁盘队列,一键配置切换到场景适用的MQ。
21. 通知公告:采用WebSocket实时推送在线用户最新通知、公告、私信消息。
22. 地区编码:整合国内通用省市区编码,运用于项目于一身,支持动态省市区选项。
23. 常用工具:集成常用的工具包和命令行工具,可以快速开发自定义命令行,多种启动入口。
> HotGo开源以来得到了大家的很多支持,本项目初衷只为互相学习交流,没有任何盈利性目的!欢迎为HotGo贡献代码或提供建议!
## 演示图
<table>
<tr>
<td><img src="./docs/guide-zh-CN/images/demo/1.png"/></td>
<td><img src="./docs/guide-zh-CN/images/demo/2.png"/></td>
</tr>
<tr>
<td><img src="./docs/guide-zh-CN/images/demo/3.png"/></td>
<td><img src="./docs/guide-zh-CN/images/demo/4.png"/></td>
</tr>
<tr>
<td><img src="./docs/guide-zh-CN/images/demo/5.png"/></td>
<td><img src="./docs/guide-zh-CN/images/demo/6.png"/></td>
</tr>
<tr>
<td><img src="./docs/guide-zh-CN/images/demo/7.png"/></td>
<td><img src="./docs/guide-zh-CN/images/demo/8.png"/></td>
</tr>
<tr>
<td><img src="./docs/guide-zh-CN/images/demo/9.png"/></td>
<td><img src="./docs/guide-zh-CN/images/demo/10.png"/></td>
</tr>
<tr>
<td><img src="./docs/guide-zh-CN/images/demo/11.png"/></td>
<td><img src="./docs/guide-zh-CN/images/demo/12.png"/></td>
</tr>
</table>
## 感谢(排名不分先后)
> gf框架 [https://github.com/gogf/gf](https://github.com/gogf/gf)
>
> naive-ui [https://www.naiveui.com](https://www.naiveui.com)
>
> naive-ui-admin [https://github.com/jekip/naive-ui-admin](https://github.com/jekip/naive-ui-admin)
>
> websocket [https://github.com/gorilla/websocket](github.com/gorilla/websocket)
>
> casbin [https://github.com/casbin/casbin](https://github.com/casbin/casbin)
>
> gopay [https://github.com/go-pay/gopay](https://github.com/go-pay/gopay)
## 交流QQ群
交流群①:190966648 <a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=mJafkvme3VNyiQlCFIFNRtY8Xlr7pj9U&jump_from=webapi&authKey=jL10vIESr+vO8wpxwyd6DlChzkrbHpzN9uhAsIHgAinL/Vvd+nvuRyilf2UqUlCy"><img border="0" src="https://gmycos.facms.cn/hotgo/group.png" alt="HotGo框架交流1群" title="HotGo框架交流1群"></a>
> <img src="https://gmycos.facms.cn/hotgo/hotgo1qun.png" width="400px"/>
## 商用说明
> HotGo 是开源免费的,遵循 MIT 开源协议,意味着您无需支付任何费用,也无需授权,即可将它应用到您的产品中。
* 使用本项目必须保留所有版权信息。
* 本项目包含的第三方源码和二进制文件之版权信息另行标注。
* 版权所有Copyright © 2020-2026 by Ms (https://github.com/bufanyun/hotgo)
* All rights reserved。
## 免责声明:
* HotGo为开源学习项目,一切商业行为与HotGo无关。
* 用户不得利用HotGo从事非法行为,用户应当合法合规的使用,发现用户在使用产品时有任何的非法行为,HotGo有权配合有关机关进行调查或向政府部门举报,HotGo不承担用户因非法行为造成的任何法律责任,一切法律责任由用户自行承担,如因用户使用造成第三方损害的,用户应当依法予以赔偿。
* 所有与使用HotGo相关的资源直接风险均由用户承担。
#### 如果对您有帮助,您可以点右上角 💘Star💘支持
## [感谢JetBrains提供的免费GoLand](https://jb.gg/OpenSource)
[![avatar](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://jb.gg/OpenSource)
## License
[MIT © HotGo-2026](./LICENSE)
@@ -0,0 +1,62 @@
{
"label": "数据概览",
"slug": "01-dashboard",
"route": "/dashboard",
"url": "https://admin.adfahi.cn/dashboard",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/01-dashboard.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n总用户数\n16\n活跃用户\n0\n总群组数\n6\n总会话数\n11\n总消息数\n220\n今日消息\n0\n用户增长趋势\n日期\t数量\n2026-08-28\t0\n2026-08-29\t0\n2026-08-30\t0\n2026-08-31\t0\n2026-09-01\t0\n2026-09-02\t0\n2026-09-03\t0\n消息增长趋势\n日期\t数量\n2026-08-28\t0\n2026-08-29\t0\n2026-08-30\t0\n2026-08-31\t0\n2026-09-01\t0\n2026-09-02\t0\n2026-09-03\t0",
"tables": [
{
"headers": [
"日期",
"数量"
],
"idx": 0,
"rows": [
[
"2026-08-28",
"0"
],
[
"2026-08-29",
"0"
],
[
"2026-08-30",
"0"
]
]
},
{
"headers": [
"日期",
"数量"
],
"idx": 1,
"rows": [
[
"2026-08-28",
"0"
],
[
"2026-08-29",
"0"
],
[
"2026-08-30",
"0"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
}
],
"resources": []
}
@@ -0,0 +1,78 @@
{
"label": "数据概览",
"slug": "01-dashboard",
"route": "/dashboard",
"url": "https://admin.adfahi.cn/dashboard",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/01-dashboard.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n总用户数\n16\n活跃用户\n0\n总群组数\n6\n总会话数\n11\n总消息数\n220\n今日消息\n0\n用户增长趋势\n日期\t数量\n2026-08-28\t0\n2026-08-29\t0\n2026-08-30\t0\n2026-08-31\t0\n2026-09-01\t0\n2026-09-02\t0\n2026-09-03\t0\n消息增长趋势\n日期\t数量\n2026-08-28\t0\n2026-08-29\t0\n2026-08-30\t0\n2026-08-31\t0\n2026-09-01\t0\n2026-09-02\t0\n2026-09-03\t0",
"tables": [
{
"headers": [
"日期",
"数量"
],
"idx": 0,
"rows": [
[
"2026-08-28",
"0"
],
[
"2026-08-29",
"0"
],
[
"2026-08-30",
"0"
],
[
"2026-08-31",
"0"
],
[
"2026-09-01",
"0"
]
]
},
{
"headers": [
"日期",
"数量"
],
"idx": 1,
"rows": [
[
"2026-08-28",
"0"
],
[
"2026-08-29",
"0"
],
[
"2026-08-30",
"0"
],
[
"2026-08-31",
"0"
],
[
"2026-09-01",
"0"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
}
]
}
@@ -0,0 +1,866 @@
{
"label": "用户管理",
"slug": "02-user-management",
"route": "/users",
"url": "https://admin.adfahi.cn/users",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/02-user-management.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户管理\n编号\n用户分组\n全部\n状态\n全部\n关键词\n查 询\n重 置\n创建用户\n批量创建\n导入Excel\n下载模板\n编号\t头像\t用户名\t昵称\t手机号\t注册方式\t状态\t用户分组\t最近登录\t创建时间\t操作\n\n编号\n\t\n头像\n\t\n用户名\n\t\n昵称\n\t\n手机号\n\t\n注册方式\n\t\n状态\n\t\n用户分组\n\t\n最近登录\n\t\n创建时间\n\t\n操作\n\n16\t\n点击查看\n\thy73074162\tpoter001\t\t后台创建\t正常\t默认用户组\t2026-08-01 00:05:30\t2026-08-01 00:04:25\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n15\t\n点击查看\n\thy17716319\t往事随风\t\t后台创建\t正常\t默认用户组\t2026-08-01 21:16:15\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n14\t\n点击查看\n\thy34899108\t坚守的山羊\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n13\t\n点击查看\n\thy45257043\t沉稳的松鼠\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n12\t\n点击查看\n\thy69598195\t专注的白兔\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n11\t\n点击查看\n\thy20144467\t沉稳的黑猫\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n10\t\n点击查看\n\thy70299474\t坚韧的河马\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n9\t\n点击查看\n\thy23799134\t求真的猫头\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n8\t\n点击查看\n\thy18959373\t进取的北狐\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n7\t\n点击查看\n\thy80424632\t温润的乌鸦\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n6\t\n点击查看\n\thy98400466\t乐观的野马\t\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:44:06\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n5\t\n点击查看\n\thy99111080\tF\t13800001115\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:43:53\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n4\t\n点击查看\n\thy92120233\tF\t13800001114\t后台创建\t正常\t默认用户组\t--\t2026-07-31 22:43:37\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n3\t\n点击查看\n\thy69089908\tF\t13800001113\t后台创建\t正常\t默认用户组\t2026-07-31 23:26:17\t2026-07-31 22:43:12\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n2\t\n点击查看\n\thy91144536\t冯仁飞\t13800001112\t后台创建\t正常\t默认用户组\t2026-08-02 22:27:59\t2026-07-31 22:43:02\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n\n1\t\n点击查看\n\thy50703413\t冯宇昂\t13800001111\t后台创建\t正常\t默认用户组\t2026-07-31 23:37:42\t2026-07-31 22:42:45\t\n详 情\n重置密码\nIP白名单\n调整分组\n封 禁\n强制下线\n强制注销\n1\n20 条/页",
"tables": [
{
"headers": [
"编号",
"头像",
"用户名",
"昵称",
"手机号",
"注册方式",
"状态",
"用户分组",
"最近登录",
"创建时间",
"操作",
"编号",
"头像",
"用户名",
"昵称",
"手机号",
"注册方式",
"状态",
"用户分组",
"最近登录",
"创建时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"16",
"点击查看",
"hy73074162",
"poter001",
"后台创建",
"正常",
"默认用户组",
"2026-08-01 00:05:30",
"2026-08-01 00:04:25",
"详 情重置密码IP白名单调整分组封 禁强制下线强制注销"
],
[
"15",
"点击查看",
"hy17716319",
"往事随风",
"后台创建",
"正常",
"默认用户组",
"2026-08-01 21:16:15",
"2026-07-31 22:44:06",
"详 情重置密码IP白名单调整分组封 禁强制下线强制注销"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "用户编号",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "用户名/昵称/手机号",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "创建用户"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "批量创建"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "导入Excel"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "下载模板"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重置密码"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "调整分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制下线"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "强制注销"
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
}
],
"resources": []
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,102 @@
{
"label": "用户分组",
"slug": "03-user-groups",
"route": "/user-policy-groups",
"url": "https://admin.adfahi.cn/user-policy-groups",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/03-user-groups.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户分组\n添加分组\nIP 白名单\n租户渠道 IP 白名单\nAPP:未配置\nWeb:未配置\n分组名称\t用户数\t允许加好友\t允许建群\t直接加好友\t好友上限\tAPP 登录\tWeb 登录\tIP 白名单\t状态\t权重\t操作\n\n分组名称\n\t\n用户数\n\t\n允许加好友\n\t\n允许建群\n\t\n直接加好友\n\t\n好友上限\n\t\nAPP 登录\n\t\nWeb 登录\n\t\nIP 白名单\n\t\n状态\n\t\n权重\n\t\n操作\n\n\n默认用户组\n默认\n\t16\t允许\t允许\t--\t不限\t允许\t允许\t未启用\t启用\t0\t\n编辑\n删除",
"tables": [
{
"headers": [
"分组名称",
"用户数",
"允许加好友",
"允许建群",
"直接加好友",
"好友上限",
"APP 登录",
"Web 登录",
"IP 白名单",
"状态",
"权重",
"操作",
"分组名称",
"用户数",
"允许加好友",
"允许建群",
"直接加好友",
"好友上限",
"APP 登录",
"Web 登录",
"IP 白名单",
"状态",
"权重",
"操作"
],
"idx": 0,
"rows": [
[],
[
"默认用户组默认",
"16",
"允许",
"允许",
"--",
"不限",
"允许",
"允许",
"未启用",
"启用",
"0",
"编辑删除"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "添加分组"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP 白名单"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "编辑"
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "删除"
}
],
"resources": []
}
@@ -0,0 +1,108 @@
{
"label": "用户分组",
"slug": "03-user-groups",
"route": "/user-policy-groups",
"url": "https://admin.adfahi.cn/user-policy-groups",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/03-user-groups.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户分组\n添加分组\nIP 白名单\n租户渠道 IP 白名单\nAPP:未配置\nWeb:未配置\n分组名称\t用户数\t允许加好友\t允许建群\t直接加好友\t好友上限\tAPP 登录\tWeb 登录\tIP 白名单\t状态\t权重\t操作\n\n分组名称\n\t\n用户数\n\t\n允许加好友\n\t\n允许建群\n\t\n直接加好友\n\t\n好友上限\n\t\nAPP 登录\n\t\nWeb 登录\n\t\nIP 白名单\n\t\n状态\n\t\n权重\n\t\n操作\n\n\n默认用户组\n默认\n\t16\t允许\t允许\t--\t不限\t允许\t允许\t未启用\t启用\t0\t\n编辑\n删除",
"tables": [
{
"headers": [
"分组名称",
"用户数",
"允许加好友",
"允许建群",
"直接加好友",
"好友上限",
"APP 登录",
"Web 登录",
"IP 白名单",
"状态",
"权重",
"操作",
"分组名称",
"用户数",
"允许加好友",
"允许建群",
"直接加好友",
"好友上限",
"APP 登录",
"Web 登录",
"IP 白名单",
"状态",
"权重",
"操作"
],
"idx": 0,
"rows": [
[],
[
"默认用户组默认",
"16",
"允许",
"允许",
"--",
"不限",
"允许",
"允许",
"未启用",
"启用",
"0",
"编辑删除"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "添加分组",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "IP 白名单",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "编辑",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "删除",
"value": ""
}
]
}
@@ -0,0 +1,296 @@
{
"label": "群组管理",
"slug": "04-group-management",
"route": "/groups",
"url": "https://admin.adfahi.cn/groups",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/04-group-management.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群组管理\n群号\n关键词\n状态\n全部\n查 询\n重 置\n群组编号\t群号\t群组名称\t成员数\t群主昵称\t群主用户名\t状态\t创建时间\t操作\n\n群组编号\n\t\n群号\n\t\n群组名称\n\t\n成员数\n\t\n群主昵称\n\t\n群主用户名\n\t\n状态\n\t\n创建时间\n\t\n操作\n\n6\t68127154\t\n冯\n\t1\tF\thy69089908\t正常\t2026-07-31 22:50:52\t\n详 情\n群文件\n封 禁\n解 散\n\n5\t62262588\t\n冯\n\t3\tF\thy69089908\t正常\t2026-07-31 22:50:38\t\n详 情\n群文件\n封 禁\n解 散\n\n4\t75874312\t\n346亿916\n\t1\t冯宇昂\thy50703413\t正常\t2026-07-31 22:47:57\t\n详 情\n群文件\n封 禁\n解 散\n\n3\t92851806\t\n64919\n\t1\t冯宇昂\thy50703413\t正常\t2026-07-31 22:47:49\t\n详 情\n群文件\n封 禁\n解 散\n\n2\t89233971\t\n冯氏家族\n\t3\t冯仁飞\thy91144536\t正常\t2026-07-31 22:46:59\t\n详 情\n群文件\n封 禁\n解 散\n\n1\t17776111\t\n冯氏家族\n\t3\t冯宇昂\thy50703413\t正常\t2026-07-31 22:45:28\t\n详 情\n群文件\n封 禁\n解 散\n1\n20 条/页",
"tables": [
{
"headers": [
"群组编号",
"群号",
"群组名称",
"成员数",
"群主昵称",
"群主用户名",
"状态",
"创建时间",
"操作",
"群组编号",
"群号",
"群组名称",
"成员数",
"群主昵称",
"群主用户名",
"状态",
"创建时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"6",
"68127154",
"冯",
"1",
"F",
"hy69089908",
"正常",
"2026-07-31 22:50:52",
"详 情群文件封 禁解 散"
],
[
"5",
"62262588",
"冯",
"3",
"F",
"hy69089908",
"正常",
"2026-07-31 22:50:38",
"详 情群文件封 禁解 散"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "群号",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "群名称",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "群文件"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解 散"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "群文件"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解 散"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "群文件"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解 散"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "群文件"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解 散"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "群文件"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解 散"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "群文件"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解 散"
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
}
],
"resources": []
}
@@ -0,0 +1,356 @@
{
"label": "群组管理",
"slug": "04-group-management",
"route": "/groups",
"url": "https://admin.adfahi.cn/groups",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/04-group-management.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群组管理\n群号\n关键词\n状态\n全部\n查 询\n重 置\n群组编号\t群号\t群组名称\t成员数\t群主昵称\t群主用户名\t状态\t创建时间\t操作\n\n群组编号\n\t\n群号\n\t\n群组名称\n\t\n成员数\n\t\n群主昵称\n\t\n群主用户名\n\t\n状态\n\t\n创建时间\n\t\n操作\n\n6\t68127154\t\n冯\n\t1\tF\thy69089908\t正常\t2026-07-31 22:50:52\t\n详 情\n群文件\n封 禁\n解 散\n\n5\t62262588\t\n冯\n\t3\tF\thy69089908\t正常\t2026-07-31 22:50:38\t\n详 情\n群文件\n封 禁\n解 散\n\n4\t75874312\t\n346亿916\n\t1\t冯宇昂\thy50703413\t正常\t2026-07-31 22:47:57\t\n详 情\n群文件\n封 禁\n解 散\n\n3\t92851806\t\n64919\n\t1\t冯宇昂\thy50703413\t正常\t2026-07-31 22:47:49\t\n详 情\n群文件\n封 禁\n解 散\n\n2\t89233971\t\n冯氏家族\n\t3\t冯仁飞\thy91144536\t正常\t2026-07-31 22:46:59\t\n详 情\n群文件\n封 禁\n解 散\n\n1\t17776111\t\n冯氏家族\n\t3\t冯宇昂\thy50703413\t正常\t2026-07-31 22:45:28\t\n详 情\n群文件\n封 禁\n解 散\n1\n20 条/页",
"tables": [
{
"headers": [
"群组编号",
"群号",
"群组名称",
"成员数",
"群主昵称",
"群主用户名",
"状态",
"创建时间",
"操作",
"群组编号",
"群号",
"群组名称",
"成员数",
"群主昵称",
"群主用户名",
"状态",
"创建时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"6",
"68127154",
"冯",
"1",
"F",
"hy69089908",
"正常",
"2026-07-31 22:50:52",
"详 情群文件封 禁解 散"
],
[
"5",
"62262588",
"冯",
"3",
"F",
"hy69089908",
"正常",
"2026-07-31 22:50:38",
"详 情群文件封 禁解 散"
],
[
"4",
"75874312",
"346亿916",
"1",
"冯宇昂",
"hy50703413",
"正常",
"2026-07-31 22:47:57",
"详 情群文件封 禁解 散"
],
[
"3",
"92851806",
"64919",
"1",
"冯宇昂",
"hy50703413",
"正常",
"2026-07-31 22:47:49",
"详 情群文件封 禁解 散"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "群号",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "群名称",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "群文件",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解 散",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "群文件",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解 散",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "群文件",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解 散",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "群文件",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解 散",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "群文件",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解 散",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详 情",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "群文件",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "封 禁",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解 散",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
}
]
}
@@ -0,0 +1,113 @@
{
"label": "群成员管理",
"slug": "05-group-members",
"route": "/group-members",
"url": "https://admin.adfahi.cn/group-members",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/05-group-members.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群成员管理\n群号\n角色\n全部\n关键词\n查 询\n重 置\n刷 新\n编号\t用户名\t昵称\t群昵称\t角色\t禁言状态\t加入时间\t操作\n\n编号\n\t\n用户名\n\t\n昵称\n\t\n群昵称\n\t\n角色\n\t\n禁言状态\n\t\n加入时间\n\t\n操作\n\n\n暂无数据",
"tables": [
{
"headers": [
"编号",
"用户名",
"昵称",
"群昵称",
"角色",
"禁言状态",
"加入时间",
"操作",
"编号",
"用户名",
"昵称",
"群昵称",
"角色",
"禁言状态",
"加入时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"暂无数据暂无数据"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "必填",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "用户名/昵称",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "刷 新"
}
],
"resources": []
}
@@ -0,0 +1,173 @@
{
"label": "群成员管理",
"slug": "05-group-members",
"route": "/group-members",
"url": "https://admin.adfahi.cn/group-members",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/05-group-members.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群成员管理\n群号\n角色\n全部\n关键词\n查 询\n重 置\n刷 新\n编号\t用户名\t昵称\t群昵称\t角色\t禁言状态\t加入时间\t操作\n\n编号\n\t\n用户名\n\t\n昵称\n\t\n群昵称\n\t\n角色\n\t\n禁言状态\n\t\n加入时间\n\t\n操作\n\n3\thy69089908\tF\t--\t群主\t正常\t2026-07-31 22:50:52\t\n禁 言\n踢 出\n1\n20 条/页",
"tables": [
{
"headers": [
"编号",
"用户名",
"昵称",
"群昵称",
"角色",
"禁言状态",
"加入时间",
"操作",
"编号",
"用户名",
"昵称",
"群昵称",
"角色",
"禁言状态",
"加入时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"3",
"hy69089908",
"F",
"--",
"群主",
"正常",
"2026-07-31 22:50:52",
"禁 言踢 出"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "必填",
"tag": "INPUT",
"text": "",
"value": "68127154"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "用户名/昵称",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "刷 新",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "禁 言",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "踢 出",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
}
]
}
@@ -0,0 +1,103 @@
{
"label": "邀请码管理",
"slug": "06-invite-codes",
"route": "/invite-codes",
"url": "https://admin.adfahi.cn/invite-codes",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/06-invite-codes.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n邀请码管理\n状态\n全部\n邀请码\n查 询\n重 置\n生成邀请码\n每次生成 1 个邀请码,可多次使用。可指定企业与用户;勾选「不限制时间」则永久有效;开启「自动加好友」后,使用该码注册的用户将直接成为指定用户的好友。点击「查看」可查看使用该邀请码注册的用户列表。\n邀请码\t指定用户\t自动加好友\t使用人数\t创建人\t状态\t过期时间\t创建时间\t操作\n\n邀请码\n\t\n指定用户\n\t\n自动加好友\n\t\n使用人数\n\t\n创建人\n\t\n状态\n\t\n过期时间\n\t\n创建时间\n\t\n操作\n\n\n暂无数据",
"tables": [
{
"headers": [
"邀请码",
"指定用户",
"自动加好友",
"使用人数",
"创建人",
"状态",
"过期时间",
"创建时间",
"操作",
"邀请码",
"指定用户",
"自动加好友",
"使用人数",
"创建人",
"状态",
"过期时间",
"创建时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"暂无数据暂无数据"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "6 位数字",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "生成邀请码"
}
],
"resources": []
}
@@ -0,0 +1,162 @@
{
"label": "邀请码管理",
"slug": "06-invite-codes",
"route": "/invite-codes",
"url": "https://admin.adfahi.cn/invite-codes",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/06-invite-codes.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n用户管理\n用户分组\n群组管理\n群成员管理\n邀请码管理\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n邀请码管理\n状态\n全部\n邀请码\n查 询\n重 置\n生成邀请码\n每次生成 1 个邀请码,可多次使用。可指定企业与用户;勾选「不限制时间」则永久有效;开启「自动加好友」后,使用该码注册的用户将直接成为指定用户的好友。点击「查看」可查看使用该邀请码注册的用户列表。\n邀请码\t指定用户\t自动加好友\t使用人数\t创建人\t状态\t过期时间\t创建时间\t操作\n\n邀请码\n\t\n指定用户\n\t\n自动加好友\n\t\n使用人数\n\t\n创建人\n\t\n状态\n\t\n过期时间\n\t\n创建时间\n\t\n操作\n\n323441\t往事随风 (#2271)\t否\t0\t16\t启用\t2026-09-05 00:34:55\t2026-09-04 00:34:55\t\n查 看\n删 除\n1\n20 条/页",
"tables": [
{
"headers": [
"邀请码",
"指定用户",
"自动加好友",
"使用人数",
"创建人",
"状态",
"过期时间",
"创建时间",
"操作",
"邀请码",
"指定用户",
"自动加好友",
"使用人数",
"创建人",
"状态",
"过期时间",
"创建时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"323441",
"往事随风 (#2271)",
"否",
"0",
"16",
"启用",
"2026-09-05 00:34:55",
"2026-09-04 00:34:55",
"查 看删 除"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "6 位数字",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "生成邀请码",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 看",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
}
]
}
@@ -0,0 +1,171 @@
{
"label": "单聊消息",
"slug": "07-direct-messages",
"route": "/private-messages",
"url": "https://admin.adfahi.cn/private-messages",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/07-direct-messages.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n单聊消息\n全部\n文本\n图片\n视频\n语音\n文件\n名片\n系统\n发送人用户名\n接收人用户名\n关键词\n开始时间\n结束时间\n查 询\n重 置\n刷 新\n发送人\t接收人\t类型\t内容\t状态\t发送时间\t操作\n\n发送人\n\t\n接收人\n\t\n类型\n\t\n内容\n\t\n状态\n\t\n发送时间\n\t\n操作\n\n\n暂无数据",
"tables": [
{
"headers": [
"发送人",
"接收人",
"类型",
"内容",
"状态",
"发送时间",
"操作",
"发送人",
"接收人",
"类型",
"内容",
"状态",
"发送时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"暂无数据暂无数据"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "关键字",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "开始时间",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "结束时间",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "刷 新"
}
],
"resources": []
}
@@ -0,0 +1,393 @@
{
"label": "单聊消息",
"slug": "07-direct-messages",
"route": "/private-messages",
"url": "https://admin.adfahi.cn/private-messages",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/07-direct-messages.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n单聊消息\n全部\n文本\n图片\n视频\n语音\n文件\n名片\n系统\n发送人用户名\n接收人用户名\n关键词\n开始时间\n结束时间\n查 询\n重 置\n刷 新\n发送人\t接收人\t类型\t内容\t状态\t发送时间\t操作\n\n发送人\n\t\n接收人\n\t\n类型\n\t\n内容\n\t\n状态\n\t\n发送时间\n\t\n操作\n\n\nF\nhy69089908\n\t\n冯仁飞\nhy91144536\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:06:05\t\n删 除\n\n\nF\nhy69089908\n\t\n冯宇昂\nhy50703413\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:06:05\t\n删 除\n\n\nF\nhy69089908\n\t\n冯宇昂\nhy50703413\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:05:19\t\n删 除\n\n\nF\nhy69089908\n\t\n冯仁飞\nhy91144536\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:04:12\t\n删 除\n\n\nF\nhy69089908\n\t\n冯宇昂\nhy50703413\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:04:12\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯仁飞\nhy91144536\n\t系统\t\n语音通话 00:13\n\t正常\t2026-07-31 23:02:22\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯仁飞\nhy91144536\n\t系统\t\n语音通话 00:01\n\t正常\t2026-07-31 23:01:45\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t系统\t\n语音通话 已取消\n\t正常\t2026-07-31 23:01:36\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t系统\t\n语音通话 已拒绝\n\t正常\t2026-07-31 23:01:19\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t系统\t\n视频通话 已取消\n\t正常\t2026-07-31 23:00:20\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t系统\t\n视频通话 00:19\n\t正常\t2026-07-31 22:59:59\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t系统\t\n语音通话 00:07\n\t正常\t2026-07-31 22:59:32\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t系统\t\n语音通话 已取消\n\t正常\t2026-07-31 22:59:05\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t系统\t\n语音通话 00:15\n\t正常\t2026-07-31 22:58:42\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t系统\t\n视频通话 00:07\n\t正常\t2026-07-31 22:58:20\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t系统\t\n视频通话 已取消\n\t正常\t2026-07-31 22:58:07\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t文本\t\n红心\n\t正常\t2026-07-31 22:51:35\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t文本\t\n1\n\t正常\t2026-07-31 22:51:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t文本\t\n你想让我\n\t正常\t2026-07-31 22:51:32\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t文本\t\n1\n\t正常\t2026-07-31 22:51:32\t\n删 除\n1\n2\n3\n4\n20 条/页",
"tables": [
{
"headers": [
"发送人",
"接收人",
"类型",
"内容",
"状态",
"发送时间",
"操作",
"发送人",
"接收人",
"类型",
"内容",
"状态",
"发送时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"Fhy69089908",
"冯仁飞hy91144536",
"文本",
"哈哈哈哈",
"正常",
"2026-07-31 23:06:05",
"删 除"
],
[
"Fhy69089908",
"冯宇昂hy50703413",
"文本",
"哈哈哈哈",
"正常",
"2026-07-31 23:06:05",
"删 除"
],
[
"Fhy69089908",
"冯宇昂hy50703413",
"文本",
"哈哈哈哈",
"正常",
"2026-07-31 23:05:19",
"删 除"
],
[
"Fhy69089908",
"冯仁飞hy91144536",
"文本",
"哈哈哈哈",
"正常",
"2026-07-31 23:04:12",
"删 除"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "关键字",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "开始时间",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "结束时间",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "刷 新",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
}
]
}
@@ -0,0 +1,159 @@
{
"label": "群聊消息",
"slug": "08-group-messages",
"route": "/group-messages",
"url": "https://admin.adfahi.cn/group-messages",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/08-group-messages.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群聊消息\n全部\n文本\n图片\n视频\n语音\n文件\n名片\n系统\n发送人用户名\n关键词\n开始时间\n结束时间\n查 询\n重 置\n刷 新\n发送人\t群名称\t类型\t内容\t状态\t发送时间\t操作\n\n发送人\n\t\n群名称\n\t\n类型\n\t\n内容\n\t\n状态\n\t\n发送时间\n\t\n操作\n\n\n暂无数据",
"tables": [
{
"headers": [
"发送人",
"群名称",
"类型",
"内容",
"状态",
"发送时间",
"操作",
"发送人",
"群名称",
"类型",
"内容",
"状态",
"发送时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"暂无数据暂无数据"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "关键字",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "开始时间",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "结束时间",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "刷 新"
}
],
"resources": []
}
@@ -0,0 +1,379 @@
{
"label": "群聊消息",
"slug": "08-group-messages",
"route": "/group-messages",
"url": "https://admin.adfahi.cn/group-messages",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/08-group-messages.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群聊消息\n全部\n文本\n图片\n视频\n语音\n文件\n名片\n系统\n发送人用户名\n关键词\n开始时间\n结束时间\n查 询\n重 置\n刷 新\n发送人\t群名称\t类型\t内容\t状态\t发送时间\t操作\n\n发送人\n\t\n群名称\n\t\n类型\n\t\n内容\n\t\n状态\n\t\n发送时间\n\t\n操作\n\n\nF\nhy69089908\n\t\n冯\n68127154\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:06:05\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n89233971\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:06:05\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n17776111\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:06:05\t\n删 除\n\n\nF\nhy69089908\n\t\n冯\n62262588\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:05:19\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n17776111\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:05:19\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n89233971\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:05:19\t\n删 除\n\n\nF\nhy69089908\n\t\n冯\n68127154\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:05:19\t\n删 除\n\n\nF\nhy69089908\n\t\n冯\n68127154\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:04:12\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n89233971\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:04:12\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n17776111\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:04:12\t\n删 除\n\n\nF\nhy69089908\n\t\n冯\n62262588\n\t文本\t\n哈哈哈哈\n\t正常\t2026-07-31 23:03:50\t\n删 除\n\n\nF\nhy69089908\n\t\n冯氏家族\n17776111\n\t文本\t\n😊😊😊😊\n\t正常\t2026-07-31 22:53:42\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\n冯氏家族\n17776111\n\t文本\t\nkddkkffjc\n\t正常\t2026-07-31 22:53:18\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\n冯氏家族\n17776111\n\t文本\t\nkdododdk\n\t正常\t2026-07-31 22:53:17\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\n冯氏家族\n17776111\n\t文本\t\nfkdkkddoso\n\t正常\t2026-07-31 22:53:16\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\n冯氏家族\n17776111\n\t文本\t\nfkkfkfkd\n\t正常\t2026-07-31 22:53:15\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\n冯氏家族\n17776111\n\t文本\t\nfkfkkdod\n\t正常\t2026-07-31 22:53:14\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯氏家族\n17776111\n\t文本\t\n敏敏\n\t正常\t2026-07-31 22:53:13\t\n删 除\n\n\n冯仁飞\nhy91144536\n\t\n冯氏家族\n17776111\n\t文本\t\nfkfkfkdo\n\t正常\t2026-07-31 22:53:13\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯氏家族\n17776111\n\t文本\t\n您提着\n\t正常\t2026-07-31 22:53:12\t\n删 除\n1\n2\n3\n4\n5\n•••\n8\n20 条/页",
"tables": [
{
"headers": [
"发送人",
"群名称",
"类型",
"内容",
"状态",
"发送时间",
"操作",
"发送人",
"群名称",
"类型",
"内容",
"状态",
"发送时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"Fhy69089908",
"冯68127154",
"文本",
"哈哈哈哈",
"正常",
"2026-07-31 23:06:05",
"删 除"
],
[
"Fhy69089908",
"冯氏家族89233971",
"文本",
"哈哈哈哈",
"正常",
"2026-07-31 23:06:05",
"删 除"
],
[
"Fhy69089908",
"冯氏家族17776111",
"文本",
"哈哈哈哈",
"正常",
"2026-07-31 23:06:05",
"删 除"
],
[
"Fhy69089908",
"冯62262588",
"文本",
"哈哈哈哈",
"正常",
"2026-07-31 23:05:19",
"删 除"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "关键字",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "开始时间",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "结束时间",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "刷 新",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
}
]
}
@@ -0,0 +1,135 @@
{
"label": "敏感词库",
"slug": "09-sensitive-words",
"route": "/sensitive-words",
"url": "https://admin.adfahi.cn/sensitive-words",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/09-sensitive-words.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n敏感词库\n状态\n全部\n等级\n全部\n关键词\n查 询\n重 置\n新增敏感词\n批量导入\n文件导入\n批量导出\nID\t敏感词\t等级\t替换词\t状态\t创建时间\t操作\n\nID\n\t\n敏感词\n\t\n等级\n\t\n替换词\n\t\n状态\n\t\n创建时间\n\t\n操作\n\n\n暂无数据",
"tables": [
{
"headers": [
"ID",
"敏感词",
"等级",
"替换词",
"状态",
"创建时间",
"操作",
"ID",
"敏感词",
"等级",
"替换词",
"状态",
"创建时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"暂无数据暂无数据"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "敏感词",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "新增敏感词"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "批量导入"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "文件导入"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "批量导出"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
}
],
"resources": []
}
@@ -0,0 +1,150 @@
{
"label": "敏感词库",
"slug": "09-sensitive-words",
"route": "/sensitive-words",
"url": "https://admin.adfahi.cn/sensitive-words",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/09-sensitive-words.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n敏感词库\n状态\n全部\n等级\n全部\n关键词\n查 询\n重 置\n新增敏感词\n批量导入\n文件导入\n批量导出\nID\t敏感词\t等级\t替换词\t状态\t创建时间\t操作\n\nID\n\t\n敏感词\n\t\n等级\n\t\n替换词\n\t\n状态\n\t\n创建时间\n\t\n操作\n\n\n暂无数据",
"tables": [
{
"headers": [
"ID",
"敏感词",
"等级",
"替换词",
"状态",
"创建时间",
"操作",
"ID",
"敏感词",
"等级",
"替换词",
"状态",
"创建时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"暂无数据暂无数据"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "敏感词",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "新增敏感词",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "批量导入",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "文件导入",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "批量导出",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
}
]
}
+288
View File
@@ -0,0 +1,288 @@
{
"label": "文件管理",
"slug": "10-files",
"route": "/file-records",
"url": "https://admin.adfahi.cn/file-records",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/10-files.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n文件管理\n全部\n图片\n视频\n音频\n文档\n其他\n发送人用户名\n文件名\n开始时间\n结束时间\n查 询\n重 置\n刷 新\n发送人\t接收方\t类型\t内容\t文件名\t文件大小\tURL\t状态\t发送时间\t操作\n\n发送人\n\t\n接收方\n\t\n类型\n\t\n内容\n\t\n文件名\n\t\n文件大小\n\t\nURL\n\t\n状态\n\t\n发送时间\n\t\n操作\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯氏家族\n17776111\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n64919\n92851806\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n346亿916\n75874312\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯仁飞\nhy91144536\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:46:46\t\n删 除\n1\n20 条/页",
"tables": [
{
"headers": [
"发送人",
"接收方",
"类型",
"内容",
"文件名",
"文件大小",
"URL",
"状态",
"发送时间",
"操作",
"发送人",
"接收方",
"类型",
"内容",
"文件名",
"文件大小",
"URL",
"状态",
"发送时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"冯宇昂hy50703413",
"Fhy69089908",
"图片",
"预览下载",
"--",
"--",
"https://gdd-chat-fls.oss-a...",
"正常",
"2026-07-31 22:48:33",
"删 除"
],
[
"冯宇昂hy50703413",
"冯氏家族17776111",
"图片",
"预览下载",
"--",
"--",
"https://gdd-chat-fls.oss-a...",
"正常",
"2026-07-31 22:48:33",
"删 除"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "搜索文件名",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "开始时间",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "结束时间",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "刷 新"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "下载"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "下载"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "下载"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "下载"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "下载"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除"
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
}
],
"resources": []
}
@@ -0,0 +1,348 @@
{
"label": "文件管理",
"slug": "10-files",
"route": "/file-records",
"url": "https://admin.adfahi.cn/file-records",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/10-files.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n文件管理\n全部\n图片\n视频\n音频\n文档\n其他\n发送人用户名\n文件名\n开始时间\n结束时间\n查 询\n重 置\n刷 新\n发送人\t接收方\t类型\t内容\t文件名\t文件大小\tURL\t状态\t发送时间\t操作\n\n发送人\n\t\n接收方\n\t\n类型\n\t\n内容\n\t\n文件名\n\t\n文件大小\n\t\nURL\n\t\n状态\n\t\n发送时间\n\t\n操作\n\n\n冯宇昂\nhy50703413\n\t\nF\nhy69089908\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯氏家族\n17776111\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n64919\n92851806\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n346亿916\n75874312\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:48:33\t\n删 除\n\n\n冯宇昂\nhy50703413\n\t\n冯仁飞\nhy91144536\n\t图片\t\n预览\n下载\n\t--\t--\thttps://gdd-chat-fls.oss-a...\n\t正常\t2026-07-31 22:46:46\t\n删 除\n1\n20 条/页",
"tables": [
{
"headers": [
"发送人",
"接收方",
"类型",
"内容",
"文件名",
"文件大小",
"URL",
"状态",
"发送时间",
"操作",
"发送人",
"接收方",
"类型",
"内容",
"文件名",
"文件大小",
"URL",
"状态",
"发送时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"冯宇昂hy50703413",
"Fhy69089908",
"图片",
"预览下载",
"--",
"--",
"https://gdd-chat-fls.oss-a...",
"正常",
"2026-07-31 22:48:33",
"删 除"
],
[
"冯宇昂hy50703413",
"冯氏家族17776111",
"图片",
"预览下载",
"--",
"--",
"https://gdd-chat-fls.oss-a...",
"正常",
"2026-07-31 22:48:33",
"删 除"
],
[
"冯宇昂hy50703413",
"6491992851806",
"图片",
"预览下载",
"--",
"--",
"https://gdd-chat-fls.oss-a...",
"正常",
"2026-07-31 22:48:33",
"删 除"
],
[
"冯宇昂hy50703413",
"346亿91675874312",
"图片",
"预览下载",
"--",
"--",
"https://gdd-chat-fls.oss-a...",
"正常",
"2026-07-31 22:48:33",
"删 除"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "搜索文件名",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "开始时间",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "结束时间",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "刷 新",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "下载",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "下载",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "下载",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "下载",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "下载",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "删 除",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
}
]
}
+141
View File
@@ -0,0 +1,141 @@
{
"label": "用户反馈",
"slug": "11-feedback",
"route": "/feedbacks",
"url": "https://admin.adfahi.cn/feedbacks",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/11-feedback.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户反馈\n用户ID\n状态\n全部\n优先级\n全部\n关键词\n查 询\n重 置\n批量处理\n导出 CSV\n\t用户\t优先级\t内容\t状态\t处理人\t创建时间\t操作\n\n\t\n用户\n\t\n优先级\n\t\n内容\n\t\n状态\n\t\n处理人\n\t\n创建时间\n\t\n操作\n\n\n暂无数据",
"tables": [
{
"headers": [
"用户",
"优先级",
"内容",
"状态",
"处理人",
"创建时间",
"操作",
"用户",
"优先级",
"内容",
"状态",
"处理人",
"创建时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"暂无数据暂无数据"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "用户ID",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "内容/联系方式",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "批量处理"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "导出 CSV"
},
{
"disabled": true,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "INPUT",
"text": ""
}
],
"resources": []
}
@@ -0,0 +1,157 @@
{
"label": "用户反馈",
"slug": "11-feedback",
"route": "/feedbacks",
"url": "https://admin.adfahi.cn/feedbacks",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/11-feedback.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n单聊消息\n群聊消息\n敏感词库\n文件管理\n用户反馈\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户反馈\n用户ID\n状态\n全部\n优先级\n全部\n关键词\n查 询\n重 置\n批量处理\n导出 CSV\n\t用户\t优先级\t内容\t状态\t处理人\t创建时间\t操作\n\n\t\n用户\n\t\n优先级\n\t\n内容\n\t\n状态\n\t\n处理人\n\t\n创建时间\n\t\n操作\n\n\n暂无数据",
"tables": [
{
"headers": [
"用户",
"优先级",
"内容",
"状态",
"处理人",
"创建时间",
"操作",
"用户",
"优先级",
"内容",
"状态",
"处理人",
"创建时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"暂无数据暂无数据"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "用户ID",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "内容/联系方式",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查 询",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "批量处理",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "导出 CSV",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
},
{
"disabled": true,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "on"
}
]
}
@@ -0,0 +1,180 @@
{
"label": "操作日志",
"slug": "12-operation-logs",
"route": "/audit-logs",
"url": "https://admin.adfahi.cn/audit-logs",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/12-operation-logs.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n操作日志\n动作\n全部\n目标类型\n全部\n目标用户\n目标群\n开始时间\n结束时间\n查询\n重 置\n导出 CSV\n管理员\t动作\t目标类型\t目标\t查询条件\tIP\t时间\n\n管理员\n\t\n动作\n\t\n目标类型\n\t\n目标\n\t\n查询条件\n\t\nIP\n\t\n时间\n\nheiyue\t创建用户\t用户\t\npoter001\nhy73074162\n\t\n--\n\t104.30.173.163\t2026-08-01 00:04:25\nheiyue\t重置密码\t用户\t\n往事随风\nhy17716319\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:23\nheiyue\t重置密码\t用户\t\n坚守的山羊\nhy34899108\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:19\nheiyue\t重置密码\t用户\t\n沉稳的松鼠\nhy45257043\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:16\nheiyue\t重置密码\t用户\t\n专注的白兔\nhy69598195\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:12\nheiyue\t重置密码\t用户\t\n沉稳的黑猫\nhy20144467\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:09\nheiyue\t重置密码\t用户\t\n坚韧的河马\nhy70299474\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:05\nheiyue\t重置密码\t用户\t\n求真的猫头\nhy23799134\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:00\nheiyue\t重置密码\t用户\t\n进取的北狐\nhy18959373\n\t\n--\n\t141.164.107.33\t2026-07-31 22:44:55\nheiyue\t重置密码\t用户\t\n温润的乌鸦\nhy80424632\n\t\n--\n\t141.164.107.33\t2026-07-31 22:44:51\nheiyue\t重置密码\t用户\t\n乐观的野马\nhy98400466\n\t\n--\n\t141.164.107.33\t2026-07-31 22:44:48\nheiyue\t批量创建用户\t用户\t--\t\n详情\n\t141.164.107.33\t2026-07-31 22:44:06\nheiyue\t创建用户\t用户\t\nF\nhy99111080\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:53\nheiyue\t创建用户\t用户\t\nF\nhy92120233\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:37\nheiyue\t创建用户\t用户\t\nF\nhy69089908\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:12\nheiyue\t创建用户\t用户\t\n冯仁飞\nhy91144536\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:02\nheiyue\t创建用户\t用户\t\n冯宇昂\nhy50703413\n\t\n--\n\t141.164.107.33\t2026-07-31 22:42:45\n1\n20 条/页",
"tables": [
{
"headers": [
"管理员",
"动作",
"目标类型",
"目标",
"查询条件",
"IP",
"时间",
"管理员",
"动作",
"目标类型",
"目标",
"查询条件",
"IP",
"时间"
],
"idx": 0,
"rows": [
[],
[
"heiyue",
"创建用户",
"用户",
"poter001hy73074162",
"--",
"104.30.173.163",
"2026-08-01 00:04:25"
],
[
"heiyue",
"重置密码",
"用户",
"往事随风hy17716319",
"--",
"141.164.107.33",
"2026-07-31 22:45:23"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "用户名",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "群号",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "导出 CSV"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详情"
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
}
],
"resources": []
}
@@ -0,0 +1,218 @@
{
"label": "操作日志",
"slug": "12-operation-logs",
"route": "/audit-logs",
"url": "https://admin.adfahi.cn/audit-logs",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/12-operation-logs.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n操作日志\n动作\n全部\n目标类型\n全部\n目标用户\n目标群\n开始时间\n结束时间\n查询\n重 置\n导出 CSV\n管理员\t动作\t目标类型\t目标\t查询条件\tIP\t时间\n\n管理员\n\t\n动作\n\t\n目标类型\n\t\n目标\n\t\n查询条件\n\t\nIP\n\t\n时间\n\nheiyue\t创建用户\t用户\t\npoter001\nhy73074162\n\t\n--\n\t104.30.173.163\t2026-08-01 00:04:25\nheiyue\t重置密码\t用户\t\n往事随风\nhy17716319\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:23\nheiyue\t重置密码\t用户\t\n坚守的山羊\nhy34899108\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:19\nheiyue\t重置密码\t用户\t\n沉稳的松鼠\nhy45257043\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:16\nheiyue\t重置密码\t用户\t\n专注的白兔\nhy69598195\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:12\nheiyue\t重置密码\t用户\t\n沉稳的黑猫\nhy20144467\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:09\nheiyue\t重置密码\t用户\t\n坚韧的河马\nhy70299474\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:05\nheiyue\t重置密码\t用户\t\n求真的猫头\nhy23799134\n\t\n--\n\t141.164.107.33\t2026-07-31 22:45:00\nheiyue\t重置密码\t用户\t\n进取的北狐\nhy18959373\n\t\n--\n\t141.164.107.33\t2026-07-31 22:44:55\nheiyue\t重置密码\t用户\t\n温润的乌鸦\nhy80424632\n\t\n--\n\t141.164.107.33\t2026-07-31 22:44:51\nheiyue\t重置密码\t用户\t\n乐观的野马\nhy98400466\n\t\n--\n\t141.164.107.33\t2026-07-31 22:44:48\nheiyue\t批量创建用户\t用户\t--\t\n详情\n\t141.164.107.33\t2026-07-31 22:44:06\nheiyue\t创建用户\t用户\t\nF\nhy99111080\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:53\nheiyue\t创建用户\t用户\t\nF\nhy92120233\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:37\nheiyue\t创建用户\t用户\t\nF\nhy69089908\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:12\nheiyue\t创建用户\t用户\t\n冯仁飞\nhy91144536\n\t\n--\n\t141.164.107.33\t2026-07-31 22:43:02\nheiyue\t创建用户\t用户\t\n冯宇昂\nhy50703413\n\t\n--\n\t141.164.107.33\t2026-07-31 22:42:45\n1\n20 条/页",
"tables": [
{
"headers": [
"管理员",
"动作",
"目标类型",
"目标",
"查询条件",
"IP",
"时间",
"管理员",
"动作",
"目标类型",
"目标",
"查询条件",
"IP",
"时间"
],
"idx": 0,
"rows": [
[],
[
"heiyue",
"创建用户",
"用户",
"poter001hy73074162",
"--",
"104.30.173.163",
"2026-08-01 00:04:25"
],
[
"heiyue",
"重置密码",
"用户",
"往事随风hy17716319",
"--",
"141.164.107.33",
"2026-07-31 22:45:23"
],
[
"heiyue",
"重置密码",
"用户",
"坚守的山羊hy34899108",
"--",
"141.164.107.33",
"2026-07-31 22:45:19"
],
[
"heiyue",
"重置密码",
"用户",
"沉稳的松鼠hy45257043",
"--",
"141.164.107.33",
"2026-07-31 22:45:16"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "用户名",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "群号",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查询",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "导出 CSV",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "详情",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
}
]
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,172 @@
{
"label": "群事件审计",
"slug": "14-group-event-audit",
"route": "/group-events",
"url": "https://admin.adfahi.cn/group-events",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/14-group-event-audit.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群事件审计\n群号\n操作人\n目标用户\n事件类型\n全部\n开始时间\n结束时间\n查询\n重 置\n群名称\t事件类型\t操作人\t目标用户\t可见范围\t旧值\t新值\t时间\n\n群名称\n\t\n事件类型\n\t\n操作人\n\t\n目标用户\n\t\n可见范围\n\t\n旧值\n\t\n新值\n\t\n时间\n\n\n冯\n62262588\n\t成员加入\t\nF\nhy69089908\n\t\n冯宇昂\nhy50703413\n\t全员可见\t--\t--\t2026-07-31 23:03:42\n\n冯\n62262588\n\t成员加入\t\nF\nhy69089908\n\t\n冯仁飞\nhy91144536\n\t全员可见\t--\t--\t2026-07-31 23:03:42\n\n冯\n68127154\n\t群创建\t\nF\nhy69089908\n\t--\t全员可见\t--\t--\t2026-07-31 22:50:52\n\n冯氏家族\n89233971\n\t成员加入\t\n冯仁飞\nhy91144536\n\t\n冯宇昂\nhy50703413\n\t全员可见\t--\t--\t2026-07-31 22:50:43\n\n冯氏家族\n89233971\n\t成员加入\t\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t全员可见\t--\t--\t2026-07-31 22:50:43\n\n冯\n62262588\n\t群创建\t\nF\nhy69089908\n\t--\t全员可见\t--\t--\t2026-07-31 22:50:38\n\n冯氏家族\n17776111\n\t成员加入\t\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t全员可见\t--\t--\t2026-07-31 22:50:34\n\n346亿916\n75874312\n\t群创建\t\n冯宇昂\nhy50703413\n\t--\t全员可见\t--\t--\t2026-07-31 22:47:57\n\n64919\n92851806\n\t群创建\t\n冯宇昂\nhy50703413\n\t--\t全员可见\t--\t--\t2026-07-31 22:47:50\n\n冯氏家族\n17776111\n\t成员加入\t\n冯宇昂\nhy50703413\n\t\n冯仁飞\nhy91144536\n\t全员可见\t--\t--\t2026-07-31 22:47:19\n\n冯氏家族\n89233971\n\t群创建\t\n冯仁飞\nhy91144536\n\t--\t全员可见\t--\t--\t2026-07-31 22:46:59\n\n冯氏家族\n17776111\n\t群创建\t\n冯宇昂\nhy50703413\n\t--\t全员可见\t--\t--\t2026-07-31 22:45:28\n1\n20 条/页",
"tables": [
{
"headers": [
"群名称",
"事件类型",
"操作人",
"目标用户",
"可见范围",
"旧值",
"新值",
"时间",
"群名称",
"事件类型",
"操作人",
"目标用户",
"可见范围",
"旧值",
"新值",
"时间"
],
"idx": 0,
"rows": [
[],
[
"冯62262588",
"成员加入",
"Fhy69089908",
"冯宇昂hy50703413",
"全员可见",
"--",
"--",
"2026-07-31 23:03:42"
],
[
"冯62262588",
"成员加入",
"Fhy69089908",
"冯仁飞hy91144536",
"全员可见",
"--",
"--",
"2026-07-31 23:03:42"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "用户名",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "用户名",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
}
],
"resources": []
}
@@ -0,0 +1,210 @@
{
"label": "群事件审计",
"slug": "14-group-event-audit",
"route": "/group-events",
"url": "https://admin.adfahi.cn/group-events",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/14-group-event-audit.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n群事件审计\n群号\n操作人\n目标用户\n事件类型\n全部\n开始时间\n结束时间\n查询\n重 置\n群名称\t事件类型\t操作人\t目标用户\t可见范围\t旧值\t新值\t时间\n\n群名称\n\t\n事件类型\n\t\n操作人\n\t\n目标用户\n\t\n可见范围\n\t\n旧值\n\t\n新值\n\t\n时间\n\n\n冯\n62262588\n\t成员加入\t\nF\nhy69089908\n\t\n冯宇昂\nhy50703413\n\t全员可见\t--\t--\t2026-07-31 23:03:42\n\n冯\n62262588\n\t成员加入\t\nF\nhy69089908\n\t\n冯仁飞\nhy91144536\n\t全员可见\t--\t--\t2026-07-31 23:03:42\n\n冯\n68127154\n\t群创建\t\nF\nhy69089908\n\t--\t全员可见\t--\t--\t2026-07-31 22:50:52\n\n冯氏家族\n89233971\n\t成员加入\t\n冯仁飞\nhy91144536\n\t\n冯宇昂\nhy50703413\n\t全员可见\t--\t--\t2026-07-31 22:50:43\n\n冯氏家族\n89233971\n\t成员加入\t\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t全员可见\t--\t--\t2026-07-31 22:50:43\n\n冯\n62262588\n\t群创建\t\nF\nhy69089908\n\t--\t全员可见\t--\t--\t2026-07-31 22:50:38\n\n冯氏家族\n17776111\n\t成员加入\t\n冯仁飞\nhy91144536\n\t\nF\nhy69089908\n\t全员可见\t--\t--\t2026-07-31 22:50:34\n\n346亿916\n75874312\n\t群创建\t\n冯宇昂\nhy50703413\n\t--\t全员可见\t--\t--\t2026-07-31 22:47:57\n\n64919\n92851806\n\t群创建\t\n冯宇昂\nhy50703413\n\t--\t全员可见\t--\t--\t2026-07-31 22:47:50\n\n冯氏家族\n17776111\n\t成员加入\t\n冯宇昂\nhy50703413\n\t\n冯仁飞\nhy91144536\n\t全员可见\t--\t--\t2026-07-31 22:47:19\n\n冯氏家族\n89233971\n\t群创建\t\n冯仁飞\nhy91144536\n\t--\t全员可见\t--\t--\t2026-07-31 22:46:59\n\n冯氏家族\n17776111\n\t群创建\t\n冯宇昂\nhy50703413\n\t--\t全员可见\t--\t--\t2026-07-31 22:45:28\n1\n20 条/页",
"tables": [
{
"headers": [
"群名称",
"事件类型",
"操作人",
"目标用户",
"可见范围",
"旧值",
"新值",
"时间",
"群名称",
"事件类型",
"操作人",
"目标用户",
"可见范围",
"旧值",
"新值",
"时间"
],
"idx": 0,
"rows": [
[],
[
"冯62262588",
"成员加入",
"Fhy69089908",
"冯宇昂hy50703413",
"全员可见",
"--",
"--",
"2026-07-31 23:03:42"
],
[
"冯62262588",
"成员加入",
"Fhy69089908",
"冯仁飞hy91144536",
"全员可见",
"--",
"--",
"2026-07-31 23:03:42"
],
[
"冯68127154",
"群创建",
"Fhy69089908",
"--",
"全员可见",
"--",
"--",
"2026-07-31 22:50:52"
],
[
"冯氏家族89233971",
"成员加入",
"冯仁飞hy91144536",
"冯宇昂hy50703413",
"全员可见",
"--",
"--",
"2026-07-31 22:50:43"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "用户名",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "用户名",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查询",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
}
]
}
@@ -0,0 +1,102 @@
{
"label": "管理员登录",
"slug": "15-admin-login",
"route": "/admin-login-history",
"url": "https://admin.adfahi.cn/admin-login-history",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/15-admin-login.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n管理员登录历史\n开始时间\n结束时间\n查询\n用户名\t登录时间\tUser-Agent\tIP 地址\n\n用户名\n\t\n登录时间\n\t\nUser-Agent\n\t\nIP 地址\n\nheiyue\t2026-09-04 00:10:57\tMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36\t103.136.251.99\nheiyue\t2026-08-01 00:03:52\tMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36\t104.30.173.163\nheiyue\t2026-07-31 22:47:31\tMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36\t141.164.107.235\nheiyue\t2026-07-31 22:42:09\tMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0\t141.164.107.33\nheiyue\t2026-07-31 21:32:28\tMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36\t104.30.173.163\nheiyue\t2026-07-31 00:45:59\tMozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Mobile/15E148 Safari/604.1\t203.160.80.152\n1\n20 条/页",
"tables": [
{
"headers": [
"用户名",
"登录时间",
"User-Agent",
"IP 地址",
"用户名",
"登录时间",
"User-Agent",
"IP 地址"
],
"idx": 0,
"rows": [
[],
[
"heiyue",
"2026-09-04 00:10:57",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36",
"103.136.251.99"
],
[
"heiyue",
"2026-08-01 00:03:52",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36",
"104.30.173.163"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查询"
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
}
],
"resources": []
}
@@ -0,0 +1,123 @@
{
"label": "管理员登录",
"slug": "15-admin-login",
"route": "/admin-login-history",
"url": "https://admin.adfahi.cn/admin-login-history",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/15-admin-login.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n管理员登录历史\n开始时间\n结束时间\n查询\n用户名\t登录时间\tUser-Agent\tIP 地址\n\n用户名\n\t\n登录时间\n\t\nUser-Agent\n\t\nIP 地址\n\nheiyue\t2026-09-04 00:10:57\tMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36\t103.136.251.99\nheiyue\t2026-08-01 00:03:52\tMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36\t104.30.173.163\nheiyue\t2026-07-31 22:47:31\tMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36\t141.164.107.235\nheiyue\t2026-07-31 22:42:09\tMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0\t141.164.107.33\nheiyue\t2026-07-31 21:32:28\tMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36\t104.30.173.163\nheiyue\t2026-07-31 00:45:59\tMozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Mobile/15E148 Safari/604.1\t203.160.80.152\n1\n20 条/页",
"tables": [
{
"headers": [
"用户名",
"登录时间",
"User-Agent",
"IP 地址",
"用户名",
"登录时间",
"User-Agent",
"IP 地址"
],
"idx": 0,
"rows": [
[],
[
"heiyue",
"2026-09-04 00:10:57",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36",
"103.136.251.99"
],
[
"heiyue",
"2026-08-01 00:03:52",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36",
"104.30.173.163"
],
[
"heiyue",
"2026-07-31 22:47:31",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36",
"141.164.107.235"
],
[
"heiyue",
"2026-07-31 22:42:09",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0",
"141.164.107.33"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查询",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
}
]
}
@@ -0,0 +1,202 @@
{
"label": "用户登录",
"slug": "16-user-login",
"route": "/user-login-history",
"url": "https://admin.adfahi.cn/user-login-history",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/16-user-login.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户登录历史\n用户编号\n用户名\n开始时间\n结束时间\nIP\n查询\n重 置\n用户编号\t用户名\t当前状态\t登录时间\t设备类型\t设备型号\t系统版本\tApp 版本\tIP 地址\t归属地\t操作\n\n用户编号\n\t\n用户名\n\t\n当前状态\n\t\n登录时间\n\t\n设备类型\n\t\n设备型号\n\t\n系统版本\n\t\nApp 版本\n\t\nIP 地址\n\t\n归属地\n\t\n操作\n\n16\thy73074162\t正常\t2026-08-01 00:04:47\tweb\tChrome Browser\tMac OS X 10.15.7\t-\t104.30.173.163\t美国 加利福尼亚州 罗斯维尔\t\n快速封禁\n\n15\thy17716319\t正常\t2026-07-31 22:50:19\tandroid\tOPPO PCHM10\tAndroid 11\t1.1.2\t141.164.107.33\t老挝 万象市 永珍\t\n快速封禁\n\n3\thy69089908\t正常\t2026-07-31 22:47:10\tandroid\tOPPO PKW110\tAndroid 16\t1.1.2\t61.153.184.95\t浙江 绍兴\t\n快速封禁\n\n2\thy91144536\t正常\t2026-07-31 22:45:28\tandroid\tHONOR LOG-AN00\tAndroid 15\t1.1.2\t61.153.184.95\t浙江 绍兴\t\n快速封禁\n\n1\thy50703413\t正常\t2026-07-31 22:45:10\tandroid\tvivo V1809A\tAndroid 9\t1.1.2\t124.160.160.95\t浙江 杭州\t\n快速封禁\n\n1\thy50703413\t正常\t2026-07-31 22:44:44\tandroid\tHONOR LOG-AN00\tAndroid 15\t1.1.2\t61.153.184.95\t浙江 绍兴\t\n快速封禁\n\n1\thy50703413\t正常\t2026-07-31 22:43:38\tandroid\tvivo V1809A\tAndroid 9\t1.1.2\t124.160.160.95\t浙江 杭州\t\n快速封禁\n1\n20 条/页",
"tables": [
{
"headers": [
"用户编号",
"用户名",
"当前状态",
"登录时间",
"设备类型",
"设备型号",
"系统版本",
"App 版本",
"IP 地址",
"归属地",
"操作",
"用户编号",
"用户名",
"当前状态",
"登录时间",
"设备类型",
"设备型号",
"系统版本",
"App 版本",
"IP 地址",
"归属地",
"操作"
],
"idx": 0,
"rows": [
[],
[
"16",
"hy73074162",
"正常",
"2026-08-01 00:04:47",
"web",
"Chrome Browser",
"Mac OS X 10.15.7",
"-",
"104.30.173.163",
"美国 加利福尼亚州 罗斯维尔",
"快速封禁"
],
[
"15",
"hy17716319",
"正常",
"2026-07-31 22:50:19",
"android",
"OPPO PCHM10",
"Android 11",
"1.1.2",
"141.164.107.33",
"老挝 万象市 永珍",
"快速封禁"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "登录IP",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁"
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
}
],
"resources": []
}
@@ -0,0 +1,249 @@
{
"label": "用户登录",
"slug": "16-user-login",
"route": "/user-login-history",
"url": "https://admin.adfahi.cn/user-login-history",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/16-user-login.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n用户登录历史\n用户编号\n用户名\n开始时间\n结束时间\nIP\n查询\n重 置\n用户编号\t用户名\t当前状态\t登录时间\t设备类型\t设备型号\t系统版本\tApp 版本\tIP 地址\t归属地\t操作\n\n用户编号\n\t\n用户名\n\t\n当前状态\n\t\n登录时间\n\t\n设备类型\n\t\n设备型号\n\t\n系统版本\n\t\nApp 版本\n\t\nIP 地址\n\t\n归属地\n\t\n操作\n\n16\thy73074162\t正常\t2026-08-01 00:04:47\tweb\tChrome Browser\tMac OS X 10.15.7\t-\t104.30.173.163\t美国 加利福尼亚州 罗斯维尔\t\n快速封禁\n\n15\thy17716319\t正常\t2026-07-31 22:50:19\tandroid\tOPPO PCHM10\tAndroid 11\t1.1.2\t141.164.107.33\t老挝 万象市 永珍\t\n快速封禁\n\n3\thy69089908\t正常\t2026-07-31 22:47:10\tandroid\tOPPO PKW110\tAndroid 16\t1.1.2\t61.153.184.95\t浙江 绍兴\t\n快速封禁\n\n2\thy91144536\t正常\t2026-07-31 22:45:28\tandroid\tHONOR LOG-AN00\tAndroid 15\t1.1.2\t61.153.184.95\t浙江 绍兴\t\n快速封禁\n\n1\thy50703413\t正常\t2026-07-31 22:45:10\tandroid\tvivo V1809A\tAndroid 9\t1.1.2\t124.160.160.95\t浙江 杭州\t\n快速封禁\n\n1\thy50703413\t正常\t2026-07-31 22:44:44\tandroid\tHONOR LOG-AN00\tAndroid 15\t1.1.2\t61.153.184.95\t浙江 绍兴\t\n快速封禁\n\n1\thy50703413\t正常\t2026-07-31 22:43:38\tandroid\tvivo V1809A\tAndroid 9\t1.1.2\t124.160.160.95\t浙江 杭州\t\n快速封禁\n1\n20 条/页",
"tables": [
{
"headers": [
"用户编号",
"用户名",
"当前状态",
"登录时间",
"设备类型",
"设备型号",
"系统版本",
"App 版本",
"IP 地址",
"归属地",
"操作",
"用户编号",
"用户名",
"当前状态",
"登录时间",
"设备类型",
"设备型号",
"系统版本",
"App 版本",
"IP 地址",
"归属地",
"操作"
],
"idx": 0,
"rows": [
[],
[
"16",
"hy73074162",
"正常",
"2026-08-01 00:04:47",
"web",
"Chrome Browser",
"Mac OS X 10.15.7",
"-",
"104.30.173.163",
"美国 加利福尼亚州 罗斯维尔",
"快速封禁"
],
[
"15",
"hy17716319",
"正常",
"2026-07-31 22:50:19",
"android",
"OPPO PCHM10",
"Android 11",
"1.1.2",
"141.164.107.33",
"老挝 万象市 永珍",
"快速封禁"
],
[
"3",
"hy69089908",
"正常",
"2026-07-31 22:47:10",
"android",
"OPPO PKW110",
"Android 16",
"1.1.2",
"61.153.184.95",
"浙江 绍兴",
"快速封禁"
],
[
"2",
"hy91144536",
"正常",
"2026-07-31 22:45:28",
"android",
"HONOR LOG-AN00",
"Android 15",
"1.1.2",
"61.153.184.95",
"浙江 绍兴",
"快速封禁"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "登录IP",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查询",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "快速封禁",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
}
]
}
@@ -0,0 +1,123 @@
{
"label": "IP 账号统计",
"slug": "17-ip-account-stats",
"route": "/ip-user-stats",
"url": "https://admin.adfahi.cn/ip-user-stats",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/17-ip-account-stats.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\nIP 账号统计\nIP\n查询\n重 置\nIP 地址\t归属地\t关联用户\t注册用户\t登录用户\t正常\t已封禁\t最近活动\t操作\n\nIP 地址\n\t\n归属地\n\t\n关联用户\n\t\n注册用户\n\t\n登录用户\n\t\n正常\n\t\n已封禁\n\t\n最近活动\n\t\n操作\n\n61.153.184.95\t浙江 绍兴\t\n3\n多账号\n\t0\t3\t3\t0\t2026-08-02 22:27:59\t\n用户列表\n共 1 个 IP\n1\n20 条/页",
"tables": [
{
"headers": [
"IP 地址",
"归属地",
"关联用户",
"注册用户",
"登录用户",
"正常",
"已封禁",
"最近活动",
"操作",
"IP 地址",
"归属地",
"关联用户",
"注册用户",
"登录用户",
"正常",
"已封禁",
"最近活动",
"操作"
],
"idx": 0,
"rows": [
[],
[
"61.153.184.95",
"浙江 绍兴",
"3多账号",
"0",
"3",
"3",
"0",
"2026-08-02 22:27:59",
"用户列表"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "IPv4 或 IPv6",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "用户列表"
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
}
],
"resources": []
}
@@ -0,0 +1,134 @@
{
"label": "IP 账号统计",
"slug": "17-ip-account-stats",
"route": "/ip-user-stats",
"url": "https://admin.adfahi.cn/ip-user-stats",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/17-ip-account-stats.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\nIP 账号统计\nIP\n查询\n重 置\nIP 地址\t归属地\t关联用户\t注册用户\t登录用户\t正常\t已封禁\t最近活动\t操作\n\nIP 地址\n\t\n归属地\n\t\n关联用户\n\t\n注册用户\n\t\n登录用户\n\t\n正常\n\t\n已封禁\n\t\n最近活动\n\t\n操作\n\n61.153.184.95\t浙江 绍兴\t\n3\n多账号\n\t0\t3\t3\t0\t2026-08-02 22:27:59\t\n用户列表\n共 1 个 IP\n1\n20 条/页",
"tables": [
{
"headers": [
"IP 地址",
"归属地",
"关联用户",
"注册用户",
"登录用户",
"正常",
"已封禁",
"最近活动",
"操作",
"IP 地址",
"归属地",
"关联用户",
"注册用户",
"登录用户",
"正常",
"已封禁",
"最近活动",
"操作"
],
"idx": 0,
"rows": [
[],
[
"61.153.184.95",
"浙江 绍兴",
"3多账号",
"0",
"3",
"3",
"0",
"2026-08-02 22:27:59",
"用户列表"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "IPv4 或 IPv6",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查询",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "用户列表",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
}
]
}
@@ -0,0 +1,156 @@
{
"label": "登录失败日志",
"slug": "18-login-failures",
"route": "/login-failure-logs",
"url": "https://admin.adfahi.cn/login-failure-logs",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/18-login-failures.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n登录失败日志\n类型\n全部\n登录账号\nIP\n开始时间\n结束时间\n查询\n重 置\n类型\t登录账号\t失败原因\tIP 地址\tUser-Agent\t时间\t操作\n\n类型\n\t\n登录账号\n\t\n失败原因\n\t\nIP 地址\n\t\nUser-Agent\n\t\n时间\n\t\n操作\n\n用户\t13800001111\t密码错误\t106.119.66.106\tMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0\t2026-08-01 01:31:20\t\n解锁\n\n用户\t13800001111\t密码错误\t61.153.184.95\tokhttp/4.12.0\t2026-07-31 22:44:36\t\n解锁\n1\n20 条/页",
"tables": [
{
"headers": [
"类型",
"登录账号",
"失败原因",
"IP 地址",
"User-Agent",
"时间",
"操作",
"类型",
"登录账号",
"失败原因",
"IP 地址",
"User-Agent",
"时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"用户",
"13800001111",
"密码错误",
"106.119.66.106",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0",
"2026-08-01 01:31:20",
"解锁"
],
[
"用户",
"13800001111",
"密码错误",
"61.153.184.95",
"okhttp/4.12.0",
"2026-07-31 22:44:36",
"解锁"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查询"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解锁"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解锁"
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
}
],
"resources": []
}
@@ -0,0 +1,172 @@
{
"label": "登录失败日志",
"slug": "18-login-failures",
"route": "/login-failure-logs",
"url": "https://admin.adfahi.cn/login-failure-logs",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/18-login-failures.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n操作日志\n用户账号审计\n群事件审计\n管理员登录\n用户登录\nIP 账号统计\n登录失败日志\n系统设置\nheiyue\nheiyue\n账户操作\n数据概览\n登录失败日志\n类型\n全部\n登录账号\nIP\n开始时间\n结束时间\n查询\n重 置\n类型\t登录账号\t失败原因\tIP 地址\tUser-Agent\t时间\t操作\n\n类型\n\t\n登录账号\n\t\n失败原因\n\t\nIP 地址\n\t\nUser-Agent\n\t\n时间\n\t\n操作\n\n用户\t13800001111\t密码错误\t106.119.66.106\tMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0\t2026-08-01 01:31:20\t\n解锁\n\n用户\t13800001111\t密码错误\t61.153.184.95\tokhttp/4.12.0\t2026-07-31 22:44:36\t\n解锁\n1\n20 条/页",
"tables": [
{
"headers": [
"类型",
"登录账号",
"失败原因",
"IP 地址",
"User-Agent",
"时间",
"操作",
"类型",
"登录账号",
"失败原因",
"IP 地址",
"User-Agent",
"时间",
"操作"
],
"idx": 0,
"rows": [
[],
[
"用户",
"13800001111",
"密码错误",
"106.119.66.106",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0",
"2026-08-01 01:31:20",
"解锁"
],
[
"用户",
"13800001111",
"密码错误",
"61.153.184.95",
"okhttp/4.12.0",
"2026-07-31 22:44:36",
"解锁"
]
]
}
],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "全部",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "可选",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "查询",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "重 置",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解锁",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "解锁",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": true,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "DIV",
"text": "20 条/页",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
}
]
}
@@ -0,0 +1,67 @@
{
"label": "私域设置",
"slug": "19-private-domain-settings",
"route": "/tenant-settings",
"url": "https://admin.adfahi.cn/tenant-settings",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/19-private-domain-settings.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\n私域设置\n安全策略\nheiyue\nheiyue\n账户操作\n数据概览\n私域设置\n私域设置 - 黑月测试\n消息字符上限\n范围 1~5000,仅允许调低\n图片大小上限(MB)\n范围 1~1000 MB\n文件大小上限(MB)\n范围 1~1000 MB,默认 50 MB\n最大撤回消息时间(分钟)\n群主/管理员撤回自己或他人消息的最长时限,范围 1~1440 分钟;普通用户撤回自己的消息固定为 2 分钟\n是否开启手机验证码\n开启\n关闭\n关闭后,注册仅支持邀请码,短信登录与忘记密码不可用\n保存设置",
"tables": [],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "开启关闭"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "保存设置"
}
],
"resources": []
}
@@ -0,0 +1,75 @@
{
"label": "私域设置",
"slug": "19-private-domain-settings",
"route": "/tenant-settings",
"url": "https://admin.adfahi.cn/tenant-settings",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/19-private-domain-settings.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\n私域设置\n安全策略\nheiyue\nheiyue\n账户操作\n数据概览\n私域设置\n私域设置 - 黑月测试\n消息字符上限\n范围 1~5000,仅允许调低\n图片大小上限(MB)\n范围 1~1000 MB\n文件大小上限(MB)\n范围 1~1000 MB,默认 50 MB\n最大撤回消息时间(分钟)\n群主/管理员撤回自己或他人消息的最长时限,范围 1~1440 分钟;普通用户撤回自己的消息固定为 2 分钟\n是否开启手机验证码\n开启\n关闭\n关闭后,注册仅支持邀请码,短信登录与忘记密码不可用\n保存设置",
"tables": [],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "5000"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "10"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "50"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "2"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "开启关闭",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "保存设置",
"value": ""
}
]
}
@@ -0,0 +1,157 @@
{
"label": "安全策略",
"slug": "20-security-policy",
"route": "/security-settings",
"url": "https://admin.adfahi.cn/security-settings",
"title": "鸽达达管理后台",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots/20-security-policy.png",
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\n私域设置\n安全策略\nheiyue\nheiyue\n账户操作\n数据概览\n安全策略\n用户安全\n验证码触发次数\n连续密码错误该次数后要求验证码(1~10)\n密码最小位数\n用户密码最少字符数(6~32)\n强制包含字母\n开启后密码必须包含英文字母\n注册登录管控\n用户注册功能\n关闭后用户端将隐藏注册入口\n修改密码功能\n关闭后用户无法修改密码,不影响后台重置\n用户登录功能\n关闭后用户无法登录,不影响已登录用户\nWeb 端多端登录\n开启后同一账号可在多个浏览器标签页同时登录\n聊天消息管控\n全局好友功能\n关闭后无法搜索和添加好友\n全局群消息\n关闭后所有群无法发送消息\n全局私聊消息\n关闭后所有私聊无法发送消息\n群聊发言间隔(秒)\n0 表示不限制;1~1000 表示同一群内两次发言的最小间隔\n群组功能管控\n群号搜索功能\n关闭后用户端隐藏群号和群搜索入口\n群创建功能\n关闭后任何人无法新建群聊\n群解散功能\n关闭后任何人无法解散群聊,不影响后台管理员\n群管理员功能\n关闭后任何人无法设置群管理员\n是否显示群人数\n关闭后用户端查看群资料时不显示群总人数\n其他功能开关\n允许用户注销账号\n关闭后用户端将隐藏注销账号按钮\nIP 访问控制\n注册 IP 黑名单\n留空表示不限制;每行一个 IPv4、IPv6 或 CIDR。命中后无法注册及获取注册短信验证码。\n登录 IP 黑名单\n留空表示不限制;命中后无法密码登录、短信登录及刷新 Token。与用户分组登录白名单独立,黑名单优先。\n高级功能\n消息已读状态\n开启后显示消息已读/未读标记\n保存设置",
"tables": [],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "203.0.113.10\n10.0.0.0/8",
"tag": "TEXTAREA",
"text": ""
},
{
"disabled": null,
"placeholder": "198.51.100.0/24",
"tag": "TEXTAREA",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "保存设置"
}
],
"resources": []
}
@@ -0,0 +1,180 @@
{
"label": "安全策略",
"slug": "20-security-policy",
"route": "/security-settings",
"url": "https://admin.adfahi.cn/security-settings",
"screenshot": "/Users/youshunlai/go_workspace/im_manager/docs/admin-adfahi-research/screenshots-queried/20-security-policy.png",
"queried": true,
"text": "鸽达达管理后台\n数据概览\n用户与群组\n内容审核\n日志审计\n系统设置\n私域设置\n安全策略\nheiyue\nheiyue\n账户操作\n数据概览\n安全策略\n用户安全\n验证码触发次数\n连续密码错误该次数后要求验证码(1~10)\n密码最小位数\n用户密码最少字符数(6~32)\n强制包含字母\n开启后密码必须包含英文字母\n注册登录管控\n用户注册功能\n关闭后用户端将隐藏注册入口\n修改密码功能\n关闭后用户无法修改密码,不影响后台重置\n用户登录功能\n关闭后用户无法登录,不影响已登录用户\nWeb 端多端登录\n开启后同一账号可在多个浏览器标签页同时登录\n聊天消息管控\n全局好友功能\n关闭后无法搜索和添加好友\n全局群消息\n关闭后所有群无法发送消息\n全局私聊消息\n关闭后所有私聊无法发送消息\n群聊发言间隔(秒)\n0 表示不限制;1~1000 表示同一群内两次发言的最小间隔\n群组功能管控\n群号搜索功能\n关闭后用户端隐藏群号和群搜索入口\n群创建功能\n关闭后任何人无法新建群聊\n群解散功能\n关闭后任何人无法解散群聊,不影响后台管理员\n群管理员功能\n关闭后任何人无法设置群管理员\n是否显示群人数\n关闭后用户端查看群资料时不显示群总人数\n其他功能开关\n允许用户注销账号\n关闭后用户端将隐藏注销账号按钮\nIP 访问控制\n注册 IP 黑名单\n留空表示不限制;每行一个 IPv4、IPv6 或 CIDR。命中后无法注册及获取注册短信验证码。\n登录 IP 黑名单\n留空表示不限制;命中后无法密码登录、短信登录及刷新 Token。与用户分组登录白名单独立,黑名单优先。\n高级功能\n消息已读状态\n开启后显示消息已读/未读标记\n保存设置",
"tables": [],
"controls": [
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "3"
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "INPUT",
"text": "",
"value": "0"
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "203.0.113.10\n10.0.0.0/8",
"tag": "TEXTAREA",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "198.51.100.0/24",
"tag": "TEXTAREA",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "",
"value": ""
},
{
"disabled": null,
"placeholder": "",
"tag": "BUTTON",
"text": "保存设置",
"value": ""
}
]
}
@@ -0,0 +1,409 @@
# Admin Server 改造文档:对齐鸽达达管理后台
本文基于 `docs/admin-adfahi-research/需求文档.md`、当前 `im_manager` 代码、`im_server` 文档与本地 MySQL 数据核对结果编写。目标是在 HotGo Admin Server 中复刻鸽达达后台的 20 个页面,并保持当前系统“Admin 只直连 hotgo 控制库,IM Server 只直连租户业务库”的边界。
> 实施状态(2026-09-07):Admin 第二批已完成 `imDashboard`、`imPrivateMessage`、`imGroupMessage`、`imUserLoginHistory`、`imLoginFailureLog` 的 API、service、logic、controller、路由、Vue 页面、字典、导出和菜单权限。消息隐藏/删除、失败日志封禁用户使用 Kafka Admin Command;失败 IP 加黑复用安全策略。对应菜单 SQL 为 `server/storage/data/generate/im_adfahi_batch2_menu.sql`,已在本地 `hotgo` 执行。上述查询仍依赖 IM Server 本文约定的 internal-query;本地 `tinode` 尚无 `im_user_login_logs`、`im_login_failure_logs`,需在 IM Server 批次建表并接入日志采集后才会产生真实数据。
## 1. 改造边界
Admin Server 负责后台菜单、权限、页面、查询聚合、运营配置、Kafka 管理命令投递、命令结果展示与后台审计落库。业务 IM 数据不直接跨库读写,用户、群、消息、文件、反馈、登录等租户数据通过 IM Server 内部只读接口 `/internal/admin-query/tenants/{tenant_code}/...` 查询;用户封禁、群治理、消息处置、文件处置等写操作通过 Kafka Admin Command 下发。
当前本地库观察:
| 数据库 | 现状 |
| --- | --- |
| `hotgo` | 当前有 66 张表,已存在 `im_admin_commands`、`im_admin_operation_audit`、`im_admin_outbox`、`im_registration_invite_codes`、`im_external_config`、`im_file_policy`,并已新增策略分组、敏感词、安全策略和宵禁控制表。 |
| `tinode` | 当前有 73 张表,已有 `im_users`、`im_topics`、`im_subscriptions`、`im_messages`、`im_group_messages`、`im_group_settings`、`im_fileuploads`、`im_feedback_submissions` 等 IM 业务表。 |
| 联调状态 | `hotgo.im_tenant` 已补默认租户映射(`id=1`、`code=default`);`tinode` 尚无用户登录历史和登录失败日志表,对应页面待 IM Server 批次补齐数据源。 |
敏感配置说明:`hg_sys_config` 中已有声网、阿里云、OSS、短信等配置项。文档与页面只能展示脱敏值,后续应补充加密存储、轮换、审计与权限控制。
## 2. 当前 Admin 能力盘点
已有后台 API 模块:
| 模块 | 主要能力 | 复用结论 |
| --- | --- | --- |
| `imUser` | 用户列表、详情、设备、重置密码、状态、封禁/解封、冻结/解冻、踢设备、全端登出、注销、删除 | 可作为“用户管理”的主体,补鸽达达字段、筛选项、批量操作与审计页联动。 |
| `imGroup` | 群列表、详情、成员、群治理、资料更新、解散、禁言、成员禁言/移除、入群申请、邀请、公告、文件、管理日志 | 可覆盖“群组管理”和“群成员管理”主体,需补独立菜单页与鸽达达状态/字段映射。 |
| `imInvite` | 邀请码列表、新增、批量新增、批量查看、撤销、批量撤销、导出 | 可覆盖“邀请码管理”,但邀请码格式与鸽达达需求存在差异。 |
| `imFile` | 文件列表、详情、隔离、删除、清理孤儿文件 | 可覆盖“文件管理”,需补预览/下载链接、审核枚举、内容风险字段。 |
| `imAuditLog` | 操作日志列表、详情、导出 | 可覆盖后台操作日志的一部分,需扩展为用户账号审计、群事件审计等专题页。 |
| `imKafkaCommand`、`imDeadLetter`、`imOutbox`、`imKafkaAudit` | Kafka 命令、死信、出站事件、审计事件 | 保留为运维治理菜单,不直接出现在鸽达达 20 个业务页中。 |
| `imRegistration`、`imExternalConfig`、`imFilePolicy`、`imFeedbackConfig`、`imMailboxConfig`、`imNotification`、`imAppRelease` | 注册、第三方、文件策略、反馈、邮箱、通知、版本配置 | 可组合成“私域设置”和“安全策略”,需要按鸽达达页面重组展示。 |
已有菜单已包含 `IM管理`、`注册邀请码`、`用户列表`、`群组列表`、`文件治理`、`Kafka命令`、`Kafka死信`、`Kafka审计事件`、`租户管理` 等。缺少与鸽达达完全一致的“单聊消息、群聊消息、敏感词库、用户反馈、用户登录、IP账号统计、登录失败日志”等前台页面。
## 3. 页面级改造
### 3.1 数据概览
新增或改造 `imDashboard` 页面。顶部统计按需求文档展示总用户数、活跃用户、总群组数、总会话数、总消息数、今日消息;趋势表展示最近 7 天用户增长、消息增长。现有 IM Server 内部接口已有 `/internal/admin-query/tenants/{tenant}/dashboard/summary`,但仅返回 `dead_kafka`、`pending_business`、`pending_group`、`pending_realname`、`received_abuse`、`received_feedback`、`active_groups`、`suspended_users`,不足以还原鸽达达数据概览。
Admin 改造:
| 项 | 方案 |
| --- | --- |
| API | 新增 `/imDashboard/overview`、`/imDashboard/trends`。 |
| 数据源 | 控制库租户信息来自 `im_tenant`;统计与趋势来自 IM internal query。 |
| 字段 | `totalUsers`、`activeUsers`、`totalGroups`、`totalConversations`、`totalMessages`、`todayMessages`、`date`、`userCount`、`messageCount`。 |
| 按钮 | 页面无写操作;支持租户切换、日期范围查询、刷新。 |
| 缺口 | IM Server 需补 dashboard 聚合项与趋势接口;Admin 需补租户为空时的默认租户兜底提示。 |
### 3.2 用户管理
复用 `imUser`,页面按鸽达达字段重排。列表数据通过 IM internal `users` 查询,详情通过 `/users/{id}`,设备通过 `/users/{id}/devices`。当前 Admin 已有 `/imUser/list`、`/imUser/view`、`/imUser/devices`、`/imUser/ban`、`/imUser/unban`、`/imUser/freeze`、`/imUser/unfreeze`、`/imUser/deviceKick`、`/imUser/logoutAll`、`/imUser/accountCancel`、`/imUser/accountDelete`、`/imUser/resetPassword`。
字段说明:
| 字段 | 来源 | 说明 |
| --- | --- | --- |
| `user_id` | `tinode.im_users.id` 编码后 | 用户唯一 ID,列表、详情、审计联动主键。 |
| `username` | `im_users.username` | 登录账号。 |
| `phone` | `im_users.phone` | 手机号,页面默认脱敏,导出需权限。 |
| `nickname` | `im_user_profiles.nickname` | 昵称,支持模糊查询。 |
| `public_account` | `im_user_profiles.public_account` | 对外账号/靓号。 |
| `state` | `im_users.state` | Tinode 用户状态。建议映射为正常、封禁、冻结、注销、删除。 |
| `last_seen` | `im_users.last_seen` | 最后在线/活跃时间。 |
| `created_at` | `im_users.created_at` | 注册时间。 |
| `credentials` | IM internal 聚合 | 认证方式摘要,不展示密钥。 |
按钮功能:
| 按钮 | 已有接口 | 功能 |
| --- | --- | --- |
| 查询 | `/imUser/list` | 按用户 ID、昵称、账号、手机号、状态、注册时间、最后活跃时间筛选。 |
| 重置 | 前端表单重置 | 清空筛选项并重新查询。 |
| 查看 | `/imUser/view` | 展示基础信息、资料、设备、最近审计事件。 |
| 封禁/解封 | `/imUser/ban`、`/imUser/unban` | Kafka 命令 `user.ban` / `user.unban`,需填写原因和过期时间。 |
| 冻结/解冻 | `/imUser/freeze`、`/imUser/unfreeze` | Kafka 命令 `user.freeze` / `user.unfreeze`。 |
| 踢设备 | `/imUser/deviceKick` | 指定设备下线。 |
| 全端登出 | `/imUser/logoutAll` | 下发 `user.logout_all`。 |
| 注销/删除 | `/imUser/accountCancel`、`/imUser/accountDelete` | 高危操作,二次确认并写审计。 |
枚举说明:`state` 当前来自 Tinode 状态值,Admin 应新增统一字典 `im_user_state`,至少包含正常、封禁、冻结、注销、删除。封禁/冻结原因不应写死在前端,可复用“安全策略”中的处置原因配置。
### 3.3 用户分组
当前缺少等价模块,需要新增 `imUserPolicyGroup`。该页面不是组织部门,而是账号策略分组,用于控制注册、登录、私聊、建群、入群、发文件、发消息、IP 限制等策略。
Admin 改造:
| 项 | 方案 |
| --- | --- |
| 后端模块 | `api/admin/imuserpolicygroup`、`controller/admin/sys/im_user_policy_group.go`、`logic/sys/im_user_policy_group.go`、`model/input/sysin/im_user_policy_group.go`。 |
| 控制表 | 新增 `im_user_policy_groups`、`im_user_policy_group_members`。 |
| API | `/imUserPolicyGroup/list`、`/view`、`/edit`、`/delete`、`/status`、`/memberList`、`/memberAdd`、`/memberRemove`。 |
| 同步 | 策略变更写 `im_admin_outbox`,发布 Kafka config event;IM Server 缓存策略并执行。 |
| 页面按钮 | 查询、新增、编辑、删除、启用/禁用、成员管理、导出。 |
字段说明:
| 字段 | 说明 |
| --- | --- |
| `group_code` | 分组编码,唯一,不可编辑。 |
| `group_name` | 分组名称。 |
| `priority` | 命中多个分组时的优先级,数字越大优先级越高。 |
| `status` | 启用、禁用。 |
| `policy_json` | 策略 JSON,包含消息、好友、群、文件、登录等开关与限额。 |
| `ip_whitelist`、`ip_blacklist` | IP 白名单/黑名单,支持 CIDR。 |
| `remark` | 备注。 |
好友策略必须覆盖移动端所有加好友入口,不能只依赖前端隐藏。分组策略中至少包含 `allow_add_friend`、`direct_add_friend`、`max_friend_count`、`allow_view_profile_when_friend_disabled`、`allow_qrcode_add_friend`、`allow_group_member_profile`。当全局或分组禁止加好友时,从搜索、通讯录推荐、群成员列表、个人名片、二维码解析、邀请注册自动加好友、转发目标联系人等入口都必须由后端返回禁止或脱敏数据。
枚举说明:`status` 使用 `sys_normal_disable`;策略开关使用布尔值;策略动作建议统一枚举 `allow`、`deny`、`challenge`、`audit_only`。好友入口枚举建议 `search`、`profile_card`、`group_member`、`qrcode`、`invite_auto_add`、`recommendation`。
### 3.4 群组管理
复用 `imGroup`。列表通过 IM internal `groups` 查询,详情通过 `/groups/{topic}`,现有 Admin 已有群资料、治理、成员、申请、邀请、公告、文件、日志等接口。
字段说明:
| 字段 | 来源 | 说明 |
| --- | --- | --- |
| `topic` | `im_topics.name` | 群 Topic,等价群号/群唯一标识。 |
| `group_name` | `im_group_settings.group_name` | 群名称。 |
| `owner_id` | `im_topics.owner` | 群主。 |
| `group_status` | `im_group_settings.group_status` | 群业务状态。 |
| `state` | `im_topics.state` | Tinode topic 状态。 |
| `business_member_count` | `im_group_settings.business_member_count` | 成员数。 |
| `join_approval` | `im_group_settings.join_approval` | 入群审批开关。 |
| `mute_all` | `im_group_settings.mute_all` | 全员禁言。 |
| `created_at`、`updated_at` | topic/settings | 创建与更新时间。 |
按钮功能:
| 按钮 | 已有接口 | 功能 |
| --- | --- | --- |
| 查询 | `/imGroup/list` | 按群号、群名、群主、状态、创建时间查询。 |
| 查看 | `/imGroup/view` | 群资料、成员、公告、邀请、文件、治理配置汇总。 |
| 编辑资料 | `/imGroup/profileUpdate` | Kafka `group.profile.update`。 |
| 治理设置 | `/imGroup/governanceUpdate` | Kafka `group.governance.update`,控制入群审批、全员禁言、成员上传文件、成员私聊、成员邀请。 |
| 解散 | `/imGroup/dissolve` | 高危操作,二次确认。 |
| 禁言/解禁言 | `/imGroup/mute`、`/imGroup/unmute` | 群级禁言。 |
| 成员/申请/邀请/公告/文件/日志 | 已有子接口 | 打开子面板或跳转专题页。 |
枚举说明:新增 `im_group_status`,建议值 `active` 正常、`muted` 禁言、`suspended` 封停、`dissolved` 已解散。当前 IM 命令未看到明确 `group.ban`/`group.unban`,如鸽达达要求群封停,需要新增 Kafka 命令或通过治理状态统一处理。
### 3.5 群成员管理
复用 `/imGroup/memberList` 与成员治理命令,新增独立菜单页 `imGroupMember`,默认要求输入群号或从群详情跳转携带 `topic`。
字段说明:
| 字段 | 说明 |
| --- | --- |
| `topic` | 群 Topic。 |
| `user_id` | 成员用户 ID。 |
| `display_name`/`nickname` | 群内展示名或用户昵称。 |
| `role` | 群主、管理员、普通成员。 |
| `status` | 正常、禁言、已移除。 |
| `muted_until` | 禁言截止时间。 |
| `joined_at` | 入群时间。 |
按钮功能:查询、查看用户、设为管理员、取消管理员、转让群主、成员禁言、解除禁言、移除成员。现有接口分别为 `/imGroup/adminSet`、`/adminRemove`、`/ownerTransfer`、`/memberMute`、`/memberUnmute`、`/memberRemove`。
枚举说明:`role` 新增字典 `im_group_member_role`:`owner` 群主、`admin` 管理员、`member` 成员;成员状态新增 `im_group_member_status`。
### 3.6 邀请码管理
复用 `imInvite`。本地 `hotgo.im_registration_invite_codes` 有样例数据,批次表为空。当前需求文档按鸽达达页面描述 6 位数字邀请码;历史 IM 文档曾描述 5 位 ASCII 字母邀请码,二者冲突。若以复刻鸽达达为目标,应统一改为 6 位数字,Admin 生成、IM 注册校验、数据库唯一索引与错误文案同步调整。
字段说明:`code` 邀请码、`batch_id` 批次、`status` 状态、`max_uses` 最大使用次数、`used_count` 已使用次数、`expires_at` 过期时间、`created_by` 创建管理员、`created_at` 创建时间、`revoked_at` 撤销时间。
按钮功能:查询、新增、批量生成、批量查看、撤销、批量撤销、导出。接口已有 `/imInvite/list`、`/create`、`/batchCreate`、`/batchView`、`/revoke`、`/batchRevoke`、`/export`。
枚举说明:新增或确认 `im_invite_status`:`unused` 未使用、`used` 已用完、`expired` 已过期、`revoked` 已撤销。
### 3.7 单聊消息
当前 Admin 缺少独立消息管理模块,需要新增 `imPrivateMessage`。IM Server 已有消息表 `im_messages`,但 internal admin query 目前只支持 `/messages/{topic}/{seq}` 单条查询,缺少按会话分页检索单聊消息的后台列表接口。
Admin 改造:
| 项 | 方案 |
| --- | --- |
| API | `/imPrivateMessage/list`、`/view`、`/hide`、`/delete`、`/export`。 |
| 数据源 | 新增 IM internal query:`/tenants/{tenant}/private-messages` 或 `/messages?kind=p2p`。 |
| 写操作 | 通过 Kafka 命令新增 `message.hide`、`message.delete` 或复用 IM 已有 recall/delete 能力封装为后台命令。 |
| 页面按钮 | 查询、查看上下文、隐藏、删除、导出。 |
字段说明:`topic` 会话 Topic、`seq_id` 消息序号、`from_user_id` 发送者、`to_user_id` 接收者、`content_type` 内容类型、`content` 内容摘要、`status` 状态、`created_at` 发送时间、`updated_at` 更新时间。
枚举说明:`content_type` 建议 `text`、`image`、`file`、`audio`、`video`、`card`、`system`;`status` 建议 `normal`、`recalled`、`hidden`、`deleted`。
### 3.8 群聊消息
新增 `imGroupMessage` 页面。IM Server 本地有 `im_group_messages` 表,需求需要按群号、发送者、时间、内容关键字筛选。
Admin 改造:新增 `/imGroupMessage/list`、`/view`、`/hide`、`/delete`、`/export`。IM Server 补 internal query `group-messages`,支持 `topic`、`sender_user_id`、`content_type`、`status`、`created_at_start/end`、`keyword`。
字段、按钮、枚举与单聊消息一致,额外展示 `group_name`、`member_role`、`at_users`、`reply_to_seq`。
### 3.9 敏感词库
当前 Admin 与 IM Server 未发现完整敏感词库模块,需要新增。Admin 维护词库,IM Server 在消息发送、昵称/群名修改、反馈/举报提交时执行匹配。
Admin 改造:
| 项 | 方案 |
| --- | --- |
| 表 | `im_sensitive_words`、`im_sensitive_word_groups`、`im_sensitive_word_hits` 可按需拆分。 |
| API | `/imSensitiveWord/list`、`/view`、`/edit`、`/delete`、`/status`、`/import`、`/export`。 |
| 同步 | 词库变更发布 config event 或 cache invalidate,IM Server 热加载。 |
| 按钮 | 查询、新增、编辑、删除、启用/禁用、导入、导出。 |
字段说明:`word` 敏感词、`match_type` 匹配类型、`scene` 生效场景、`action` 命中动作、`replacement` 替换文本、`level` 风险等级、`status` 状态。
枚举说明:`match_type` 为 `exact` 精确、`contains` 包含、`regex` 正则;`scene` 为 `message` 消息、`profile` 资料、`group` 群资料、`feedback` 反馈;`action` 为 `block` 拦截、`replace` 替换、`review` 人审、`audit_only` 仅记录。
### 3.10 文件管理
复用 `imFile`,补齐鸽达达文件字段和预览能力。IM internal 已支持 `files`、`files/{id}`、`files/{id}/links`。本地 `tinode.im_fileuploads` 有数据,`im_group_files` 暂无数据。
字段说明:`file_id` 文件 ID、`user_id` 上传者、`topic` 所属会话、`mime_type` MIME、`size` 文件大小、`location` 存储位置、`etag` 校验、`status` 状态、`review_status` 审核状态、`risk_level` 风险等级、`created_at` 上传时间。
按钮功能:查询、查看、预览/下载、隔离、删除、清理孤儿文件。现有接口 `/imFile/quarantine`、`/imFile/delete`、`/imFile/cleanupOrphan` 可复用;预览/下载建议由 Admin 获取短期签名 URL,不直接暴露 OSS 原始地址。
枚举说明:现有字典包括 `im_storage_provider=oss`、`im_file_review_provider`、`im_file_review_status(pending/running/clean/risky/failed)`、`im_file_review_task_type(content/malware)`;还需补 `im_file_status`:`normal` 正常、`quarantined` 已隔离、`deleted` 已删除。
### 3.11 用户反馈
IM Server 已有 `im_feedback_submissions` 和 internal resource `feedback-submissions`,Admin 目前有反馈配置和工单模块,但缺少完全按鸽达达展示的反馈列表页。建议新增 `imFeedback` 或改造 `imWorkOrder` 作为反馈处理页。
字段说明:`feedback_id` 反馈 ID、`user_id` 用户、`category` 分类、`content` 内容、`contact` 联系方式、`file_ids` 附件、`client_context` 客户端环境、`include_diagnostics` 是否含诊断、`status` 状态、`created_at`、`updated_at`。
按钮功能:查询、查看、标记处理中、标记已处理、关闭、导出。写操作建议先落 Admin 工单状态,再通过 Kafka 或 IM internal 写接口回写业务状态。
枚举说明:`status` 建议 `received` 已收到、`processing` 处理中、`resolved` 已解决、`closed` 已关闭;`category` 来自 `im_feedback_config.categories`,禁止前端硬编码。
### 3.12 操作日志
复用 `imAuditLog` 与 `im_admin_operation_audit`。本地该表已有 45 条记录。页面应覆盖后台管理员对 IM 资源的所有操作,包括用户、群、消息、文件、配置、邀请码、敏感词。
字段说明:`id`、`request_id`、`admin_id`、`admin_name`、`action`、`target_type`、`target_id`、`before_data`、`after_data`、`ip`、`user_agent`、`result`、`created_at`。
按钮功能:查询、查看详情、导出。详情页需展示变更前后 JSON,敏感字段脱敏。
枚举说明:`target_type` 建议 `user`、`group`、`message`、`file`、`invite`、`config`、`sensitive_word`;`result` 为 `success`、`failed`、`pending`。
### 3.13 用户账号审计
新增专题页 `imUserAccountAudit`,从 Admin 操作审计、IM `audit-logs`、Kafka 命令结果中聚合用户生命周期事件。
字段说明:`event_id`、`user_id`、`action`、`operator_type`、`operator_id`、`reason`、`ip`、`device_id`、`before_state`、`after_state`、`created_at`。
按钮功能:查询、查看、跳转用户详情、导出。动作枚举建议包含注册、登录、登出、登录失败、改密、重置密码、封禁、解封、冻结、解冻、注销、删除、踢设备。
缺口:IM Server 当前 `im_audit_logs` 本地为空,需要补登录、失败、状态变更等事件写入。
### 3.14 群事件审计
可复用 `imGroup/adminLogList`、`outbox/group-events` 和 Admin audit,新增独立页面 `imGroupEventAudit`。
字段说明:`event_id`、`topic`、`group_name`、`operator_id`、`target_user_id`、`action`、`object_type`、`object_id`、`before_data`、`after_data`、`created_at`。
按钮功能:查询、查看、跳转群详情、导出。动作枚举建议包含建群、解散、修改资料、修改治理设置、入群申请、审批通过、审批拒绝、成员禁言、解除禁言、移除成员、设管理员、取消管理员、转让群主、公告发布/删除、文件删除。
### 3.15 管理员登录历史
复用 HotGo 系统登录日志能力,不需要 IM Server 改造。若现有登录日志字段不足,补 Admin 聚合接口 `/imAdminLoginHistory/list` 或直接配置菜单指向系统日志页面。
字段说明:管理员 ID、账号、昵称、登录 IP、地区、浏览器、系统、登录结果、失败原因、登录时间。
按钮功能:查询、查看、导出。枚举 `result` 为成功、失败。
### 3.16 用户登录历史
当前缺少完整用户登录历史。IM Server 路由中未看到客户端 `/v1/im/auth/logout` 或独立 session 管理路由;本地 `im_devices` 为空,不能满足鸽达达登录历史。
Admin 改造:新增 `imUserLoginHistory` 页面,查询 IM internal `user-login-logs`。字段包括 `user_id`、`phone`、`login_type`、`device_id`、`platform`、`ip`、`region`、`user_agent`、`result`、`login_at`、`logout_at`。
枚举说明:`login_type` 为 `password`、`sms`、`token_refresh`、`third_party`;`platform` 为 `ios`、`android`、`web`、`desktop`;`result` 为 `success`、`failed`。
### 3.17 IP 账号统计
新增 `imIpAccountStats` 页面。数据由 IM Server 基于注册 IP、登录 IP、失败登录 IP 聚合生成,Admin 只查询展示。
字段说明:`ip`、`region`、`user_count`、`register_count`、`login_count`、`failure_count`、`first_seen_at`、`last_seen_at`、`risk_level`。
按钮功能:查询、查看关联账号、导出、加入黑名单。加入黑名单写入“安全策略”或“用户分组”策略并同步 IM Server。
枚举说明:`risk_level` 为 `low`、`medium`、`high`;黑名单动作 `block_login`、`challenge`、`audit_only`。
### 3.18 登录失败日志
新增 `imLoginFailureLog` 页面。IM Server 需要记录认证失败事件,包含错误原因、IP、设备、账号、风控命中信息。
字段说明:`id`、`account`、`user_id`、`failure_type`、`reason`、`ip`、`region`、`device_id`、`platform`、`user_agent`、`attempt_at`。
按钮功能:查询、查看、导出、加入 IP 黑名单、封禁账号。封禁账号复用 `/imUser/ban`。
枚举说明:`failure_type` 为 `password_error`、`code_error`、`account_not_found`、`account_disabled`、`rate_limited`、`risk_blocked`。
### 3.19 私域设置
以现有 `imRegistration`、`imExternalConfig`、`imFeedbackConfig`、`imMailboxConfig`、`imNotification`、`imAppRelease` 为基础,新增汇总页面 `imTenantSettings`,按鸽达达页面展示私域基础配置。
字段说明:租户标识、注册开关、邀请码开关、短信开关、默认策略分组、客服/反馈配置、上传配置、客户端功能开关、版本策略、更新时间。客户端功能开关中新增 `global_friend_enabled` 和 `message_curfew_enabled` 的只读摘要,便于运营在私域设置页看到当前私域是否允许加好友、是否存在宵禁;实际编辑入口放在“安全策略”。
按钮功能:查看、编辑、保存、测试第三方配置、发布配置。保存后写 `hg_sys_config` 或 `im_tenant_config`,并通过 Kafka config event 通知 IM Server 刷新缓存。
枚举说明:开关统一使用布尔;配置发布状态 `draft`、`published`、`failed`。
### 3.20 安全策略
新增或重组 `imSecurityPolicy` 页面,统一管理登录安全、密码策略、IP 风控、敏感词动作、文件审核、用户处置原因、消息处置策略、全局好友功能与消息宵禁。
字段说明:`password_policy`、`login_rate_limit`、`ip_blacklist`、`ip_whitelist`、`sensitive_word_policy`、`file_review_policy`、`realname_policy`、`risk_challenge_policy`、`global_friend_enabled`、`friend_disabled_policy`、`message_curfew_enabled`、`message_curfew_rules`。
全局好友功能说明:
| 字段 | 说明 |
| --- | --- |
| `global_friend_enabled` | 全局是否允许加好友。关闭后所有移动端加好友入口都禁止。 |
| `friend_disabled_policy.hide_profile` | 禁止加好友时,群成员列表、个人名片、二维码解析是否隐藏个人资料。 |
| `friend_disabled_policy.block_qrcode` | 是否禁止通过二维码添加好友。 |
| `friend_disabled_policy.block_group_member_entry` | 是否禁止从群成员入口查看个人信息或发起添加。 |
| `friend_disabled_policy.blocked_entries` | 被禁用的移动端入口数组:`search`、`profile_card`、`group_member`、`qrcode`、`invite_auto_add`、`recommendation`。关闭全局好友功能时默认全部禁用。 |
| `friend_disabled_policy.message` | 移动端提示文案,例如“当前时段暂不允许添加好友”。 |
宵禁功能说明:
| 字段 | 说明 |
| --- | --- |
| `message_curfew_enabled` | 是否启用消息宵禁。 |
| `message_curfew_rules` | 宵禁规则数组,支持每天、工作日、周末、自定义日期。 |
| `start_time`、`end_time` | 宵禁开始和结束时间,支持跨天,例如 `18:00` 到次日 `09:00`。 |
| `scope` | 管控范围,默认至少包含 `private_message`,即单聊/私聊不能发消息;如产品确认,可扩展 `group_message`。 |
| `whitelist_user_ids`、`whitelist_group_ids` | 豁免用户或群,可选。 |
| `message` | 宵禁期间发送失败提示。 |
按钮功能:查询当前策略、编辑、保存、发布、恢复默认、查看发布历史。保存必须写操作审计。
枚举说明:风控动作统一 `allow`、`challenge`、`block`、`audit_only`;文件审核动作 `allow`、`quarantine`、`delete`、`manual_review`;宵禁范围 `private_message` 单聊/私聊、`group_message` 群聊;日期类型 `daily` 每天、`weekday` 工作日、`weekend` 周末、`custom` 自定义。
## 4. 后端实现方案
按 HotGo 规范新增模块时,必须完成 API、controller、service、logic、model/input、router/genrouter、前端 API、views/model、index、edit。接口命名沿用当前项目风格,例如 `/imPrivateMessage/list`,不直接照搬鸽达达 `/admin/private-messages` 路径;如后续需要兼容外部路径,可单独加网关映射。
新增模块建议:
| 优先级 | 模块 | 说明 |
| --- | --- | --- |
| P0 | `imDashboard` | 首页统计与趋势。 |
| P0 | `imPrivateMessage`、`imGroupMessage` | 单聊/群聊消息查询与处置。 |
| P0 | `imSensitiveWord` | 敏感词库与热更新。 |
| P0 | `imUserLoginHistory`、`imLoginFailureLog` | 用户登录与失败日志。 |
| P1 | `imUserPolicyGroup` | 用户策略分组。 |
| P1 | `imFeedback` | 用户反馈处理页。 |
| P1 | `imIpAccountStats` | IP 聚合与风控联动。 |
| P1 | `imUserAccountAudit`、`imGroupEventAudit` | 专题审计页。 |
| P2 | `imTenantSettings`、`imSecurityPolicy` | 运营配置整合页。 |
Admin 查询 IM 数据统一走 `server/internal/library/iminternal` 或现有 `imadmin` 封装,不在 logic 层直接拼接外部 HTTP 细节。写操作统一创建 `im_admin_commands` 与 `im_admin_outbox`,等待 Kafka result 更新状态;页面展示 `pending/success/failed/dead`。
## 5. 数据库与字典
配套建表与兼容迁移脚本见 [`sql/Admin-Server改造.sql`](sql/Admin-Server改造.sql)。脚本面向 `hotgo` 控制库,只保存管理配置和发布版本,不保存租户业务消息。
控制库新增表优先放在 `hotgo`:
| 表 | 用途 |
| --- | --- |
| `im_user_policy_groups` | 用户策略分组主表。 |
| `im_user_policy_group_members` | 用户与策略分组关系。 |
| `im_sensitive_word_groups` | 敏感词分组。 |
| `im_sensitive_words` | 敏感词主表。 |
| `im_security_policy` | 安全策略草稿/发布版本。 |
| `im_admin_query_snapshots` | 可选,用于缓存重型统计查询快照。 |
字典由后端 `internal/consts` 注册,前端通过 `dict.loadOptions()` 加载。禁止在 `model.ts` 中硬编码枚举中文。
必补字典:`im_user_state`、`im_group_status`、`im_group_member_role`、`im_group_member_status`、`im_invite_status`、`im_message_content_type`、`im_message_status`、`im_sensitive_match_type`、`im_sensitive_scene`、`im_sensitive_action`、`im_feedback_status`、`im_login_type`、`im_login_failure_type`、`im_risk_level`、`im_policy_action`、`im_friend_entry`、`im_curfew_scope`、`im_curfew_date_type`。
## 6. 权限与审计
每个按钮权限与后端路由保持一致,例如 `/imPrivateMessage/delete`、`/imSensitiveWord/import`。高危操作包括用户删除、账号注销、群解散、消息删除、文件删除、IP 拉黑、安全策略发布,必须二次确认、记录原因、写 `im_admin_operation_audit`,并展示 Kafka 命令执行结果。
审计脱敏规则:
| 类型 | 展示规则 |
| --- | --- |
| 手机号 | 中间 4 位脱敏。 |
| 身份证/实名 | 默认只展示脱敏字段。 |
| 配置密钥 | 只展示前后 3-4 位或完全隐藏。 |
| 消息内容 | 列表展示摘要,详情按权限展示全文。 |
| 文件地址 | 不展示原始存储地址,使用短期签名 URL。 |
## 7. 联调与验收
验收顺序建议:
1. 补齐 `hotgo.im_tenant` 与 `tinode` 默认租户映射,确保 Admin 能通过 tenant code 查询 IM internal。
2. 完成数据概览、用户、群、邀请码、文件这些已有基础模块的字段对齐。
3. 新增消息、敏感词、反馈、登录日志、IP 统计等缺口模块。
4. 为 Kafka 命令增加幂等键、结果回写、失败重试、死信展示。
5. 使用本地 `hotgo` 与 `tinode` 数据验证每个页面的查询、按钮、详情和导出。
最低验收标准:20 个菜单均可打开;查询按钮能返回真实或空态数据;表格字段与需求文档一致;所有枚举来自字典;高危按钮有二次确认、原因、审计与结果状态;敏感数据脱敏。
@@ -0,0 +1,390 @@
# IM Server 改造文档:支撑鸽达达管理后台复刻
本文面向 `/Users/youshunlai/go_workspace/im_server` 的现状改造,目标是为 Admin Server 复刻鸽达达后台提供准确、稳定、可审计的数据与治理能力。当前 IM Server 已有 Tinode 风格实时链路、产品 HTTP API、独立租户库、Kafka 命令消费、配置事件消费、内部 Admin Query,但鸽达达 20 个后台页面仍需要补充若干查询资源、审计日志、风控策略与消息处置能力。
## 1. 当前实现现状
核心架构:
| 能力 | 现状 |
| --- | --- |
| 实时链路 | `Session -> Hub -> Topic -> Store`。 |
| 客户端入口 | WebSocket `/v0/channels`,产品 HTTP `/v1/im/...`。 |
| 后台只读入口 | `/internal/admin-query/tenants/{tenant_code}/...`,要求内部签名与 capability。 |
| 后台写操作 | Kafka Admin Command 消费器 `startKafkaAdminCommandConsumer`。 |
| 配置同步 | Kafka config event、cache invalidate consumer 已存在。 |
| 消息转发 | `/v1/im/messages/forward` 已存在。 |
| 音视频入会 | `/v1/im/calls/rtc-join` 已存在。 |
本地 `tinode` 库观察:`im_users` 有数据、`im_topics` 有群/会话、`im_subscriptions` 有订阅、`im_messages` 有大量单聊或通用消息、`im_group_messages` 有群消息、`im_feedback_submissions`、`im_abuse_reports`、`im_kafka_dead_letters` 等表已存在;`im_audit_logs` 本地为空,`im_devices` 和 `im_group_files` 数据不足,不能直接满足后台登录历史、设备历史和群文件验收。
已有内部查询资源:
| 资源 | 已支持字段/场景 |
| --- | --- |
| `users` | 用户 ID、账号、手机号、状态、资料、凭证摘要、最后在线。 |
| `user_devices` | 用户设备列表。 |
| `groups` | Topic、群名、群主、群状态、治理开关、成员数。 |
| `groups/{topic}/members` | 群成员。 |
| `group_join-requests`、`group_invitations`、`group_announcements`、`group_mutes`、`group_admin-logs`、`group_files` | 群治理专题资源。 |
| `messages/{topic}/{seq}` | 单条消息详情。 |
| `files`、`files/{id}`、`files/{id}/links` | 文件列表、详情、链接关系。 |
| `feedback-submissions`、`abuse-reports`、`realname-verifications`、`audit-logs` | 用户反馈、举报、实名、审计。 |
| `dashboard/summary` | 当前只返回待办类指标,不足以覆盖鸽达达首页统计。 |
已有 Kafka Admin Command:
| 命令 | 用途 |
| --- | --- |
| `user.ban`、`user.unban` | 用户封禁/解封。 |
| `user.freeze`、`user.unfreeze` | 用户冻结/解冻。 |
| `user.device.kick`、`user.logout_all` | 设备踢下线、全端登出。 |
| `user.account.cancel`、`user.account.delete`、`user.password.reset` | 注销、删除、重置密码。 |
| `group.profile.update` | 群资料更新。 |
| `group.governance.update` | 群治理开关更新。 |
| `group.admin.set`、`group.admin.remove`、`group.owner.transfer` | 群角色管理。 |
| `group.member.mute`、`group.member.unmute`、`group.member.remove` | 群成员治理。 |
| `kafka.dead_letter.replay`、`ignore`、`resolve` | 死信处理。 |
## 2. 改造原则
IM Server 只负责租户业务库的数据查询、业务状态变更、实时生效与审计事件产生,不直接依赖 HotGo 后台表。Admin Server 下发的配置、策略和治理命令必须具备幂等性,并通过事件结果回传 Admin。所有 internal query 必须保持只读、分页、最大 `per_page=200`、内部签名鉴权、字段脱敏。
响应协议继续沿用现有 `imHTTPResponse`:`code`、`data`、`reason`、`message`、`details`、`request_id`、`server_time`。写请求继续要求 `Idempotency-Key`,避免后台重复点击导致重复处置。
## 3. 支撑 20 个后台页面的 IM 改造
### 3.1 数据概览
现有 `dashboard/summary` 只覆盖死信、待处理 outbox、待实名、待举报、待反馈、活跃群、封禁用户等运营待办。需要新增统计字段以匹配鸽达达首页。
新增 internal query:
| 路径 | 方法 | 说明 |
| --- | --- | --- |
| `/internal/admin-query/tenants/{tenant}/dashboard/overview` | GET | 返回总用户、活跃用户、总群组、总会话、总消息、今日消息。 |
| `/internal/admin-query/tenants/{tenant}/dashboard/trends` | GET | 返回最近 N 天用户增长与消息增长。 |
字段口径:
| 字段 | 计算建议 |
| --- | --- |
| `total_users` | `im_users` 有效用户数。 |
| `active_users` | `last_seen` 在指定窗口内或当天有消息/登录行为的用户数。 |
| `total_groups` | `im_group_settings.group_status='active'` 或有效群 topic 数。 |
| `total_conversations` | 有效 P2P topic + group topic 数。 |
| `total_messages` | `im_messages` + `im_group_messages`,按最终存储口径去重。 |
| `today_messages` | 当天创建的消息数,按租户时区对齐。 |
| `date`、`user_count`、`message_count` | 趋势表行字段。 |
### 3.2 用户管理
现有 `users`、`users/{id}`、`users/{id}/devices` 基本可支撑。需要补足鸽达达页面要求的筛选和字段脱敏。
改造点:
| 项 | 内容 |
| --- | --- |
| 查询筛选 | 增加 `phone`、`public_account`、`state`、`created_at_start/end`、`last_seen_start/end`。 |
| 字段补充 | 返回 `nickname`、头像文件 ID、性别、地区、签名、认证方式摘要、设备数、最近登录 IP。 |
| 状态映射 | 将 Tinode `state` 转换为 Admin 字典所需状态;保留原始值 `raw_state` 便于排错。 |
| 治理命令 | 继续使用已有 `user.ban/unban/freeze/unfreeze/device.kick/logout_all/account.cancel/account.delete/password.reset`。 |
| 审计 | 每次状态变更、重置密码、踢设备必须写 `im_audit_logs` 并产出 Kafka command result。 |
枚举建议:`user_state` 包含正常、封禁、冻结、注销、删除;`device_platform` 包含 `ios`、`android`、`web`、`desktop`、`unknown`。
### 3.3 用户分组
当前 IM Server 没有看到独立的后台用户策略分组执行层。Admin 将新增策略分组后,IM Server 需要消费配置事件并在运行时执行。
新增能力:
| 能力 | 说明 |
| --- | --- |
| 策略缓存 | 按租户缓存 `policy_group`、成员关系、优先级与规则。 |
| 匹配入口 | 登录、注册、加好友、建群、入群、发消息、上传文件、发起音视频前匹配策略。 |
| 配置事件 | 消费 `user_policy_group.updated`、`user_policy_group.deleted`,刷新缓存。 |
| 命中审计 | 命中 `deny`、`challenge` 或高风险规则时写审计与风控日志。 |
策略动作枚举:`allow` 放行、`deny` 拦截、`challenge` 二次验证、`audit_only` 仅记录。
好友策略需要在后端覆盖所有移动端入口。禁止加好友时,IM Server 不能只让客户端隐藏按钮,而要在搜索用户、查看个人名片、群成员资料、二维码解析、好友申请、邀请注册自动加好友、推荐联系人等入口统一拦截或返回脱敏数据。策略字段建议包含 `allow_add_friend`、`direct_add_friend`、`max_friend_count`、`allow_qrcode_add_friend`、`allow_group_member_profile`、`hide_profile_when_friend_disabled`。
### 3.4 群组管理
已有 `groups` 查询与群治理命令可复用。需要补鸽达达群状态语义和可能的群封停动作。
改造点:
| 项 | 内容 |
| --- | --- |
| 字段 | 确保 `topic`、`group_name`、`owner_id`、`group_status`、`business_member_count`、`join_approval`、`mute_all`、`created_at` 可稳定返回。 |
| 状态 | 明确 `group_status` 值:`active`、`muted`、`suspended`、`dissolved`。 |
| 命令 | 已有资料更新、治理设置、角色与成员治理;若需求要求群封停/解封,新增 `group.suspend`、`group.unsuspend`。 |
| 审计 | 群资料、治理开关、解散、禁言、成员操作均写 `im_group_admin_logs` 与 `im_audit_logs`。 |
### 3.5 群成员管理
现有 `groups/{topic}/members` 与成员命令可支撑。需要确保成员列表返回群角色、禁言状态与入群时间。
字段建议:`topic`、`user_id`、`nickname`、`display_name`、`role`、`status`、`muted_until`、`joined_at`、`last_seen`。`role` 枚举为 `owner`、`admin`、`member`;`status` 枚举为 `active`、`muted`、`removed`。
按钮对应命令:设管理员 `group.admin.set`、取消管理员 `group.admin.remove`、转让群主 `group.owner.transfer`、成员禁言 `group.member.mute`、解除禁言 `group.member.unmute`、移除成员 `group.member.remove`。
### 3.6 邀请码管理
IM Server 注册链路已在 `user.go` 中记录邀请码使用,`RecordUse` 已存在。需要解决邀请码格式冲突:鸽达达需求为 6 位数字,既有 IM 文档曾要求 5 位 ASCII 字母。若严格复刻鸽达达,应将 IM 注册校验、错误提示、唯一性检查、大小写处理统一改为 6 位数字。
改造点:
| 项 | 内容 |
| --- | --- |
| 校验 | 仅允许 `^[0-9]{6}$`,不做大小写转换。 |
| 使用记录 | 注册成功后写 `im_registration_invite_uses`,包含 `code`、`user_id`、`request_id`、`used_at`。 |
| 并发 | 使用事务或唯一约束防止超发。 |
| 状态 | `unused`、`used`、`expired`、`revoked`。 |
### 3.7 单聊消息
当前只有单条消息 detail 查询,不足以支撑后台列表。需要新增 internal message list resource。
新增 internal query:
| 路径 | 方法 | 查询参数 |
| --- | --- | --- |
| `/internal/admin-query/tenants/{tenant}/private-messages` | GET | `topic`、`from_user_id`、`to_user_id`、`content_type`、`status`、`keyword`、`created_at_start/end`、`page`、`per_page`。 |
| `/internal/admin-query/tenants/{tenant}/messages/{topic}/{seq}` | GET | 已有,继续作为详情。 |
返回字段:`topic`、`seq_id`、`from_user_id`、`to_user_id`、`head`、`content_type`、`content_excerpt`、`status`、`created_at`、`updated_at`。全文内容只在详情返回,并根据 Admin 权限决定是否脱敏。
新增 Kafka 命令建议:`message.hide`、`message.unhide`、`message.delete`、`message.restore`。如果只允许软删除,命令语义必须明确为后台不可见还是客户端不可见。
### 3.8 群聊消息
新增 internal group message list resource。可读取 `im_group_messages` 或统一消息表,但需要确保与客户端可见状态一致。
路径:`/internal/admin-query/tenants/{tenant}/group-messages`。
筛选:`topic`、`sender_user_id`、`content_type`、`status`、`keyword`、`created_at_start/end`。返回字段在单聊基础上增加 `group_name`、`reply_to_seq`、`at_users`。
处置命令复用消息命令,审计动作记录为 `message.hidden`、`message.deleted`、`message.restored`。
### 3.9 敏感词库
IM Server 需要新增敏感词运行时,而词库主数据由 Admin 控制库维护。IM Server 只消费配置事件和执行匹配。
改造点:
| 项 | 内容 |
| --- | --- |
| 缓存 | 按租户加载敏感词,支持分组、场景、优先级、状态。 |
| 匹配场景 | 消息发送、编辑消息、用户昵称/签名、群名/公告、反馈/举报内容。 |
| 动作 | `block` 拦截、`replace` 替换、`review` 进入审核、`audit_only` 仅审计。 |
| 审计 | 命中记录写 `im_sensitive_word_hits` 或统一 `im_audit_logs`。 |
| 性能 | 正常词库用 AC 自动机或等价高效结构;正则词单独限量执行。 |
### 3.10 文件管理
已有 internal `files`、`files/{id}`、`files/{id}/links` 与文件生命周期 Kafka 基础。需要补后台预览、下载和处置一致性。
改造点:
| 项 | 内容 |
| --- | --- |
| 文件状态 | `normal`、`quarantined`、`deleted`、`orphan`。 |
| 审核状态 | 复用 `pending`、`running`、`clean`、`risky`、`failed`。 |
| 预览下载 | 提供短期签名 URL 或代理下载,禁止返回永久存储地址。 |
| 隔离删除 | 后台命令应更新文件状态、断开消息/群文件链接、写审计。 |
| 安全审核 | 接入内容安全/恶意文件检测结果,并可重试审核。 |
### 3.11 用户反馈
已有 `feedback-submissions` 资源可查询。需要补处理状态回写能力和状态审计。
新增能力:
| 能力 | 说明 |
| --- | --- |
| 状态更新 | 提供 Kafka 命令或内部写接口:`feedback.status.update`。 |
| 附件 | 通过文件链接查询反馈附件,并返回签名预览 URL。 |
| 分类 | 分类来自 `im_feedback_config.categories`,Admin 配置后 IM bootstrap 同步。 |
| 审计 | 处理人、处理备注、前后状态写入审计。 |
状态枚举:`received`、`processing`、`resolved`、`closed`。
### 3.12 操作日志
IM Server 需要补充业务侧审计完整性。当前本地 `im_audit_logs` 为空,不能支撑后台多页面审计。
写入场景:用户状态变更、群治理、消息处置、文件处置、反馈处理、敏感词命中、登录成功/失败、配置热更新、Kafka 命令执行结果。
字段:`request_id`、`actor_user_id`、`action`、`target_type`、`target_id`、`ip`、`user_agent`、`detail`、`created_at`。`detail` 中敏感值必须脱敏或存 hash。
### 3.13 用户账号审计
新增或扩展 internal resource `user-account-audit`,按用户聚合账号生命周期事件。
路径:`/internal/admin-query/tenants/{tenant}/user-account-audit`。
筛选:`user_id`、`action`、`operator_id`、`ip`、`created_at_start/end`。返回:`event_id`、`user_id`、`action`、`operator_type`、`operator_id`、`before_state`、`after_state`、`reason`、`ip`、`device_id`、`created_at`。
动作枚举:`registered`、`login_success`、`logout`、`login_failed`、`password_changed`、`password_reset`、`banned`、`unbanned`、`frozen`、`unfrozen`、`device_kicked`、`cancelled`、`deleted`。
### 3.14 群事件审计
已有 `im_group_admin_logs` 与 group outbox,可新增 internal resource `group-event-audit` 或复用 `group_admin-logs` 扩展为全局查询。
路径:`/internal/admin-query/tenants/{tenant}/group-event-audit`。
筛选:`topic`、`operator_id`、`target_user_id`、`action`、`created_at_start/end`。返回:`event_id`、`topic`、`operator_id`、`target_user_id`、`action`、`object_type`、`object_id`、`before_data`、`after_data`、`created_at`。
### 3.15 管理员登录历史
该页面主要由 Admin Server 的 HotGo 登录日志提供,IM Server 无需改造。若以后要展示 Admin 调用 IM internal API 的访问审计,可在 internal API 层增加 `internal_api_access_logs`,但不作为复刻 P0。
### 3.16 用户登录历史
当前缺少完整登录历史表与查询。需要在认证成功、token 刷新、主动/被动登出时记录日志。
新增表建议:`im_user_login_logs`。
字段:`id`、`user_id`、`login_type`、`device_id`、`platform`、`ip`、`region`、`user_agent`、`request_id`、`result`、`login_at`、`logout_at`、`created_at`。
新增 internal query:`/internal/admin-query/tenants/{tenant}/user-login-logs`,支持按 `user_id`、`phone/account`、`ip`、`platform`、`login_at_start/end` 查询。
### 3.17 IP 账号统计
新增聚合查询,来源为注册、登录成功、登录失败、风控命中日志。
路径:`/internal/admin-query/tenants/{tenant}/ip-account-stats`。
字段:`ip`、`region`、`user_count`、`register_count`、`login_count`、`failure_count`、`first_seen_at`、`last_seen_at`、`risk_level`。该接口可以实时聚合,也可以由定时任务写入快照表以降低查询成本。
### 3.18 登录失败日志
新增表建议:`im_login_failure_logs`。
字段:`id`、`account`、`user_id`、`failure_type`、`reason`、`ip`、`region`、`device_id`、`platform`、`user_agent`、`request_id`、`attempt_at`。
新增 internal query:`/internal/admin-query/tenants/{tenant}/login-failure-logs`。失败类型枚举:`password_error`、`code_error`、`account_not_found`、`account_disabled`、`rate_limited`、`risk_blocked`。
### 3.19 私域设置
IM Server 需要确保客户端 `/v1/im/bootstrap` 使用 Admin 发布后的配置,并支持热更新。
配置来源:
| 配置 | 使用位置 |
| --- | --- |
| 注册/邀请码/短信 | 注册、验证码、密码找回。 |
| 上传/文件审核 | 上传、预览、消息附件。 |
| 反馈/邮箱/通知 | 客户端入口与提交表单。 |
| 版本/工作台 | bootstrap、app release、workbench。 |
| 声网/音视频 | `/v1/im/calls/rtc-join`。 |
| 好友功能 | `/v1/im/bootstrap` 返回 `global_friend_enabled`、入口隐藏建议和提示文案;实际拦截由后端完成。 |
| 消息宵禁 | `/v1/im/bootstrap` 返回当前宵禁摘要和提示文案;发送消息时仍以后端实时校验为准。 |
改造点:配置事件必须带版本号;IM 缓存应支持按租户回滚到上一发布版本;bootstrap 返回的配置只包含客户端需要的非敏感字段。
### 3.20 安全策略
IM Server 是安全策略的执行层。需要将 Admin 发布的策略接入登录、验证码、消息、文件、群、好友、实名、音视频等关键入口。全局禁止加好友和宵禁必须后端强制执行,客户端展示仅作为体验优化。
策略项:
| 策略 | 执行点 |
| --- | --- |
| 密码强度 | 注册、改密、重置密码。 |
| 登录限频 | 登录、验证码校验、密码找回。 |
| IP 黑白名单 | 登录、注册、发消息、上传文件。 |
| 敏感词 | 消息、资料、群资料、反馈。 |
| 文件审核 | 上传完成、消息发送前后、后台重审。 |
| 实名要求 | 加好友、建群、入群、发起音视频等敏感能力。 |
| 风控挑战 | 登录异常、IP 异常、设备异常。 |
| 全局好友功能 | 用户搜索、好友申请、二维码解析、群成员资料、个人名片、推荐联系人、邀请注册自动加好友。 |
| 消息宵禁 | 单聊/私聊发送消息入口,默认拦截 P2P topic 的 `{pub}`;如产品确认群聊也管控,可扩展到 group topic。 |
动作枚举统一为 `allow`、`challenge`、`block`、`audit_only`。
全局禁止加好友执行规则:
| 入口 | 后端行为 |
| --- | --- |
| 用户搜索 `/v1/im/users/search` | 可直接返回空列表,或返回脱敏结果但不允许发起好友申请。 |
| 用户详情 `/v1/im/users/{id}` | 非好友场景隐藏手机号、账号、二维码、个人扩展资料,只保留必要公开字段。 |
| 好友申请 `/v1/im/friend-requests` | 返回业务错误 reason,例如 `FRIEND_DISABLED`。 |
| 二维码解析 `/v1/im/qrcodes/resolve` | 禁止解析出可加好友目标,或返回脱敏提示。 |
| 群成员资料 | 群成员列表可保留昵称/头像用于群聊展示,但点击个人信息时返回脱敏资料并禁止添加。 |
| 邀请注册自动加好友 | 注册成功后跳过自动加好友并写审计,或按策略直接拒绝该邀请码能力。 |
宵禁执行规则:
| 项 | 说明 |
| --- | --- |
| 配置 | `message_curfew_enabled`、`message_curfew_rules`,规则包含时区、日期类型、开始时间、结束时间、scope、白名单、提示文案。 |
| 判断时机 | P2P topic 发布消息前校验;HTTP 消息发送、转发、草稿转发送等入口也要校验。 |
| 拦截结果 | 返回明确 reason,例如 `MESSAGE_CURFEW_ACTIVE`,并记录 `im_audit_logs` 或风控日志。 |
| 白名单 | 支持用户、系统账号、特定会话豁免。 |
| 跨天 | 支持如下班后 `18:00-09:00` 的跨天时间段。 |
## 4. Internal Admin Query 新增清单
建议在 `server/internal_admin_query_resources.go` 增补资源,并在 `server/internal_api.go` 路由分发中注册:
| 资源 | 必要性 | 说明 |
| --- | --- | --- |
| `dashboard/overview`、`dashboard/trends` | P0 | 首页统计。 |
| `private-messages`、`group-messages` | P0 | 消息管理列表。 |
| `user-login-logs`、`login-failure-logs` | P0 | 登录审计。 |
| `ip-account-stats` | P1 | IP 风险聚合。 |
| `user-account-audit`、`group-event-audit` | P1 | 专题审计。 |
| `sensitive-word-hits` | P1 | 敏感词命中查询。 |
所有列表接口返回现有结构:`items`、`total`、`page`、`per_page`。时间筛选继续使用 `created_at_start`、`created_at_end` 等字段,UID 参数继续支持数字 ID 与 `usr...` 编码。
## 5. Kafka 命令新增清单
已有用户与群治理命令保留。为复刻后台补充以下命令:
| 命令 | 说明 |
| --- | --- |
| `message.hide` | 后台隐藏消息,客户端不可见或后台标记隐藏。 |
| `message.unhide` | 恢复隐藏消息。 |
| `message.delete` | 后台删除消息,建议软删除。 |
| `message.restore` | 恢复误删消息。 |
| `file.quarantine` | 文件隔离。 |
| `file.delete` | 文件删除。 |
| `feedback.status.update` | 反馈处理状态更新。 |
| `group.suspend`、`group.unsuspend` | 如产品确认需要群封停/解封,则新增。 |
| `security.policy.reload` | 强制刷新安全策略缓存。 |
| `friend.policy.reload` | 强制刷新好友入口策略缓存,可与 `security.policy.reload` 合并实现。 |
| `curfew.policy.reload` | 强制刷新宵禁策略缓存,可与 `security.policy.reload` 合并实现。 |
命令 payload 必须包含 `command_id`、`actor_user_id`、`reason`、目标 ID、`version` 或 `expected_version`。执行后发布 result,状态为 `success`、`failed`、`dead`。
## 6. 数据库改造建议
配套建表与兼容迁移脚本见 [`sql/IM-Server改造.sql`](sql/IM-Server改造.sql)。脚本默认使用本地 `tinode`,上线时必须对每个独立租户数据库分别执行,租户业务表不增加 `tenant_id`。
租户库新增或补强表:
| 表 | 用途 |
| --- | --- |
| `im_user_login_logs` | 用户登录成功、登出、刷新等历史。 |
| `im_login_failure_logs` | 登录失败与风控拦截历史。 |
| `im_message_admin_actions` | 后台消息处置记录,可与消息表状态解耦。 |
| `im_sensitive_word_hits` | 敏感词命中记录。 |
| `im_ip_account_stats_daily` | IP 账号统计快照,可选。 |
已有表需补数据写入:`im_audit_logs` 当前本地为空,需要在关键业务入口统一写;`im_devices` 本地为空,需要确认设备绑定/解绑路径是否完整;`im_group_files` 本地为空,需要验证群文件写入链路。
索引建议:消息列表按 `(topic, created_at)`、`(from, created_at)`;登录日志按 `(user_id, login_at)`、`(ip, login_at)`;失败日志按 `(account, attempt_at)`、`(ip, attempt_at)`;敏感词命中按 `(scene, created_at)`、`(user_id, created_at)`。
## 7. 验收要求
1. Admin 20 个页面的查询按钮均能通过 internal query 返回真实数据或标准空态。
2. 用户、群、消息、文件、反馈的后台写操作均通过 Kafka 命令,具备幂等、结果回传、死信处理。
3. 登录历史、失败日志、账号审计、群事件审计不再依赖空表,关键入口可产生真实审计数据。
4. 敏感词与安全策略变更可热更新,无需重启 IM Server。
5. 所有 internal query 均保持只读、分页、鉴权、脱敏和错误 reason 规范。
6. 邀请码格式在 Admin 与 IM 注册链路完全一致,避免后台生成后客户端无法使用。
@@ -0,0 +1,70 @@
[
{
"endpoint": "/admin/stats",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/users",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/user-policy-groups",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/groups",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/groups/events",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/invite-codes",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/messages/search",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/sensitive-words",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/feedbacks",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/audit/logs",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/audit/user-account-logs",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/admin-login-history",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/user-login-history",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/audit/ip-user-stats",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/login-failure-logs",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/tenant-settings",
"error": "TypeError: window.fetch is not a function"
},
{
"endpoint": "/admin/security-settings",
"error": "TypeError: window.fetch is not a function"
}
]
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@@ -0,0 +1,350 @@
-- Admin Server schema changes for the GedaDa management-console adaptation.
-- Target: MySQL 8.0+, control database `hotgo`.
-- Scope: control-plane configuration only. Do not create tenant business data here.
-- Review before execution. DDL statements auto-commit in MySQL.
SET NAMES utf8mb4;
USE `hotgo`;
-- ============================================================
-- 1. User policy groups.
-- status: 1=enabled, 2=disabled.
-- policy_json action values: allow, deny, challenge, audit_only.
-- Friend entry values: search, profile_card, group_member, qrcode,
-- invite_auto_add, recommendation.
-- ============================================================
CREATE TABLE IF NOT EXISTS `im_user_policy_groups` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '0 means global default',
`group_code` varchar(64) NOT NULL COMMENT 'Stable policy group code',
`group_name` varchar(128) NOT NULL COMMENT 'Policy group name',
`priority` int NOT NULL DEFAULT 0 COMMENT 'Higher value has higher priority',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
`policy_json` json NOT NULL COMMENT 'Login, friend, message, group and file policies',
`ip_whitelist` json DEFAULT NULL COMMENT 'IPv4/IPv6 or CIDR list',
`ip_blacklist` json DEFAULT NULL COMMENT 'IPv4/IPv6 or CIDR list',
`version` int unsigned NOT NULL DEFAULT 1 COMMENT 'Optimistic-lock/config version',
`remark` varchar(500) NOT NULL DEFAULT '',
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_user_policy_group_code` (`tenant_id`, `group_code`),
KEY `idx_im_user_policy_group_list` (`tenant_id`, `status`, `priority`, `id`),
KEY `idx_im_user_policy_group_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM user policy groups';
CREATE TABLE IF NOT EXISTS `im_user_policy_group_members` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0,
`group_id` bigint NOT NULL,
`user_id` bigint NOT NULL COMMENT 'User ID in the tenant database',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
`valid_from` datetime(3) DEFAULT NULL,
`valid_until` datetime(3) DEFAULT NULL,
`remark` varchar(500) NOT NULL DEFAULT '',
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_user_policy_group_member` (`group_id`, `user_id`),
KEY `idx_im_user_policy_member_user` (`tenant_id`, `user_id`, `status`),
KEY `idx_im_user_policy_member_validity` (`status`, `valid_from`, `valid_until`),
KEY `idx_im_user_policy_member_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM user-to-policy-group assignments';
-- ============================================================
-- 2. Sensitive word dictionary.
-- match_type: exact, contains, regex, pinyin.
-- action: replace, block, audit_only, manual_review.
-- risk_level: low, medium, high.
-- scene_json values include private_message, group_message, user_profile,
-- group_profile, feedback, report.
-- ============================================================
CREATE TABLE IF NOT EXISTS `im_sensitive_word_groups` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '0 means global dictionary',
`group_code` varchar(64) NOT NULL,
`group_name` varchar(128) NOT NULL,
`priority` int NOT NULL DEFAULT 0,
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
`remark` varchar(500) NOT NULL DEFAULT '',
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_sensitive_word_group_code` (`tenant_id`, `group_code`),
KEY `idx_im_sensitive_word_group_list` (`tenant_id`, `status`, `priority`, `id`),
KEY `idx_im_sensitive_word_group_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM sensitive word groups';
CREATE TABLE IF NOT EXISTS `im_sensitive_words` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '0 means global dictionary',
`group_id` bigint NOT NULL,
`word` varchar(255) NOT NULL,
`word_hash` char(64) NOT NULL COMMENT 'SHA-256 of normalized word',
`match_type` varchar(24) NOT NULL DEFAULT 'contains',
`scene_json` json NOT NULL COMMENT 'Enabled scenes',
`action` varchar(24) NOT NULL DEFAULT 'block',
`replacement` varchar(255) NOT NULL DEFAULT '',
`risk_level` varchar(16) NOT NULL DEFAULT 'medium',
`priority` int NOT NULL DEFAULT 0,
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
`remark` varchar(500) NOT NULL DEFAULT '',
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_sensitive_word_normalized` (`tenant_id`, `group_id`, `word_hash`),
KEY `idx_im_sensitive_word_list` (`tenant_id`, `status`, `risk_level`, `id`),
KEY `idx_im_sensitive_word_group` (`group_id`, `status`, `priority`),
KEY `idx_im_sensitive_word_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM sensitive words';
-- ============================================================
-- 3. Versioned security policy.
-- publish_status: draft, published, archived, failed.
-- The latest published row is the source of truth. The summary switches in
-- im_tenant_config are updated in the same application transaction on publish.
-- ============================================================
CREATE TABLE IF NOT EXISTS `im_security_policy` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '0 means global fallback policy',
`policy_version` int unsigned NOT NULL,
`policy_name` varchar(128) NOT NULL DEFAULT '',
`publish_status` varchar(16) NOT NULL DEFAULT 'draft',
`password_policy` json DEFAULT NULL,
`login_rate_limit` json DEFAULT NULL,
`sensitive_word_policy` json DEFAULT NULL,
`file_review_policy` json DEFAULT NULL,
`realname_policy` json DEFAULT NULL,
`risk_challenge_policy` json DEFAULT NULL,
`global_friend_enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Backend master switch for every add-friend entry',
`friend_disabled_policy` json DEFAULT NULL COMMENT 'Profile masking, QR and group-member restrictions',
`message_curfew_enabled` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Backend master switch for message curfew',
`remark` varchar(500) NOT NULL DEFAULT '',
`published_at` datetime(3) DEFAULT NULL,
`published_by` bigint DEFAULT NULL,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_security_policy_version` (`tenant_id`, `policy_version`),
KEY `idx_im_security_policy_publish` (`tenant_id`, `publish_status`, `published_at`),
KEY `idx_im_security_policy_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Versioned IM security policies';
CREATE TABLE IF NOT EXISTS `im_message_curfew_rules` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0,
`policy_id` bigint NOT NULL,
`rule_code` varchar(64) NOT NULL,
`rule_name` varchar(128) NOT NULL,
`date_type` varchar(16) NOT NULL DEFAULT 'daily' COMMENT 'daily, weekday, weekend, custom',
`custom_dates` json DEFAULT NULL COMMENT 'YYYY-MM-DD values for custom date type',
`weekdays` json DEFAULT NULL COMMENT 'ISO weekdays 1 through 7',
`timezone` varchar(64) NOT NULL DEFAULT 'Asia/Shanghai',
`start_time` time NOT NULL,
`end_time` time NOT NULL COMMENT 'Less than start_time means crossing midnight',
`scope` varchar(24) NOT NULL DEFAULT 'private_message' COMMENT 'private_message or group_message',
`whitelist_user_ids` json DEFAULT NULL,
`whitelist_group_ids` json DEFAULT NULL,
`message` varchar(255) NOT NULL DEFAULT '当前时段暂不能发送消息',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
`sort` int NOT NULL DEFAULT 0,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_message_curfew_rule` (`policy_id`, `rule_code`),
KEY `idx_im_message_curfew_policy` (`tenant_id`, `policy_id`, `status`, `sort`),
KEY `idx_im_message_curfew_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Message curfew rules';
CREATE TABLE IF NOT EXISTS `im_security_ip_rules` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` bigint NOT NULL DEFAULT 0,
`rule_type` varchar(16) NOT NULL COMMENT 'whitelist or blacklist',
`ip_cidr` varchar(64) NOT NULL COMMENT 'IPv4, IPv6 or CIDR',
`action` varchar(24) NOT NULL DEFAULT 'block' COMMENT 'allow, challenge, block, audit_only',
`scene_json` json NOT NULL COMMENT 'login, register, message, upload and other scenes',
`risk_level` varchar(16) NOT NULL DEFAULT 'high',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1 enabled, 2 disabled',
`expires_at` datetime(3) DEFAULT NULL,
`remark` varchar(500) NOT NULL DEFAULT '',
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` bigint NOT NULL DEFAULT 0,
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`updated_by` bigint NOT NULL DEFAULT 0,
`deleted_at` datetime(3) DEFAULT NULL,
`deleted_by` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_security_ip_rule` (`tenant_id`, `rule_type`, `ip_cidr`),
KEY `idx_im_security_ip_rule_list` (`tenant_id`, `status`, `rule_type`, `id`),
KEY `idx_im_security_ip_rule_expiry` (`status`, `expires_at`),
KEY `idx_im_security_ip_rule_deleted` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='IM IP whitelist and blacklist rules';
-- ============================================================
-- 4. Lightweight published-policy summary in im_tenant_config.
-- These columns are read optimizations, not the policy source of truth.
-- The conditional ALTER blocks are safe to rerun on MySQL 8.0.
-- ============================================================
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_tenant_config'
AND COLUMN_NAME = 'default_policy_group_id') = 0,
'ALTER TABLE `im_tenant_config` ADD COLUMN `default_policy_group_id` BIGINT DEFAULT NULL COMMENT ''Default user policy group'' AFTER `max_group_members`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_tenant_config'
AND COLUMN_NAME = 'security_policy_version') = 0,
'ALTER TABLE `im_tenant_config` ADD COLUMN `security_policy_version` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''Published security policy version'' AFTER `default_policy_group_id`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_tenant_config'
AND COLUMN_NAME = 'global_friend_enabled') = 0,
'ALTER TABLE `im_tenant_config` ADD COLUMN `global_friend_enabled` TINYINT(1) NOT NULL DEFAULT 1 COMMENT ''Published global friend switch'' AFTER `security_policy_version`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_tenant_config'
AND COLUMN_NAME = 'message_curfew_enabled') = 0,
'ALTER TABLE `im_tenant_config` ADD COLUMN `message_curfew_enabled` TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''Published message curfew switch'' AFTER `global_friend_enabled`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
-- ============================================================
-- 5. Invitation-code compatibility for the 6-digit target format.
-- Existing 5-letter codes remain stored and valid during the application
-- rollout. New code generation must switch to exactly six ASCII digits, while
-- Admin and IM Server temporarily accept both legacy 5-letter and new 6-digit
-- values. max_uses=0 preserves the current unlimited-use behavior.
-- ============================================================
SET @im_sql = IF(
(SELECT CHARACTER_MAXIMUM_LENGTH FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_registration_invite_codes'
AND COLUMN_NAME = 'code') = 5,
'ALTER TABLE `im_registration_invite_codes` MODIFY COLUMN `code` CHAR(6) CHARACTER SET ascii COLLATE ascii_bin NOT NULL',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_registration_invite_codes'
AND COLUMN_NAME = 'max_uses') = 0,
'ALTER TABLE `im_registration_invite_codes` ADD COLUMN `max_uses` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''0 means unlimited'' AFTER `expires_at`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_registration_invite_batches'
AND COLUMN_NAME = 'max_uses_per_code') = 0,
'ALTER TABLE `im_registration_invite_batches` ADD COLUMN `max_uses_per_code` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''0 means unlimited'' AFTER `quantity`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
-- ============================================================
-- 6. Safe global fallback policy.
-- Tenant-specific published policies override tenant_id=0.
-- This keeps existing behavior permissive until an administrator publishes
-- the first tenant policy.
-- ============================================================
INSERT INTO `im_security_policy` (
`tenant_id`, `policy_version`, `policy_name`, `publish_status`,
`global_friend_enabled`, `friend_disabled_policy`,
`message_curfew_enabled`, `remark`, `published_at`, `published_by`,
`created_by`, `updated_by`
)
SELECT
0, 1, '全局默认安全策略', 'published',
1,
JSON_OBJECT(
'hide_profile', TRUE,
'block_qrcode', TRUE,
'block_group_member_entry', TRUE,
'blocked_entries', JSON_ARRAY(
'search', 'profile_card', 'group_member',
'qrcode', 'invite_auto_add', 'recommendation'
),
'message', '当前时段暂不允许添加好友'
),
0, '系统初始化:保持原有好友和消息行为', CURRENT_TIMESTAMP(3), 0, 0, 0
WHERE NOT EXISTS (
SELECT 1 FROM `im_security_policy`
WHERE `tenant_id` = 0 AND `publish_status` = 'published' AND `deleted_at` IS NULL
);
UPDATE `im_security_policy`
SET `friend_disabled_policy` = JSON_SET(
`friend_disabled_policy`,
'$.blocked_entries',
JSON_ARRAY('search', 'profile_card', 'group_member', 'qrcode', 'invite_auto_add', 'recommendation')
)
WHERE `tenant_id` = 0
AND `publish_status` = 'published'
AND `deleted_at` IS NULL
AND JSON_CONTAINS_PATH(`friend_disabled_policy`, 'one', '$.blocked_entries') = 0;
-- Post-deployment checks (read-only):
-- SELECT tenant_id, group_code, status, priority FROM im_user_policy_groups;
-- SELECT tenant_id, policy_version, publish_status,
-- global_friend_enabled, message_curfew_enabled
-- FROM im_security_policy ORDER BY tenant_id, policy_version DESC;
-- SELECT tenant_id, policy_id, rule_code, date_type, start_time, end_time, scope
-- FROM im_message_curfew_rules WHERE deleted_at IS NULL;
@@ -0,0 +1,464 @@
-- IM Server schema changes for the GedaDa management-console adaptation.
-- Target: MySQL 8.0+, one independent tenant business database.
-- Default local tenant database: `tinode`.
-- IMPORTANT: execute this migration once for every tenant database. Tenant
-- business tables intentionally do not contain tenant_id.
-- Review before execution. DDL statements auto-commit in MySQL.
SET NAMES utf8mb4;
USE `tinode`;
-- ============================================================
-- 0. User account number.
-- account_no is the short user number shown in Admin. The real primary key
-- im_users.id remains the internal Tinode/Snowflake user ID.
-- Existing users are backfilled from 1000 by created time; new users are
-- assigned by IM Server in the user creation transaction.
-- ============================================================
SET @sql := IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_users' AND COLUMN_NAME = 'account_no') = 0,
'ALTER TABLE `im_users` ADD COLUMN `account_no` int unsigned NOT NULL DEFAULT 0 COMMENT ''用户编号'' AFTER `id`',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @im_user_account_no := (
SELECT GREATEST(COALESCE(MAX(`account_no`), 999), 999)
FROM `im_users`
WHERE `account_no` > 0
);
UPDATE `im_users` AS u
JOIN (
SELECT ordered.`id`, (@im_user_account_no := @im_user_account_no + 1) AS next_no
FROM (
SELECT `id`
FROM `im_users`
WHERE `account_no` = 0
ORDER BY `createdat`, `id`
) AS ordered
) AS seq ON seq.`id` = u.`id`
SET u.`account_no` = seq.next_no
WHERE u.`account_no` = 0;
SET @sql := IF(
(SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_users' AND INDEX_NAME = 'uk_im_users_account_no') = 0,
'CREATE UNIQUE INDEX `uk_im_users_account_no` ON `im_users` (`account_no`)',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ============================================================
-- 1. Applied runtime policy snapshots.
-- policy_type: security, user_policy_groups, sensitive_words.
-- The application uses the latest row with apply_status=applied and also keeps
-- an in-memory cache. This table makes restart and Kafka replay deterministic.
-- ============================================================
CREATE TABLE IF NOT EXISTS `im_runtime_policy_snapshots` (
`id` bigint NOT NULL AUTO_INCREMENT,
`policy_type` varchar(32) NOT NULL,
`policy_version` bigint unsigned NOT NULL,
`payload` json NOT NULL,
`payload_sha256` char(64) NOT NULL,
`source_event_id` varchar(96) DEFAULT NULL COMMENT 'NULL for a manual bootstrap snapshot',
`apply_status` varchar(16) NOT NULL DEFAULT 'applied' COMMENT 'applied or failed',
`apply_error` varchar(1000) NOT NULL DEFAULT '',
`applied_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_runtime_policy_version` (`policy_type`, `policy_version`),
UNIQUE KEY `uk_im_runtime_policy_event` (`source_event_id`),
KEY `idx_im_runtime_policy_latest` (`policy_type`, `apply_status`, `policy_version` DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Last applied Admin policy payloads';
-- ============================================================
-- 2. User login history and login failure history.
-- Never store plaintext passwords, verification codes, access tokens or refresh
-- tokens. account_hash is SHA-256 of the normalized login account; account_mask
-- is the value shown in Admin.
-- login_type: password, sms_code, sso, qr_code, token_refresh.
-- event_type: login, refresh, logout, kicked, session_expired.
-- failure_type: password_error, code_error, account_not_found,
-- account_disabled, rate_limited, risk_blocked.
-- ============================================================
CREATE TABLE IF NOT EXISTS `im_user_login_logs` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`username` varchar(64) NOT NULL DEFAULT '',
`account_type` varchar(24) NOT NULL DEFAULT '',
`account_hash` char(64) NOT NULL DEFAULT '',
`account_mask` varchar(128) NOT NULL DEFAULT '',
`login_type` varchar(24) NOT NULL,
`event_type` varchar(24) NOT NULL DEFAULT 'login',
`session_id` varchar(96) NOT NULL DEFAULT '' COMMENT 'Opaque session identifier, never an auth token',
`device_id` varchar(255) NOT NULL DEFAULT '',
`platform` varchar(32) NOT NULL DEFAULT 'unknown',
`app_version` varchar(32) NOT NULL DEFAULT '',
`ip` varchar(64) NOT NULL DEFAULT '',
`region` varchar(128) NOT NULL DEFAULT '',
`user_agent` varchar(512) NOT NULL DEFAULT '',
`risk_level` varchar(16) NOT NULL DEFAULT 'low',
`request_id` varchar(64) NOT NULL DEFAULT '',
`login_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`logout_at` datetime(3) DEFAULT NULL,
`metadata` json DEFAULT NULL,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
KEY `idx_im_user_login_user_time` (`user_id`, `login_at` DESC, `id` DESC),
KEY `idx_im_user_login_ip_time` (`ip`, `login_at` DESC, `id` DESC),
KEY `idx_im_user_login_device_time` (`device_id`(64), `login_at` DESC),
KEY `idx_im_user_login_request` (`request_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='User login and session event history';
CREATE TABLE IF NOT EXISTS `im_login_failure_logs` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint DEFAULT NULL COMMENT 'NULL when the account cannot be resolved',
`account_type` varchar(24) NOT NULL DEFAULT '',
`account_hash` char(64) NOT NULL DEFAULT '',
`account_mask` varchar(128) NOT NULL DEFAULT '',
`failure_type` varchar(32) NOT NULL,
`reason` varchar(96) NOT NULL DEFAULT '' COMMENT 'Stable backend reason code',
`detail` varchar(500) NOT NULL DEFAULT '' COMMENT 'Sanitized detail without credentials',
`ip` varchar(64) NOT NULL DEFAULT '',
`region` varchar(128) NOT NULL DEFAULT '',
`device_id` varchar(255) NOT NULL DEFAULT '',
`platform` varchar(32) NOT NULL DEFAULT 'unknown',
`app_version` varchar(32) NOT NULL DEFAULT '',
`user_agent` varchar(512) NOT NULL DEFAULT '',
`risk_level` varchar(16) NOT NULL DEFAULT 'medium',
`risk_action` varchar(24) NOT NULL DEFAULT 'audit_only',
`request_id` varchar(64) NOT NULL DEFAULT '',
`attempt_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`metadata` json DEFAULT NULL,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
KEY `idx_im_login_failure_account_time` (`account_hash`, `attempt_at` DESC, `id` DESC),
KEY `idx_im_login_failure_user_time` (`user_id`, `attempt_at` DESC, `id` DESC),
KEY `idx_im_login_failure_ip_time` (`ip`, `attempt_at` DESC, `id` DESC),
KEY `idx_im_login_failure_type_time` (`failure_type`, `attempt_at` DESC, `id` DESC),
KEY `idx_im_login_failure_request` (`request_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Authentication failure and risk-block history';
-- ============================================================
-- 3. Message administration actions.
-- Messages remain in im_messages/im_group_messages. This table is an immutable
-- action overlay so hide/delete can be audited and restored.
-- conversation_type: private, group.
-- action: hide, unhide, delete, restore.
-- action_status: pending, success, failed, dead.
-- ============================================================
CREATE TABLE IF NOT EXISTS `im_message_admin_actions` (
`id` bigint NOT NULL AUTO_INCREMENT,
`action_id` varchar(96) NOT NULL,
`command_id` varchar(96) NOT NULL,
`conversation_type` varchar(16) NOT NULL,
`topic` varchar(64) NOT NULL,
`seqid` bigint NOT NULL,
`sender_user_id` bigint DEFAULT NULL,
`action` varchar(16) NOT NULL,
`action_status` varchar(16) NOT NULL DEFAULT 'pending',
`reason` varchar(500) NOT NULL DEFAULT '',
`actor_admin_id` bigint NOT NULL DEFAULT 0,
`request_id` varchar(64) NOT NULL DEFAULT '',
`before_snapshot` json DEFAULT NULL,
`after_snapshot` json DEFAULT NULL,
`failure_reason` varchar(96) NOT NULL DEFAULT '',
`failure_message` varchar(1000) NOT NULL DEFAULT '',
`processed_at` datetime(3) DEFAULT NULL,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_message_admin_action_id` (`action_id`),
UNIQUE KEY `uk_im_message_admin_command` (`command_id`),
KEY `idx_im_message_admin_target` (`conversation_type`, `topic`, `seqid`, `id` DESC),
KEY `idx_im_message_admin_status` (`action_status`, `created_at`, `id`),
KEY `idx_im_message_admin_actor` (`actor_admin_id`, `created_at` DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Auditable Admin message actions';
-- ============================================================
-- 4. Sensitive-word hits and policy decisions.
-- Store only a digest and a short masked excerpt. Do not duplicate complete
-- private messages in log tables.
-- policy decision reasons include FRIEND_DISABLED and MESSAGE_CURFEW_ACTIVE.
-- ============================================================
CREATE TABLE IF NOT EXISTS `im_sensitive_word_hits` (
`id` bigint NOT NULL AUTO_INCREMENT,
`word_id` bigint NOT NULL DEFAULT 0 COMMENT 'Admin control-database word ID',
`word_group_id` bigint NOT NULL DEFAULT 0,
`word_snapshot` varchar(255) NOT NULL DEFAULT '' COMMENT 'Masked word snapshot',
`scene` varchar(32) NOT NULL,
`user_id` bigint NOT NULL DEFAULT 0,
`target_user_id` bigint DEFAULT NULL,
`topic` varchar(64) NOT NULL DEFAULT '',
`seqid` bigint DEFAULT NULL,
`content_sha256` char(64) NOT NULL DEFAULT '',
`matched_excerpt` varchar(500) NOT NULL DEFAULT '',
`match_type` varchar(24) NOT NULL DEFAULT 'contains',
`action` varchar(24) NOT NULL,
`risk_level` varchar(16) NOT NULL DEFAULT 'medium',
`request_id` varchar(64) NOT NULL DEFAULT '',
`metadata` json DEFAULT NULL,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
KEY `idx_im_sensitive_hit_scene_time` (`scene`, `created_at` DESC, `id` DESC),
KEY `idx_im_sensitive_hit_user_time` (`user_id`, `created_at` DESC, `id` DESC),
KEY `idx_im_sensitive_hit_target` (`topic`, `seqid`, `id` DESC),
KEY `idx_im_sensitive_hit_word` (`word_id`, `created_at` DESC),
KEY `idx_im_sensitive_hit_request` (`request_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Sensitive-word match events';
CREATE TABLE IF NOT EXISTS `im_policy_decision_logs` (
`id` bigint NOT NULL AUTO_INCREMENT,
`policy_type` varchar(32) NOT NULL COMMENT 'security or user_policy_group',
`policy_version` bigint unsigned NOT NULL DEFAULT 0,
`policy_group_id` bigint NOT NULL DEFAULT 0,
`scene` varchar(64) NOT NULL COMMENT 'friend_request, qrcode_resolve, private_message and so on',
`action` varchar(24) NOT NULL COMMENT 'deny, challenge or audit_only',
`reason_code` varchar(96) NOT NULL COMMENT 'For example FRIEND_DISABLED or MESSAGE_CURFEW_ACTIVE',
`user_id` bigint NOT NULL DEFAULT 0,
`target_user_id` bigint DEFAULT NULL,
`topic` varchar(64) NOT NULL DEFAULT '',
`request_id` varchar(64) NOT NULL DEFAULT '',
`ip` varchar(64) NOT NULL DEFAULT '',
`metadata` json DEFAULT NULL,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
KEY `idx_im_policy_decision_user_time` (`user_id`, `created_at` DESC, `id` DESC),
KEY `idx_im_policy_decision_reason_time` (`reason_code`, `created_at` DESC, `id` DESC),
KEY `idx_im_policy_decision_scene_time` (`scene`, `created_at` DESC, `id` DESC),
KEY `idx_im_policy_decision_request` (`request_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Runtime policy deny/challenge decisions';
-- ============================================================
-- 5. Group event history and daily IP/account statistics.
-- im_group_events_outbox remains the delivery table; this log is the queryable
-- business history after the operation result is known.
-- ============================================================
CREATE TABLE IF NOT EXISTS `im_group_event_logs` (
`id` bigint NOT NULL AUTO_INCREMENT,
`event_id` varchar(96) NOT NULL,
`topic` varchar(64) NOT NULL,
`group_id` bigint DEFAULT NULL,
`event_type` varchar(64) NOT NULL,
`actor_user_id` bigint NOT NULL DEFAULT 0,
`target_user_id` bigint DEFAULT NULL,
`result` varchar(16) NOT NULL DEFAULT 'success',
`reason` varchar(500) NOT NULL DEFAULT '',
`request_id` varchar(64) NOT NULL DEFAULT '',
`before_snapshot` json DEFAULT NULL,
`after_snapshot` json DEFAULT NULL,
`metadata` json DEFAULT NULL,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_group_event_log_event` (`event_id`),
KEY `idx_im_group_event_topic_time` (`topic`, `created_at` DESC, `id` DESC),
KEY `idx_im_group_event_type_time` (`event_type`, `created_at` DESC, `id` DESC),
KEY `idx_im_group_event_actor_time` (`actor_user_id`, `created_at` DESC, `id` DESC),
KEY `idx_im_group_event_request` (`request_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Queryable group event audit history';
CREATE TABLE IF NOT EXISTS `im_ip_account_stats_daily` (
`id` bigint NOT NULL AUTO_INCREMENT,
`stat_date` date NOT NULL,
`ip` varchar(64) NOT NULL,
`region` varchar(128) NOT NULL DEFAULT '',
`account_count` int unsigned NOT NULL DEFAULT 0,
`user_count` int unsigned NOT NULL DEFAULT 0,
`login_success_count` int unsigned NOT NULL DEFAULT 0,
`login_failure_count` int unsigned NOT NULL DEFAULT 0,
`first_seen_at` datetime(3) DEFAULT NULL,
`last_seen_at` datetime(3) DEFAULT NULL,
`risk_level` varchar(16) NOT NULL DEFAULT 'low',
`risk_action` varchar(24) NOT NULL DEFAULT 'audit_only',
`sample_user_ids` json DEFAULT NULL COMMENT 'Bounded sample only, not an unlimited array',
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_ip_account_stats_day_ip` (`stat_date`, `ip`),
KEY `idx_im_ip_account_stats_ip_day` (`ip`, `stat_date` DESC),
KEY `idx_im_ip_account_stats_risk_day` (`risk_level`, `stat_date` DESC, `id` DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Daily IP and account aggregation';
-- ============================================================
-- 6. Compatible enhancements to existing tables.
-- Every ALTER is guarded by information_schema and can be rerun.
-- ============================================================
-- Message management queries need topic/time and sender/time indexes.
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_messages'
AND INDEX_NAME = 'idx_im_messages_topic_created') = 0,
'ALTER TABLE `im_messages` ADD INDEX `idx_im_messages_topic_created` (`topic`, `createdat`, `id`)',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_messages'
AND INDEX_NAME = 'idx_im_messages_from_created') = 0,
'ALTER TABLE `im_messages` ADD INDEX `idx_im_messages_from_created` (`from`, `createdat`, `id`)',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
-- Extend the existing Tinode device record for device and login-history views.
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_devices'
AND COLUMN_NAME = 'firstseen') = 0,
'ALTER TABLE `im_devices` ADD COLUMN `firstseen` DATETIME(3) DEFAULT NULL AFTER `platform`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_devices'
AND COLUMN_NAME = 'lastip') = 0,
'ALTER TABLE `im_devices` ADD COLUMN `lastip` VARCHAR(64) NOT NULL DEFAULT '''' AFTER `lastseen`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_devices'
AND COLUMN_NAME = 'useragent') = 0,
'ALTER TABLE `im_devices` ADD COLUMN `useragent` VARCHAR(512) NOT NULL DEFAULT '''' AFTER `lastip`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_devices'
AND COLUMN_NAME = 'appversion') = 0,
'ALTER TABLE `im_devices` ADD COLUMN `appversion` VARCHAR(32) NOT NULL DEFAULT '''' AFTER `useragent`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_devices'
AND COLUMN_NAME = 'status') = 0,
'ALTER TABLE `im_devices` ADD COLUMN `status` VARCHAR(16) NOT NULL DEFAULT ''active'' AFTER `appversion`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
-- Feedback handling fields required by the Admin processing workflow.
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_feedback_submissions'
AND COLUMN_NAME = 'assigned_to') = 0,
'ALTER TABLE `im_feedback_submissions` ADD COLUMN `assigned_to` BIGINT DEFAULT NULL AFTER `status`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_feedback_submissions'
AND COLUMN_NAME = 'handled_by') = 0,
'ALTER TABLE `im_feedback_submissions` ADD COLUMN `handled_by` BIGINT DEFAULT NULL AFTER `assigned_to`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_feedback_submissions'
AND COLUMN_NAME = 'handled_at') = 0,
'ALTER TABLE `im_feedback_submissions` ADD COLUMN `handled_at` DATETIME(3) DEFAULT NULL AFTER `handled_by`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_feedback_submissions'
AND COLUMN_NAME = 'resolution') = 0,
'ALTER TABLE `im_feedback_submissions` ADD COLUMN `resolution` VARCHAR(1000) NOT NULL DEFAULT '''' AFTER `handled_at`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_feedback_submissions'
AND COLUMN_NAME = 'admin_remark') = 0,
'ALTER TABLE `im_feedback_submissions` ADD COLUMN `admin_remark` VARCHAR(1000) NOT NULL DEFAULT '''' AFTER `resolution`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_feedback_submissions'
AND INDEX_NAME = 'idx_im_feedback_status_time') = 0,
'ALTER TABLE `im_feedback_submissions` ADD INDEX `idx_im_feedback_status_time` (`status`, `created_at`, `id`)',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_audit_logs'
AND INDEX_NAME = 'idx_im_audit_logs_ip_time') = 0,
'ALTER TABLE `im_audit_logs` ADD INDEX `idx_im_audit_logs_ip_time` (`ip`, `created_at`, `id`)',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
-- Post-deployment checks (read-only):
-- SELECT policy_type, policy_version, apply_status, applied_at
-- FROM im_runtime_policy_snapshots ORDER BY policy_type, policy_version DESC;
-- SELECT reason_code, scene, COUNT(*) AS deny_count
-- FROM im_policy_decision_logs
-- WHERE created_at >= CURRENT_DATE
-- GROUP BY reason_code, scene;
-- SELECT stat_date, ip, account_count, login_failure_count, risk_level
-- FROM im_ip_account_stats_daily ORDER BY stat_date DESC, login_failure_count DESC;
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More