refactor: Remove database migrations for clean dev-phase bootstrap (#176)
This commit is contained in:
@@ -188,7 +188,6 @@ kandev/
|
||||
│ │ └── Makefile
|
||||
│ └── web/ # Frontend application
|
||||
├── docs/ # Architecture and planning docs
|
||||
├── migrations/ # Database migrations (future)
|
||||
├── deployments/ # Deployment configs
|
||||
└── scripts/ # Utility scripts (including e2e-test.sh)
|
||||
```
|
||||
|
||||
@@ -58,6 +58,7 @@ func (r *sqliteRepository) initSchema() error {
|
||||
auto_approve INTEGER NOT NULL DEFAULT 0,
|
||||
dangerously_skip_permissions INTEGER NOT NULL DEFAULT 0,
|
||||
allow_indexing INTEGER NOT NULL DEFAULT 1,
|
||||
cli_passthrough INTEGER NOT NULL DEFAULT 0,
|
||||
plan TEXT DEFAULT '',
|
||||
created_at DATETIME NOT NULL,
|
||||
updated_at DATETIME NOT NULL,
|
||||
@@ -80,19 +81,7 @@ func (r *sqliteRepository) initSchema() error {
|
||||
CREATE INDEX IF NOT EXISTS idx_agent_profiles_agent_id ON agent_profiles(agent_id);
|
||||
`
|
||||
_, err := r.db.Exec(schema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := sqlite.EnsureColumn(r.db, "agent_profiles", "deleted_at", "DATETIME"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := sqlite.EnsureColumn(r.db, "agent_profiles", "agent_display_name", "TEXT NOT NULL DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := sqlite.EnsureColumn(r.db, "agent_profiles", "cli_passthrough", "INTEGER NOT NULL DEFAULT 0"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *sqliteRepository) Close() error {
|
||||
|
||||
@@ -72,21 +72,7 @@ func (r *sqliteRepository) initSchema() error {
|
||||
);
|
||||
`
|
||||
_, err := r.db.Exec(schema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
columns := []columnDef{
|
||||
{name: "name", typ: "TEXT", defaultValue: "''"},
|
||||
{name: "kind", typ: "TEXT", defaultValue: "'built_in'"},
|
||||
{name: "config", typ: "TEXT", defaultValue: "NULL"},
|
||||
{name: "installed", typ: "INTEGER", defaultValue: "0"},
|
||||
}
|
||||
for _, column := range columns {
|
||||
if err := ensureColumn(r.db, "editors", column); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *sqliteRepository) ensureDefaults(ctx context.Context) error {
|
||||
@@ -319,47 +305,6 @@ func scanEditor(scanner interface{ Scan(dest ...any) error }) (*models.Editor, e
|
||||
return editor, nil
|
||||
}
|
||||
|
||||
type columnDef struct {
|
||||
name string
|
||||
typ string
|
||||
defaultValue string
|
||||
}
|
||||
|
||||
func ensureColumn(db *sql.DB, table string, column columnDef) error {
|
||||
rows, err := db.Query(fmt.Sprintf("PRAGMA table_info(%s)", table))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = rows.Close()
|
||||
}()
|
||||
for rows.Next() {
|
||||
var (
|
||||
cid int
|
||||
name string
|
||||
typ string
|
||||
notNull int
|
||||
defaultVal sql.NullString
|
||||
pk int
|
||||
)
|
||||
if err := rows.Scan(&cid, &name, &typ, ¬Null, &defaultVal, &pk); err != nil {
|
||||
return err
|
||||
}
|
||||
if name == column.name {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
alter := fmt.Sprintf(
|
||||
"ALTER TABLE %s ADD COLUMN %s %s DEFAULT %s",
|
||||
table,
|
||||
column.name,
|
||||
column.typ,
|
||||
column.defaultValue,
|
||||
)
|
||||
_, err = db.Exec(alter)
|
||||
return err
|
||||
}
|
||||
|
||||
func marshalConfig(config json.RawMessage) (string, error) {
|
||||
if len(config) == 0 {
|
||||
return "", nil
|
||||
|
||||
@@ -4,8 +4,6 @@ package sqlite
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
commonsqlite "github.com/kandev/kandev/internal/common/sqlite"
|
||||
)
|
||||
|
||||
// Repository provides SQLite-based task storage operations.
|
||||
@@ -45,11 +43,6 @@ func (r *Repository) DB() *sql.DB {
|
||||
return r.db
|
||||
}
|
||||
|
||||
// ensureColumn adds a column to a table if it doesn't exist
|
||||
func (r *Repository) ensureColumn(table, column, definition string) error {
|
||||
return commonsqlite.EnsureColumn(r.db, table, column, definition)
|
||||
}
|
||||
|
||||
// ensureWorkspaceIndexes creates workspace-related indexes
|
||||
func (r *Repository) ensureWorkspaceIndexes() error {
|
||||
if _, err := r.db.Exec(`CREATE INDEX IF NOT EXISTS idx_tasks_workspace_id ON tasks(workspace_id)`); err != nil {
|
||||
@@ -129,6 +122,7 @@ func (r *Repository) initSchema() error {
|
||||
CREATE TABLE IF NOT EXISTS boards (
|
||||
id TEXT PRIMARY KEY,
|
||||
workspace_id TEXT NOT NULL DEFAULT '',
|
||||
workflow_template_id TEXT DEFAULT '',
|
||||
name TEXT NOT NULL,
|
||||
description TEXT DEFAULT '',
|
||||
created_at DATETIME NOT NULL,
|
||||
@@ -372,88 +366,6 @@ func (r *Repository) initSchema() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure columns exist for schema migrations
|
||||
if err := r.ensureColumn("boards", "workspace_id", "TEXT NOT NULL DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("boards", "workflow_template_id", "TEXT DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("tasks", "workspace_id", "TEXT NOT NULL DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("workspaces", "default_executor_id", "TEXT DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("workspaces", "default_environment_id", "TEXT DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("workspaces", "default_agent_profile_id", "TEXT DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.ensureColumn("environments", "is_system", "INTEGER NOT NULL DEFAULT 0"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("repositories", "deleted_at", "DATETIME"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("repositories", "worktree_branch_prefix", "TEXT DEFAULT 'feature/'"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("repositories", "pull_before_worktree", "INTEGER NOT NULL DEFAULT 1"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("repositories", "dev_script", "TEXT DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("executors", "deleted_at", "DATETIME"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("executors", "resumable", "INTEGER NOT NULL DEFAULT 1"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("environments", "deleted_at", "DATETIME"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure new message columns exist for existing databases
|
||||
if err := r.ensureColumn("task_session_messages", "type", "TEXT NOT NULL DEFAULT 'message'"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("task_session_messages", "metadata", "TEXT DEFAULT '{}'"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("task_session_messages", "task_session_id", "TEXT NOT NULL DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("task_session_messages", "turn_id", "TEXT DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure container_id column exists for existing databases
|
||||
if err := r.ensureColumn("task_sessions", "container_id", "TEXT NOT NULL DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("task_sessions", "executor_id", "TEXT DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("task_sessions", "environment_id", "TEXT DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("task_sessions", "state", "TEXT NOT NULL DEFAULT 'CREATED'"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("task_sessions", "is_primary", "INTEGER DEFAULT 0"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("task_sessions", "workflow_step_id", "TEXT DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureColumn("task_sessions", "review_status", "TEXT DEFAULT ''"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.ensureDefaultWorkspace(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/kandev/kandev/internal/common/sqlite"
|
||||
"github.com/kandev/kandev/internal/user/models"
|
||||
)
|
||||
|
||||
@@ -53,17 +52,10 @@ func (r *sqliteRepository) initSchema() error {
|
||||
if _, err := r.db.Exec(schema); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureUserSettingsColumn(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return r.ensureDefaultUser()
|
||||
}
|
||||
|
||||
func (r *sqliteRepository) ensureUserSettingsColumn() error {
|
||||
return sqlite.EnsureColumn(r.db, "users", "settings", "TEXT NOT NULL DEFAULT '{}'")
|
||||
}
|
||||
|
||||
func (r *sqliteRepository) ensureDefaultUser() error {
|
||||
ctx := context.Background()
|
||||
var count int
|
||||
|
||||
@@ -33,11 +33,6 @@ func (r *Repository) DB() *sql.DB {
|
||||
return r.db
|
||||
}
|
||||
|
||||
// ensureColumn adds a column to a table if it doesn't exist.
|
||||
func (r *Repository) ensureColumn(table, column, definition string) error {
|
||||
return sqlite.EnsureColumn(r.db, table, column, definition)
|
||||
}
|
||||
|
||||
// initSchema creates the database tables if they don't exist.
|
||||
func (r *Repository) initSchema() error {
|
||||
// Create workflow_templates table
|
||||
@@ -102,11 +97,6 @@ func (r *Repository) initSchema() error {
|
||||
return fmt.Errorf("failed to create session_step_history table: %w", err)
|
||||
}
|
||||
|
||||
// Run migrations for existing tables
|
||||
if err := r.runMigrations(); err != nil {
|
||||
return fmt.Errorf("failed to run migrations: %w", err)
|
||||
}
|
||||
|
||||
// Seed system templates
|
||||
if err := r.seedSystemTemplates(); err != nil {
|
||||
return fmt.Errorf("failed to seed system templates: %w", err)
|
||||
@@ -120,27 +110,6 @@ func (r *Repository) initSchema() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// runMigrations adds columns to existing tables.
|
||||
func (r *Repository) runMigrations() error {
|
||||
// Add workflow_template_id to boards table
|
||||
if err := r.ensureColumn("boards", "workflow_template_id", "TEXT"); err != nil {
|
||||
return fmt.Errorf("failed to add workflow_template_id to boards: %w", err)
|
||||
}
|
||||
|
||||
// Add workflow-related columns to task_sessions table
|
||||
if err := r.ensureColumn("task_sessions", "is_primary", "INTEGER DEFAULT 0"); err != nil {
|
||||
return fmt.Errorf("failed to add is_primary to task_sessions: %w", err)
|
||||
}
|
||||
if err := r.ensureColumn("task_sessions", "workflow_step_id", "TEXT"); err != nil {
|
||||
return fmt.Errorf("failed to add workflow_step_id to task_sessions: %w", err)
|
||||
}
|
||||
if err := r.ensureColumn("task_sessions", "review_status", "TEXT"); err != nil {
|
||||
return fmt.Errorf("failed to add review_status to task_sessions: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// seedDefaultWorkflowSteps creates default workflow steps for boards that don't have any.
|
||||
// Uses the simple template as the default workflow.
|
||||
func (r *Repository) seedDefaultWorkflowSteps() error {
|
||||
|
||||
Reference in New Issue
Block a user