fix(#48): add the missing version-local migration for syb_session

Adding SYBSession to migrations.Migrate was not enough. Schema reaches an
existing database only through a version-local file; with the previous
version already recorded in sys_migration, Migrate never re-ran and the
table simply never appeared. The unit tests build a fresh database every
time, so they stayed green while the real database was missing a table —
which surfaced as "Error 1146: Table 'goauto.syb_session' doesn't exist"
on the first import attempt.

server/.gitignore was hiding these files. go-admin ignores version-local
because it is where generated local migrations land, but every GoAuto
migration belongs in version control; the existing ones had been forced
in with `git add -f`. Un-ignoring *.go there also recovers four migrations
that were never committed at all — 1786700000000 through 1786700300000,
covering the base schema, device registration, heartbeat and collection
execution. A fresh clone could not have built a working database.

Guard the class of mistake rather than just this instance:

  - migrations.VerifyTables checks every model's table after migrating and
    names what is missing along with the fix.
  - The migrate command runs it, so the failure lands at migrate time
    instead of at the first request that needs the table.
  - initDB no longer discards migrateModel's error. Upstream had
    `_ = migrateModel()` followed by an unconditional "初始化成功", so a
    failed migration reported success and the launcher believed it.

Also records the two-step rule in Common-Changes: a new model needs both
the model registration and a new version file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
QiuSW
2026-08-20 10:10:11 +08:00
co-authored by Claude Opus 5
parent a81d60523d
commit e6f533b71e
10 changed files with 241 additions and 6 deletions
@@ -0,0 +1,25 @@
package version_local
import (
"runtime"
goautomigrations "go-admin/app/goauto/migrations"
"go-admin/cmd/migrate/migration"
common "go-admin/common/models"
"gorm.io/gorm"
)
func init() {
_, fileName, _, _ := runtime.Caller(0)
migration.Migrate.SetVersion(migration.GetFilename(fileName), migrateGoAutoSchema)
}
func migrateGoAutoSchema(db *gorm.DB, version string) error {
return db.Transaction(func(tx *gorm.DB) error {
if err := goautomigrations.Migrate(tx); err != nil {
return err
}
return tx.Create(&common.Migration{Version: version}).Error
})
}
@@ -0,0 +1,25 @@
package version_local
import (
"runtime"
goautomodels "go-admin/app/goauto/models"
"go-admin/cmd/migrate/migration"
common "go-admin/common/models"
"gorm.io/gorm"
)
func init() {
_, fileName, _, _ := runtime.Caller(0)
migration.Migrate.SetVersion(migration.GetFilename(fileName), migrateDeviceRegistration)
}
func migrateDeviceRegistration(db *gorm.DB, version string) error {
return db.Transaction(func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&goautomodels.AgentDevice{}); err != nil {
return err
}
return tx.Create(&common.Migration{Version: version}).Error
})
}
@@ -0,0 +1,25 @@
package version_local
import (
"runtime"
goautomodels "go-admin/app/goauto/models"
"go-admin/cmd/migrate/migration"
common "go-admin/common/models"
"gorm.io/gorm"
)
func init() {
_, fileName, _, _ := runtime.Caller(0)
migration.Migrate.SetVersion(migration.GetFilename(fileName), migrateDeviceHeartbeat)
}
func migrateDeviceHeartbeat(db *gorm.DB, version string) error {
return db.Transaction(func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&goautomodels.AgentDevice{}); err != nil {
return err
}
return tx.Create(&common.Migration{Version: version}).Error
})
}
@@ -0,0 +1,29 @@
package version_local
import (
"runtime"
goautomigrations "go-admin/app/goauto/migrations"
"go-admin/cmd/migrate/migration"
common "go-admin/common/models"
"gorm.io/gorm"
)
// This separate version is required for databases that already applied the
// initial GoAuto schema before task execution, result, reset and delete fields
// were introduced. Re-running AutoMigrate under a new version is additive and
// keeps existing task snapshots and results intact.
func init() {
_, fileName, _, _ := runtime.Caller(0)
migration.Migrate.SetVersion(migration.GetFilename(fileName), migrateCollectionExecution)
}
func migrateCollectionExecution(db *gorm.DB, version string) error {
return db.Transaction(func(tx *gorm.DB) error {
if err := goautomigrations.Migrate(tx); err != nil {
return err
}
return tx.Create(&common.Migration{Version: version}).Error
})
}
@@ -0,0 +1,33 @@
package version_local
import (
"runtime"
goautomigrations "go-admin/app/goauto/migrations"
"go-admin/cmd/migrate/migration"
common "go-admin/common/models"
"gorm.io/gorm"
)
// This migration adds the syb_session table, which caches one SYB ERP login so
// a server restart does not force a fresh captcha round-trip (#48). It is
// additive: no existing table is modified.
//
// `[必须]` A new version file is required for every model added to
// goautomigrations.Migrate. Adding the model alone only affects databases
// created from scratch — an existing database has already recorded the previous
// version and will never re-run it, so the table silently never appears.
func init() {
_, fileName, _, _ := runtime.Caller(0)
migration.Migrate.SetVersion(migration.GetFilename(fileName), migrateSYBSession)
}
func migrateSYBSession(db *gorm.DB, version string) error {
return db.Transaction(func(tx *gorm.DB) error {
if err := goautomigrations.Migrate(tx); err != nil {
return err
}
return tx.Create(&common.Migration{Version: version}).Error
})
}
+13 -3
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/go-admin-team/go-admin-core/sdk"
"github.com/go-admin-team/go-admin-core/sdk/pkg"
"os"
"strconv"
"text/template"
"time"
@@ -13,6 +14,7 @@ import (
"github.com/spf13/cobra"
"github.com/go-admin-team/go-admin-core/sdk/config"
goautomigrations "go-admin/app/goauto/migrations"
"go-admin/cmd/migrate/migration"
_ "go-admin/cmd/migrate/migration/version"
_ "go-admin/cmd/migrate/migration/version-local"
@@ -52,7 +54,7 @@ func run() {
config.Setup(
file.NewSource(file.WithPath(configYml)),
ext.ApplyLocalConfig,
ext.ApplyEnvironment,
ext.ApplyEnvironment,
initDB,
)
} else {
@@ -88,14 +90,22 @@ func migrateModel() error {
}
migration.Migrate.SetDb(db.Debug())
migration.Migrate.Migrate()
return err
// GoAuto 改动(#48):迁移跑完后核对 GoAuto 的表是否都在。
// 新增模型时若忘了加 version-local 版本文件,迁移会「成功」但表不会建出来,
// 直到运行时才炸成一句 Error 1146。这里让它在迁移阶段就报出表名。
return goautomigrations.VerifyTables(db)
}
func initDB() {
//3. 初始化数据库链接
database.Setup()
//4. 数据库迁移
fmt.Println("数据库迁移开始")
_ = migrateModel()
// GoAuto 改动(#48):上游这里是 `_ = migrateModel()`,丢掉错误后无条件
// 打印「成功」——迁移失败也会报成功,启动脚本据此认为一切正常。
if err := migrateModel(); err != nil {
fmt.Println("数据库迁移失败:", err)
os.Exit(1)
}
fmt.Println(`数据库基础数据初始化成功`)
}