feat: harden loose-offline sync for user JWT, schema, and console ops

Enable Binding-scoped agent push/pull, empty-table schema ensure, SyncPage inspect/drop-table, default module import, and agent-bound publish docs from the 宇恒联调意见.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
whm
2026-08-05 09:47:35 +08:00
parent 76cdcd760e
commit b04b180d30
59 changed files with 4762 additions and 308 deletions

View File

@@ -99,11 +99,14 @@ func (l *AgentAdminLogic) Create(req *types.AgentCreateReq) (*types.AgentCreateR
return nil, err
}
acc, secret, err := st.Create(l.ctx, authx.TenantID(l.ctx), authx.UserID(l.ctx), agentstore.CreateInput{
Name: req.Name,
Perms: perms,
AppSlugs: req.AppSlugs,
Status: agentstore.StatusActive,
RoleID: roleID,
Name: req.Name,
Perms: perms,
AppSlugs: req.AppSlugs,
Status: agentstore.StatusActive,
RoleID: roleID,
ChannelID: req.ChannelID,
OnlineDBID: req.OnlineDBID,
DatabaseName: req.DatabaseName,
})
if err != nil {
return nil, err
@@ -161,6 +164,15 @@ func (l *AgentAdminLogic) Update(agentID int64, req *types.AgentUpdateReq) (*age
if req.AppSlugs != nil {
in.AppSlugs = req.AppSlugs
}
if req.ChannelID != nil {
in.ChannelID = req.ChannelID
}
if req.OnlineDBID != nil {
in.OnlineDBID = req.OnlineDBID
}
if req.DatabaseName != nil {
in.DatabaseName = req.DatabaseName
}
if req.RoleID != nil {
roleID, perms, err := l.resolvePerms(*req.RoleID, nil)
if err != nil {

View File

@@ -68,17 +68,18 @@ func (l *PublishLogic) ListApps() (*types.AppListResp, error) {
}
st := it.Status
out = append(out, types.AppListItem{
AppID: it.AppID,
Slug: it.Slug,
Name: it.Name,
Status: string(st),
StatusLabel: meta.StatusLabelCN(st),
Building: meta.IsBuilding(st),
SchemaName: it.SchemaName,
PageCount: it.PageCount,
EntityCount: it.EntityCount,
UpdatedAt: it.UpdatedAt.UTC().Format(time.RFC3339),
CreatedAt: it.CreatedAt.UTC().Format(time.RFC3339),
AppID: it.AppID,
Slug: it.Slug,
Name: it.Name,
Status: string(st),
StatusLabel: meta.StatusLabelCN(st),
Building: meta.IsBuilding(st),
SchemaName: it.SchemaName,
DatabaseName: it.DatabaseName,
PageCount: it.PageCount,
EntityCount: it.EntityCount,
UpdatedAt: it.UpdatedAt.UTC().Format(time.RFC3339),
CreatedAt: it.CreatedAt.UTC().Format(time.RFC3339),
})
}
return &types.AppListResp{Items: out, Scope: scope}, nil
@@ -115,6 +116,7 @@ func (l *PublishLogic) SaveDraft(slug string, req *types.DraftReq) (*types.AppLi
if bp.Storage.Engine == "" {
bp.Storage.Engine = "postgres"
}
bp.EnsureDefaultImportExport()
// 草稿允许尚未完全合法;尽量校验,失败则仍以宽松方式保存关键字段
_ = bp.Validate(slug)
@@ -255,12 +257,27 @@ func (l *PublishLogic) Publish(slug string, req *types.PublishReq) (*types.Publi
}
}
bp.EnsureDefaultImportExport()
if err := bp.Validate(slug); err != nil {
return nil, err
}
schemaName := bp.AssignSchemaName(tenantID)
dbName := bp.AssignDatabaseName(tenantID)
// Z8c智能体若绑定了 database_name新建模块优先落到该库database_per_app
if authx.Role(l.ctx) == authx.RoleAgent && l.svcCtx.Agents != nil {
if aid := authx.AgentID(l.ctx); aid > 0 {
if acc, err := l.svcCtx.Agents.Get(l.ctx, tenantID, aid); err == nil && acc != nil {
if dn := strings.TrimSpace(acc.DatabaseName); dn != "" {
if !exists || existing.DatabaseName == "" {
bp.Storage.Mode = "database_per_app"
schemaName = bp.AssignSchemaName(tenantID)
dbName = dn
}
}
}
}
}
ddl, err := schema.BuildPostgresDDL(bp)
if err != nil {
return nil, err