Version: 0.9.80.dev.260506

后端:
1. LLM 独立服务与统一计费出口落地:新增 `cmd/llm`、`client/llm` 与 `services/llm/rpc`,补齐 BillingContext、CreditBalanceGuard、价格规则解析、stream usage 归集与 `credit.charge.requested` outbox 发布,active-scheduler / agent / course / memory / gateway fallback 全部改走 llm zrpc,不再各自本地初始化模型。
2. TokenStore 收口为 Credit 权威账本:新增 credit account / ledger / product / order / price-rule / reward-rule 能力与 Redis 快照缓存,扩展 tokenstore rpc/client 支撑余额快照、消耗看板、商品、订单、流水、价格规则和奖励规则,并接入 LLM charge 事件消费完成 Credit 扣费落账。
3. 计费旧链路下线与网关切口切换:`/token-store` 语义整体切到 `/credit-store`,agent chat 移除旧 TokenQuotaGuard,userauth 的 CheckTokenQuota / AdjustTokenUsage 改为废弃,聊天历史落库不再同步旧 token 额度账本,course 图片解析请求补 user_id 进入新计费口径。

前端:
4. 计划广场从 mock 数据切到真实接口:新增 forum api/types,首页支持真实列表、标签、搜索、防抖、点赞、导入和发布计划,详情页补齐帖子详情、评论树、回复和删除评论链路,同时补上“至少一个标签”的前后端约束与默认标签兜底。
5. 商店页切到 Credit 体系并重做展示:顶部改为余额 + Credit/Token 消耗看板,支持 24h/7d/30d/all 周期切换;套餐区展示原价与当前价;历史区改为当前用户 Credit 流水并支持查看更多,整体视觉和交互同步收口。

仓库:
6. 配置与本地启动体系补齐 llm / outbox 编排:`config.example.yaml` 增加 llm rpc 和统一 outbox service 配置,`dev-common.ps1` 把 llm 纳入多服务依赖并自动建 Kafka topic,`docker-compose.yml` 同步初始化 agent/task/memory/active-scheduler/notification/taskclass-forum/llm/token-store 全量 outbox topic。
This commit is contained in:
Losita
2026-05-06 20:16:53 +08:00
parent 7d324b77aa
commit 61db646805
104 changed files with 9527 additions and 3925 deletions

View File

@@ -0,0 +1,206 @@
package model
import "time"
const (
// CreditProductStatusActive 表示商品可在 Credit 商店展示和购买。
CreditProductStatusActive = "active"
// CreditProductStatusInactive 表示商品已下架。
CreditProductStatusInactive = "inactive"
)
const (
// CreditOrderStatusPending 表示订单已创建,等待支付确认。
CreditOrderStatusPending = "pending"
// CreditOrderStatusPaid 表示订单已确认支付,等待入账。
CreditOrderStatusPaid = "paid"
// CreditOrderStatusCredited 表示订单对应的 Credit 已经写入账本。
CreditOrderStatusCredited = "credited"
// CreditOrderStatusClosed 表示订单已关闭。
CreditOrderStatusClosed = "closed"
)
const (
// CreditLedgerDirectionIncome 表示正向入账。
CreditLedgerDirectionIncome = "income"
// CreditLedgerDirectionExpense 表示扣费出账。
CreditLedgerDirectionExpense = "expense"
)
const (
// CreditLedgerStatusApplied 表示该笔流水已经成为权威账本事实。
CreditLedgerStatusApplied = "applied"
// CreditLedgerStatusSkipped 表示事件被消费但不影响余额。
CreditLedgerStatusSkipped = "skipped"
// CreditLedgerStatusFailed 预留给后续补偿或人工处理。
CreditLedgerStatusFailed = "failed"
)
const (
// CreditLedgerSourcePurchase 表示用户购买 Credit 商品。
CreditLedgerSourcePurchase = "purchase"
// CreditLedgerSourceCharge 表示 LLM 调用扣费。
CreditLedgerSourceCharge = "charge"
// CreditLedgerSourceForumLike 预留论坛点赞奖励。
CreditLedgerSourceForumLike = "forum_like"
// CreditLedgerSourceForumImport 预留论坛导入奖励。
CreditLedgerSourceForumImport = "forum_import"
// CreditLedgerSourceManual 预留人工补偿。
CreditLedgerSourceManual = "manual"
)
const (
// CreditPriceRuleStatusActive 表示价格规则启用。
CreditPriceRuleStatusActive = "active"
// CreditPriceRuleStatusInactive 表示价格规则停用。
CreditPriceRuleStatusInactive = "inactive"
)
const (
// CreditRewardRuleStatusActive 表示奖励规则启用。
CreditRewardRuleStatusActive = "active"
// CreditRewardRuleStatusInactive 表示奖励规则停用。
CreditRewardRuleStatusInactive = "inactive"
)
// CreditAccount 是 Credit 权威余额表。
//
// 职责边界:
// 1. 只保存用户在 TokenStore 账本口径下的当前余额与累计统计;
// 2. balance 允许被异步结算扣到 0 以下,后续由 Guard 和充值链路阻断新增调用;
// 3. 不保存逐笔明细,逐笔事实统一以 credit_ledger 为准。
type CreditAccount struct {
ID uint64 `gorm:"column:id;primaryKey;autoIncrement"`
UserID uint64 `gorm:"column:user_id;not null;uniqueIndex:uk_credit_accounts_user;comment:用户ID"`
Balance int64 `gorm:"column:balance;not null;default:0;comment:当前Credit余额"`
TotalRecharged int64 `gorm:"column:total_recharged;not null;default:0;comment:累计购买入账"`
TotalRewarded int64 `gorm:"column:total_rewarded;not null;default:0;comment:累计奖励入账"`
TotalConsumed int64 `gorm:"column:total_consumed;not null;default:0;comment:累计扣费出账"`
LastLedgerEventID string `gorm:"column:last_ledger_event_id;type:varchar(128);comment:最近一次账本事件ID"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;comment:创建时间"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;comment:更新时间"`
}
func (CreditAccount) TableName() string {
return "credit_accounts"
}
// CreditLedger 是 Credit 权威流水表。
//
// 职责边界:
// 1. event_id 是最终幂等键,所有异步扣费、充值、奖励都依赖它去重;
// 2. amount 使用带符号值正数表示入账负数表示扣费0 表示消费成功但不影响余额;
// 3. balance_before / balance_after 记录事件落账时的权威余额快照。
type CreditLedger struct {
ID uint64 `gorm:"column:id;primaryKey;autoIncrement"`
EventID string `gorm:"column:event_id;type:varchar(128);not null;uniqueIndex:uk_credit_ledger_event;comment:最终幂等事件ID"`
UserID uint64 `gorm:"column:user_id;not null;index:idx_credit_ledger_user_created,priority:1;comment:用户ID"`
Source string `gorm:"column:source;type:varchar(32);not null;index:idx_credit_ledger_user_created,priority:2;comment:purchase/charge/forum_like/forum_import/manual"`
SourceLabel string `gorm:"column:source_label;type:varchar(64);comment:来源展示文案"`
Direction string `gorm:"column:direction;type:varchar(16);not null;comment:income/expense"`
OrderID *uint64 `gorm:"column:order_id;index:idx_credit_ledger_order;comment:关联订单ID"`
SourceRefID *string `gorm:"column:source_ref_id;type:varchar(128);index:idx_credit_ledger_source_ref;comment:来源业务ID"`
Amount int64 `gorm:"column:amount;not null;comment:本次Credit变动正数入账负数扣费"`
BalanceBefore int64 `gorm:"column:balance_before;not null;default:0;comment:落账前余额"`
BalanceAfter int64 `gorm:"column:balance_after;not null;default:0;comment:落账后余额"`
Status string `gorm:"column:status;type:varchar(32);not null;default:'applied';index:idx_credit_ledger_status;comment:applied/skipped/failed"`
Description string `gorm:"column:description;type:varchar(255);comment:展示描述"`
MetadataJSON string `gorm:"column:metadata_json;type:json;comment:扩展元数据"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;index:idx_credit_ledger_user_created,priority:3;comment:创建时间"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;comment:更新时间"`
}
func (CreditLedger) TableName() string {
return "credit_ledger"
}
// CreditProduct 是 Credit 商店商品表。
type CreditProduct struct {
ID uint64 `gorm:"column:id;primaryKey;autoIncrement"`
SKU string `gorm:"column:sku;type:varchar(64);not null;uniqueIndex:uk_credit_products_sku;comment:商品稳定编码"`
Name string `gorm:"column:name;type:varchar(80);not null;comment:商品名称"`
Description string `gorm:"column:description;type:varchar(255);comment:商品描述"`
CreditAmount int64 `gorm:"column:credit_amount;not null;comment:包含Credit数量"`
PriceCent int64 `gorm:"column:price_cent;not null;comment:价格,单位分"`
OriginalPriceCent int64 `gorm:"column:original_price_cent;not null;default:0;comment:优惠前价格,单位分"`
Currency string `gorm:"column:currency;type:varchar(16);not null;default:'CNY';comment:币种"`
Badge string `gorm:"column:badge;type:varchar(32);comment:角标"`
Status string `gorm:"column:status;type:varchar(32);not null;default:'active';index:idx_credit_products_status_sort,priority:1;comment:active/inactive"`
SortOrder int `gorm:"column:sort_order;not null;default:0;index:idx_credit_products_status_sort,priority:2;comment:展示排序"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;comment:创建时间"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;comment:更新时间"`
}
func (CreditProduct) TableName() string {
return "credit_products"
}
// CreditOrder 是 Credit 商品订单表。
type CreditOrder struct {
ID uint64 `gorm:"column:id;primaryKey;autoIncrement"`
OrderNo string `gorm:"column:order_no;type:varchar(64);not null;uniqueIndex:uk_credit_orders_order_no;comment:订单号"`
UserID uint64 `gorm:"column:user_id;not null;uniqueIndex:uk_credit_orders_user_idem,priority:1;index:idx_credit_orders_user_status_created,priority:1;comment:下单用户ID"`
ProductID uint64 `gorm:"column:product_id;not null;index:idx_credit_orders_product;comment:商品ID"`
ProductSKU string `gorm:"column:product_sku;type:varchar(64);not null;comment:商品SKU快照"`
ProductName string `gorm:"column:product_name;type:varchar(80);not null;comment:商品名称快照"`
ProductSnapshotJSON string `gorm:"column:product_snapshot_json;type:json;not null;comment:商品完整快照JSON"`
Quantity int `gorm:"column:quantity;not null;default:1;comment:购买数量"`
CreditAmount int64 `gorm:"column:credit_amount;not null;comment:订单总Credit数量"`
AmountCent int64 `gorm:"column:amount_cent;not null;comment:订单总金额,单位分"`
Currency string `gorm:"column:currency;type:varchar(16);not null;default:'CNY';comment:币种"`
Status string `gorm:"column:status;type:varchar(32);not null;default:'pending';index:idx_credit_orders_user_status_created,priority:2;comment:pending/paid/credited/closed"`
PaymentMode string `gorm:"column:payment_mode;type:varchar(32);not null;default:'mock';comment:支付模式"`
IdempotencyKey *string `gorm:"column:idempotency_key;type:varchar(128);uniqueIndex:uk_credit_orders_user_idem,priority:2;comment:创建订单幂等键"`
PaidAt *time.Time `gorm:"column:paid_at;comment:支付确认时间"`
CreditedAt *time.Time `gorm:"column:credited_at;comment:入账时间"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;index:idx_credit_orders_user_status_created,priority:3;comment:创建时间"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;comment:更新时间"`
}
func (CreditOrder) TableName() string {
return "credit_orders"
}
// CreditPriceRule 是 LLM Credit 计价规则表。
//
// 职责边界:
// 1. 该表表达“某个 provider/model 在某场景下如何换算人民币与 Credit”的运营配置
// 2. 第二步先完成表结构与读取能力,具体由 LLM 服务如何引用放到后续切流阶段;
// 3. 当前结算事件已带出最终 rmb_cost_micros 与 credit_cost因此消费侧不在这里二次计算。
type CreditPriceRule struct {
ID uint64 `gorm:"column:id;primaryKey;autoIncrement"`
Scene string `gorm:"column:scene;type:varchar(64);not null;index:idx_credit_price_rules_scene_status,priority:1;comment:计费场景"`
ProviderName string `gorm:"column:provider_name;type:varchar(64);not null;comment:模型提供方"`
ModelName string `gorm:"column:model_name;type:varchar(128);not null;comment:模型名称"`
InputPriceMicros int64 `gorm:"column:input_price_micros;not null;default:0;comment:输入Token单价单位微人民币"`
OutputPriceMicros int64 `gorm:"column:output_price_micros;not null;default:0;comment:输出Token单价单位微人民币"`
CachedPriceMicros int64 `gorm:"column:cached_price_micros;not null;default:0;comment:缓存Token单价单位微人民币"`
ReasoningPriceMicros int64 `gorm:"column:reasoning_price_micros;not null;default:0;comment:推理Token单价单位微人民币"`
CreditPerYuan int64 `gorm:"column:credit_per_yuan;not null;default:0;comment:1元人民币换算多少Credit"`
Status string `gorm:"column:status;type:varchar(32);not null;default:'inactive';index:idx_credit_price_rules_scene_status,priority:2;comment:active/inactive"`
Priority int `gorm:"column:priority;not null;default:0;comment:匹配优先级,越大越优先"`
Description string `gorm:"column:description;type:varchar(255);comment:规则说明"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;comment:创建时间"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;comment:更新时间"`
}
func (CreditPriceRule) TableName() string {
return "credit_price_rules"
}
// CreditRewardRule 是 Credit 奖励规则表。
type CreditRewardRule struct {
ID uint64 `gorm:"column:id;primaryKey;autoIncrement"`
Source string `gorm:"column:source;type:varchar(32);not null;uniqueIndex:uk_credit_reward_rules_source;comment:奖励来源"`
Name string `gorm:"column:name;type:varchar(80);not null;comment:规则名称"`
Amount int64 `gorm:"column:amount;not null;comment:奖励Credit数量"`
Status string `gorm:"column:status;type:varchar(32);not null;default:'active';index:idx_credit_reward_rules_status;comment:active/inactive"`
Description string `gorm:"column:description;type:varchar(255);comment:规则描述"`
ConfigJSON *string `gorm:"column:config_json;type:json;comment:扩展配置"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;comment:创建时间"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;comment:更新时间"`
}
func (CreditRewardRule) TableName() string {
return "credit_reward_rules"
}

View File

@@ -1,155 +0,0 @@
package model
import "time"
const (
// TokenProductStatusActive 表示商品可在 Token 商店展示和购买。
TokenProductStatusActive = "active"
// TokenProductStatusInactive 表示商品已下架,不再对前端展示。
TokenProductStatusInactive = "inactive"
)
const (
// TokenOrderStatusPending 表示订单已创建,等待支付确认。
TokenOrderStatusPending = "pending"
// TokenOrderStatusPaid 表示订单已确认支付,等待写入获取账本。
TokenOrderStatusPaid = "paid"
// TokenOrderStatusGranted 表示订单已经写入 token_grants 获取账本。
TokenOrderStatusGranted = "granted"
// TokenOrderStatusClosed 表示订单关闭P0 暂不实现复杂关闭流程。
TokenOrderStatusClosed = "closed"
)
const (
// TokenGrantStatusRecorded 表示 Token 获取事实已记录在 token-store 内。
TokenGrantStatusRecorded = "recorded"
// TokenGrantStatusApplied 表示后续已同步到 user/auth 权威额度。
TokenGrantStatusApplied = "applied"
// TokenGrantStatusSkipped 表示命中奖励规则或幂等条件后跳过发放。
TokenGrantStatusSkipped = "skipped"
// TokenGrantStatusFailed 表示记录或后续同步失败,可按 event_id 重试。
TokenGrantStatusFailed = "failed"
)
const (
// TokenGrantSourcePurchase 表示购买 Token 商品产生的获取记录。
TokenGrantSourcePurchase = "purchase"
// TokenGrantSourceForumLike 表示计划被点赞产生的作者奖励。
TokenGrantSourceForumLike = "forum_like"
// TokenGrantSourceForumImport 表示计划被导入产生的作者奖励。
TokenGrantSourceForumImport = "forum_import"
// TokenGrantSourceManual 预留人工补偿来源P0 不做管理后台。
TokenGrantSourceManual = "manual"
)
const (
// TokenRewardRuleStatusActive 表示奖励规则启用。
TokenRewardRuleStatusActive = "active"
// TokenRewardRuleStatusInactive 表示奖励规则停用。
TokenRewardRuleStatusInactive = "inactive"
)
// TokenProduct 是 Token 商店商品表。
//
// 职责边界:
// 1. P0 从表读取商品,由 seed 初始化 2-3 个固定商品;
// 2. 不承载真实支付渠道配置,也不做商品管理后台;
// 3. 下单时会复制商品快照到订单,避免后续改价影响历史订单。
type TokenProduct struct {
ID uint64 `gorm:"column:id;primaryKey;autoIncrement"`
SKU string `gorm:"column:sku;type:varchar(64);not null;uniqueIndex:uk_token_products_sku;comment:商品稳定编码"`
Name string `gorm:"column:name;type:varchar(80);not null;comment:商品名称"`
Description string `gorm:"column:description;type:varchar(255);comment:商品描述"`
TokenAmount int64 `gorm:"column:token_amount;not null;comment:商品包含Token数量"`
PriceCent int64 `gorm:"column:price_cent;not null;comment:价格,单位分"`
Currency string `gorm:"column:currency;type:varchar(16);not null;default:'CNY';comment:币种"`
Badge string `gorm:"column:badge;type:varchar(32);comment:前端角标"`
Status string `gorm:"column:status;type:varchar(32);not null;default:'active';index:idx_token_products_status_sort,priority:1;comment:active/inactive"`
SortOrder int `gorm:"column:sort_order;not null;default:0;index:idx_token_products_status_sort,priority:2;comment:展示排序"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;comment:创建时间"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;comment:更新时间"`
}
func (TokenProduct) TableName() string {
return "token_products"
}
// TokenOrder 是 Token 商品订单表。
//
// 职责边界:
// 1. 记录用户购买商品的订单状态机;
// 2. P0 只支持 mock paid不接真实支付网关
// 3. granted 只表示已写入 token-store 获取账本,不代表已同步到 user/auth 权威额度。
type TokenOrder struct {
ID uint64 `gorm:"column:id;primaryKey;autoIncrement"`
OrderNo string `gorm:"column:order_no;type:varchar(64);not null;uniqueIndex:uk_token_orders_order_no;comment:订单号"`
UserID uint64 `gorm:"column:user_id;not null;uniqueIndex:uk_token_orders_user_idem,priority:1;index:idx_token_orders_user_status_created,priority:1;comment:下单用户ID"`
ProductID uint64 `gorm:"column:product_id;not null;index:idx_token_orders_product;comment:商品ID"`
ProductSKU string `gorm:"column:product_sku;type:varchar(64);not null;comment:商品SKU快照"`
ProductName string `gorm:"column:product_name;type:varchar(80);not null;comment:商品名称快照"`
ProductSnapshotJSON string `gorm:"column:product_snapshot_json;type:json;not null;comment:商品完整快照JSON"`
Quantity int `gorm:"column:quantity;not null;default:1;comment:购买数量"`
TokenAmount int64 `gorm:"column:token_amount;not null;comment:订单总Token数量"`
AmountCent int64 `gorm:"column:amount_cent;not null;comment:订单总金额,单位分"`
Currency string `gorm:"column:currency;type:varchar(16);not null;default:'CNY';comment:币种"`
Status string `gorm:"column:status;type:varchar(32);not null;default:'pending';index:idx_token_orders_user_status_created,priority:2;comment:pending/paid/granted/closed"`
PaymentMode string `gorm:"column:payment_mode;type:varchar(32);not null;default:'mock';comment:支付模式P0为mock"`
IdempotencyKey *string `gorm:"column:idempotency_key;type:varchar(128);uniqueIndex:uk_token_orders_user_idem,priority:2;comment:创建订单幂等键"`
PaidAt *time.Time `gorm:"column:paid_at;comment:支付确认时间"`
GrantedAt *time.Time `gorm:"column:granted_at;comment:写入获取账本时间"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;index:idx_token_orders_user_status_created,priority:3;comment:创建时间"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;comment:更新时间"`
}
func (TokenOrder) TableName() string {
return "token_orders"
}
// TokenGrant 是 Token 获取账本表。
//
// 职责边界:
// 1. 记录购买、论坛点赞奖励、论坛导入奖励等 Token 获取事实;
// 2. event_id 是最终幂等边界,避免订单或 outbox 重试重复发放;
// 3. P0 不直接修改 users 表quota_applied 默认为 false。
type TokenGrant struct {
ID uint64 `gorm:"column:id;primaryKey;autoIncrement"`
EventID string `gorm:"column:event_id;type:varchar(128);not null;uniqueIndex:uk_token_grants_event;comment:幂等事件ID"`
UserID uint64 `gorm:"column:user_id;not null;index:idx_token_grants_user_source_created,priority:1;comment:获得Token的用户ID"`
Source string `gorm:"column:source;type:varchar(32);not null;index:idx_token_grants_user_source_created,priority:2;comment:purchase/forum_like/forum_import/manual"`
SourceLabel string `gorm:"column:source_label;type:varchar(64);comment:前端展示来源"`
SourceRefID *uint64 `gorm:"column:source_ref_id;index:idx_token_grants_source_ref;comment:来源业务ID如order_id/post_id/import_id"`
OrderID *uint64 `gorm:"column:order_id;index:idx_token_grants_order;comment:购买订单ID非购买来源为空"`
Amount int64 `gorm:"column:amount;not null;comment:获取Token数量"`
Status string `gorm:"column:status;type:varchar(32);not null;default:'recorded';index:idx_token_grants_status;comment:recorded/applied/skipped/failed"`
QuotaApplied bool `gorm:"column:quota_applied;not null;default:false;comment:是否已同步到user/auth权威额度"`
Description string `gorm:"column:description;type:varchar(255);comment:前端展示描述"`
AppliedAt *time.Time `gorm:"column:applied_at;comment:同步到权威额度时间"`
LastError *string `gorm:"column:last_error;type:text;comment:后续同步失败原因"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;index:idx_token_grants_user_source_created,priority:3;comment:创建时间"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;comment:更新时间"`
}
func (TokenGrant) TableName() string {
return "token_grants"
}
// TokenRewardRule 是社区奖励规则表。
//
// 职责边界:
// 1. P0 可用 seed 初始化点赞、导入奖励额度;
// 2. 不提供管理后台,规则调整先通过配置或 seed 变更;
// 3. 规则命中后的最终发放仍以 token_grants.event_id 幂等为准。
type TokenRewardRule struct {
ID uint64 `gorm:"column:id;primaryKey;autoIncrement"`
Source string `gorm:"column:source;type:varchar(32);not null;uniqueIndex:uk_token_reward_rules_source;comment:forum_like/forum_import"`
Name string `gorm:"column:name;type:varchar(80);not null;comment:规则名称"`
Amount int64 `gorm:"column:amount;not null;comment:奖励Token数量"`
Status string `gorm:"column:status;type:varchar(32);not null;default:'active';index:idx_token_reward_rules_status;comment:active/inactive"`
ConfigJSON *string `gorm:"column:config_json;type:json;comment:预留扩展配置"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;comment:创建时间"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;comment:更新时间"`
}
func (TokenRewardRule) TableName() string {
return "token_reward_rules"
}