-- 0007_manual_schedules.sql -- -- Unify "what does this host back up?" under schedules. Drop the -- legacy host.default_paths column in favour of a `manual` flag on -- schedules: a manual schedule carries paths/excludes/tags/retention -- like any other but has no cron expression — it only fires when -- the operator clicks Run-now. -- -- Steps (each is a single ALTER, no table rebuilds): -- 1. Add schedules.manual. -- 2. For every host with non-empty default_paths, create a manual -- schedule seeded with those paths and bump host_schedule_version -- so the next push reaches the agent. -- 3. ALTER TABLE hosts DROP COLUMN default_paths. -- 4. ALTER TABLE enrollment_tokens RENAME COLUMN default_paths -- TO initial_paths. -- -- The earlier draft of this migration rebuilt hosts via the -- create-new + drop-old + rename pattern. With foreign_keys=ON -- (which the connection DSN sets), DROP TABLE on the parent -- triggered ON DELETE CASCADE on every child of hosts(id) — the -- smoke env lost schedules / jobs / snapshots / host_credentials -- as a result. SQLite 3.35+ supports column-level ALTERs, so we -- skip the rebuild entirely and avoid the cascade trap. ALTER TABLE schedules ADD COLUMN manual INTEGER NOT NULL DEFAULT 0; INSERT INTO schedules ( id, host_id, kind, cron_expr, paths, excludes, tags, retention_policy, options, pre_hook, post_hook, enabled, manual, created_at, updated_at ) SELECT lower(hex(randomblob(13))), id, 'backup', '', default_paths, '[]', '[]', '{}', '{}', '', '', 1, 1, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'), strftime('%Y-%m-%dT%H:%M:%fZ', 'now') FROM hosts WHERE default_paths IS NOT NULL AND default_paths != '' AND default_paths != '[]'; INSERT INTO host_schedule_version (host_id, version) SELECT id, 1 FROM hosts WHERE default_paths IS NOT NULL AND default_paths != '' AND default_paths != '[]' ON CONFLICT(host_id) DO UPDATE SET version = version + 1; ALTER TABLE hosts DROP COLUMN default_paths; ALTER TABLE enrollment_tokens RENAME COLUMN default_paths TO initial_paths;