package main import ( "context" "log/slog" "time" "github.com/google/uuid" "visiona-backend/internal/auth" "visiona-backend/internal/device" "visiona-backend/internal/model" ) // seedDemoData 在啟動時塞入示範資料,方便本機開發 / demo 不必跑完整 pairing。 // // 觸發條件:VISIONA_SEED_DEMO_DATA=true // // 內容: // - 一個示範 device(KL520) // - 一個示範 model(YOLOv5 Face) // - 一個示範 pairing token(log 出來方便手動 copy) // // 注意: // - 失敗只 log warning,不阻擋啟動 // - 重複呼叫會產生重複資料;本函式只該被呼叫一次(main 已保證) // - **不要**在生產環境啟用此 flag func seedDemoData( devRepo device.Repository, mdlRepo model.Repository, pairings auth.PairingStore, userID string, log *slog.Logger, ) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() now := time.Now().UTC() // 1. Demo device dev := &device.Device{ ID: "demo-device-" + uuid.NewString()[:8], OwnerUserID: userID, Name: "Demo KL520 (seeded)", DeviceType: "kl520", SerialNumber: "DEMO-SN-001", RemoteStatus: device.RemoteStatusOffline, Status: device.USBStatusUnknown, CreatedAt: now, UpdatedAt: now, } if err := devRepo.Save(ctx, dev); err != nil { log.Warn("seed: device save failed", "error", err) } else { log.Info("seed: demo device created", "id", dev.ID, "name", dev.Name) } // 2. Demo model mdl := &model.Model{ ID: "demo-model-" + uuid.NewString()[:8], OwnerUserID: userID, Name: "YOLOv5 Face (seeded)", TargetChip: "kl520", FileSize: 1024 * 1024, // 1 MB Source: model.SourceUploaded, StorageKey: "models/" + userID + "/demo.nef", CreatedAt: now, UpdatedAt: now, UploadedAt: &now, } if err := mdlRepo.Save(ctx, mdl); err != nil { log.Warn("seed: model save failed", "error", err) } else { log.Info("seed: demo model created", "id", mdl.ID, "name", mdl.Name) } // 3. Demo pairing token(log plaintext 方便開發 — 雛形 demo 用,生產禁用) pt, _, err := pairings.Create(ctx, userID, 24*time.Hour) if err != nil { log.Warn("seed: pairing token create failed", "error", err) } else { log.Info("seed: demo pairing token created (use for local-tool tunnel)", "token", pt, "ttl", "24h") } return nil }