GoWind 开源生态GoWind 开源生态
首页
框架
GoWind Admin
GoWind CMS
GoWind IM
GoWind UBA
GoWind IoT
GoWind Toolkit
GoWind Quant
GitHub
首页
框架
GoWind Admin
GoWind CMS
GoWind IM
GoWind UBA
GoWind IoT
GoWind Toolkit
GoWind Quant
GitHub
  • 介绍

    • GoWind UBA 产品介绍
  • 架构参考

    • UBA 系统架构
    • UBA 后端模块总览
    • UBA 后端 API 契约
    • UBA 前端架构
  • 开发者指南(二开)

    • UBA 安装指南
    • UBA 代码生成管线教程
    • 新增对外服务教程
    • 新增业务实体教程
    • 新增前端页面教程
  • 运维指南

    • UBA Docker 部署指南
    • UBA 配置详解与安全清单
    • UBA PM2 部署指南
    • UBA Superset BI 部署指南
  • 数据分析师指南

    • 数据分析师上手指南
    • 基础聚合

      • 事件趋势分析
      • 活跃用户分析
      • 维度分组聚合
    • 转化与路径

      • 漏斗分析
      • 留存分析
      • 热门转化路径
      • 行为序列分析
    • 用户深度

      • 归因分析
      • 分布分析
      • 用户分群圈选
      • 点击热力图
      • 间隔时间分析
    • 生命周期

      • 用户生命周期
      • 流失与回流分析
      • 新老用户对比
      • 矩阵象限分析
    • 营收与价值

      • 营收分析
      • 付费分层(鲸鱼分析)
      • 历史 LTV 分析
    • 会话与异常

      • 会话分析
      • 同比环比与异常检测
    • 游戏专属

      • 关卡分析(游戏)
      • 滚服留存(游戏)
      • 同时在线分析(游戏)
      • 经济系统分析(游戏)
    • OLAP 查询手册
  • SDK 接入

    • Web SDK 接入指南
    • C# SDK 接入指南(Unity / Godot / .NET)
  • 附录

    • UBA 附录:端口、术语、已知限制与 FAQ

新增业务实体教程

本教程演示如何在 UBA 后端新增一个 PostgreSQL 业务实体(Ent schema → 生成 → proto → repo → service),以项目内已实现的 EventSchema(事件 Schema) 为参照。

前置:先读 代码生成管线(尤其是「Ent 生成的坑」)与 新增对外服务。


一、适用场景

  • 需要持久化到 PostgreSQL 的业务实体(如新的配置项、业务表)。
  • 需要完整 CRUD(List/Count/Get/Create/Update/Delete)。

⚠️ 如果是分析数据(事实表、聚合查询),应走 OLAP 而非 Ent,见 新增对外服务 的 OLAP repo 部分。


二、步骤

步骤 1:定义 Ent schema

文件:backend/app/core/service/internal/data/ent/schema/uba_xxx.go

package schema

import (
    "entgo.io/ent"
    "entgo.io/ent/schema"
    "entgo.io/ent/schema/field"
    "entgo.io/ent/schema/index"
    "entgo.io/ent/schema/mixin"
    entsql "entgo.io/ent/dialect/entsql"
)

type Xxx struct{ ent.Schema }

func (Xxx) Fields() []ent.Field {
    return []ent.Field{
        field.String("name").NotEmpty().Comment("名称"),
        field.String("code").Unique().Comment("编码"),
        // 注意 Nillable / Optional / Default 的取舍
    }
}

func (Xxx) Mixin() []schema.Mixin {
    return []schema.Mixin{
        mixin.AutoIncrementId{},   // 自增主键
        mixin.TimeAt{},            // created_at / updated_at
        mixin.OperatorID{},        // 操作人
        mixin.TenantID[uint32]{},  // 多租户
    }
}

func (Xxx) Indexes() []ent.Index {
    return []ent.Index{
        index.Fields("code").Unique(),
        index.Fields("tenant_id", "name"),
    }
}

func (Xxx) Annotations() []schema.Annotation {
    return []schema.Annotation{
        entsql.Annotation{Table: "uba_xxx", Charset: "utf8mb4"},
    }
}

要点:

  • Fields():注意 Nillable / Optional / Default 的取舍。
  • Mixin():复用项目提供的 mixin.AutoIncrementId{} / mixin.TimeAt{} / mixin.OperatorID{} / mixin.TenantID[T]{}。
  • Indexes():唯一索引 + 普通索引。
  • Annotations():表名(uba_ 前缀)、字符集。

步骤 2:生成 Ent 代码(用正确命令)

⚠️ 必须带 feature flags,否则会丢扩展、编译报错。

cd backend/app/core/service
ent generate \
  --feature privacy --feature entql \
  --feature sql/modifier --feature sql/upsert --feature sql/lock \
  ./internal/data/ent/schema

或直接 make ent(在 core/service 目录)。

步骤 3:定义 proto

领域 proto(api/protos/uba/service/v1/xxx.proto,含完整 CRUD 消息)+ admin 网关 proto(api/protos/admin/service/v1/i_xxx.proto,每个 rpc 加 google.api.http 注解)。

参考 event_schema.proto / i_event_schema.proto 的 CRUD 套路:

service XxxService {
  rpc List(google.protobuf.PagingRequest) returns (ListXxxResponse) {}
  rpc Count(...) returns (...);
  rpc Get(GetXxxRequest) returns (Xxx) {}
  rpc Create(Xxx) returns (google.protobuf.Empty) {}
  rpc Update(Xxx) returns (google.protobuf.Empty) {}   // 带 FieldMask
  rpc Delete(DeleteXxxRequest) returns (google.protobuf.Empty) {}
}

步骤 4:生成 proto 代码

cd backend && make api && make ts
# 同步 TS(见代码生成管线教程第五节)

步骤 5:实现 repo

文件:backend/app/core/service/internal/data/uba_xxx_repo.go

  • 仿 uba_tag_definition_repo.go / uba_event_schema_repo.go。
  • 用 entCrud.Repository[...] 泛型 + mapper.CopierMapper。
  • Count / List 用 BuildListSelectorWithPaging。
  • ID 类型注意:Ent 默认 uint32,proto 用 uint64,需 uint32(req.GetId()) 转换。
type XxxRepo struct {
    *entCrud.Repository[ent.Xxx, ent.XxxCreate, ent.XxxUpdate, ubaV1.Xxx, *ubaV1.Xxx]
}

func NewXxxRepo(data *Data, auth authorization.Casbin) *XxxRepo {
    r := entCrud.NewRepository[ent.Xxx, ent.XxxCreate, ent.XxxUpdate, ubaV1.Xxx, *ubaV1.Xxx](
        data.GetEntTx(), mapper.NewCopierMapper[ubaV1.Xxx, ent.Xxx](),
    )
    return &XxxRepo{Repository: r}
}

步骤 6:实现 core service + admin 转发

同 新增对外服务 的步骤 4–5:

  • core:internal/service/xxx_service.go 实现 ubaV1.UnimplementedXxxServiceServer,调用 repo。
  • admin:internal/service/xxx_service.go 转发实现。
  • 两层各自注册 Provider、server 注册,并 make wire。

步骤 7:验证

cd backend && go build ./...

三、表结构说明

  • 没有手写 schema.sql:表结构由 make ent 生成;core 服务启动时 data.yaml 的 migrate: true 会自动建表。
  • 种子数据:若有字典数据,放到 sql/postgresql/default-data.sql(参考已有的 sys_dict_types / sys_dict_entries)。

四、常见坑

  • Ent 编译报 Modify 缺失:用了错误的 ent 生成命令(没带 feature flags,见步骤 2)。
  • ID 类型不匹配:Ent uint32 ↔ proto uint64,记得转换。
  • 多租户字段漏填:实体未加 mixin.TenantID,导致租户隔离失效。
  • FieldMask 更新失效:admin 前端更新时需用 makeUpdateMask(Object.keys(values)) 生成掩码(见前端 composable 范式)。

五、相关文档

  • 代码生成管线
  • 新增对外服务
  • 后端模块总览
  • 前端架构
Edit this page
Last Updated:: 6/29/26, 12:03 AM
Contributors: Bobo
Prev
新增对外服务教程
Next
新增前端页面教程