From df5c8aad109ee490eb850cfb368a723daec3aaf0 Mon Sep 17 00:00:00 2001 From: 4gray Date: Thu, 10 Sep 2026 23:02:00 +0200 Subject: [PATCH] docs(database): require upgrades across skipped releases --- AGENTS.md | 8 ++++++++ CLAUDE.md | 12 ++++++++++-- libs/shared/database/README.md | 36 ++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e5c67996c..38c8857f7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -98,6 +98,14 @@ preserves Linux window identity without a shared `linux.desktop.entry` object enable AppImageUpdate/zsync. Contract: `docs/architecture/release-pipeline.md` (AppImage external-manager metadata). +## Upgrade And Migration Compatibility + +- Users may skip releases. The application must apply all required migrations in dependency order when upgrading directly from an older release; never assume that users installed or launched every intermediate version. +- Preserve migration paths for existing persisted data. Do not make deleting a database/profile or reinstalling the application a normal upgrade requirement. Any unavoidable intermediate-version requirement must be an explicitly documented exception. +- Create required tables first, add missing columns before dependent indexes/triggers/queries, and make startup migrations safe to run again. `CREATE TABLE IF NOT EXISTS` does not update an existing table's columns. +- For persistence changes, test real SQLite initialization with representative historical schemas and data, including skipped releases, the previous release, a fresh database, and repeated startup. Assert preservation of user data as well as the resulting schema; SQL mocks alone cannot verify upgrade compatibility. Cover equivalent persisted-state transitions for non-SQLite stores. +- See `libs/shared/database/README.md` for SQLite migration ownership and validation guidance. + ## Regression Prevention And Test Updates - Before the final summary for any feature, behavior change, bug fix, data-flow change, Electron IPC/database change, or user-visible UI workflow change, complete a test impact pass. Identify the affected projects and decide whether unit, integration, E2E, build, lint, or manual/CDP verification is required. diff --git a/CLAUDE.md b/CLAUDE.md index ec455f414..808011503 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,7 +2,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. -> The process sections below (Plan Mode, Documentation After Changes, Regression Prevention, Agent Bootstrap, Electron CDP Debugging) are mirrored in `AGENTS.md`, which is the canonical copy for agent workflows. When updating one, keep the other in sync. +> The process sections below (Plan Mode, Documentation After Changes, Upgrade And Migration Compatibility, Regression Prevention, Agent Bootstrap, Electron CDP Debugging) are mirrored in `AGENTS.md`, which is the canonical copy for agent workflows. When updating one, keep the other in sync. ## Plan Mode @@ -53,6 +53,14 @@ preserves Linux window identity without a shared `linux.desktop.entry` object enable AppImageUpdate/zsync. Contract: `docs/architecture/release-pipeline.md` (AppImage external-manager metadata). +## Upgrade And Migration Compatibility + +- Users may skip releases. The application must apply all required migrations in dependency order when upgrading directly from an older release; never assume that users installed or launched every intermediate version. +- Preserve migration paths for existing persisted data. Do not make deleting a database/profile or reinstalling the application a normal upgrade requirement. Any unavoidable intermediate-version requirement must be an explicitly documented exception. +- Create required tables first, add missing columns before dependent indexes/triggers/queries, and make startup migrations safe to run again. `CREATE TABLE IF NOT EXISTS` does not update an existing table's columns. +- For persistence changes, test real SQLite initialization with representative historical schemas and data, including skipped releases, the previous release, a fresh database, and repeated startup. Assert preservation of user data as well as the resulting schema; SQL mocks alone cannot verify upgrade compatibility. Cover equivalent persisted-state transitions for non-SQLite stores. +- See `libs/shared/database/README.md` for SQLite migration ownership and validation guidance. + ## Regression Prevention And Test Updates - Before the final summary for any feature, behavior change, bug fix, data-flow change, Electron IPC/database change, or user-visible UI workflow change, Claude Code must complete a test impact pass. Identify the affected projects and decide whether unit, integration, E2E, build, lint, or manual/CDP verification is required. @@ -1699,7 +1707,7 @@ The Electron backend depends on the web app being built first: ### Database Migrations -No formal migration system yet. Schema changes are applied via raw SQL in the `createTables()` function in `libs/shared/database/src/lib/connection.ts` using `CREATE TABLE IF NOT EXISTS`. One-off data migrations run guarded by keys stored in the `appState` table. +Database initialization is owned by `libs/shared/database/src/lib/connection.ts`. `createTables()` creates missing schema objects, and `runMigrations()` applies column/index migrations and dedicated schema/data upgrades. `CREATE TABLE IF NOT EXISTS` does not add columns to existing tables. One-off data migrations use completion keys stored in `app_state` (exported as `appState`). Follow the Upgrade And Migration Compatibility policy above and the validation guidance in `libs/shared/database/README.md`; a new release must not depend on users having launched intermediate releases. ### Common Patterns diff --git a/libs/shared/database/README.md b/libs/shared/database/README.md index cd04e865a..ecddbff4a 100644 --- a/libs/shared/database/README.md +++ b/libs/shared/database/README.md @@ -31,3 +31,39 @@ import { content, categories, playlists, type Content } from '@iptvnator/shared/ ## Database Location The SQLite database is stored at: `~/.iptvnator/databases/iptvnator.db` + +## Upgrade Compatibility And Migrations + +Users may skip releases. The application must apply every required migration in +dependency order when opening an older database, preserving user data without +requiring intermediate application installations or a database reset. This is +the repository policy mirrored in `AGENTS.md` and `CLAUDE.md`. + +`src/lib/connection.ts` owns initialization: `createTables()` creates missing +schema objects, then `runMigrations()` applies column/index migrations and +dedicated schema/data upgrades. One-off data migrations can record completion +in `app_state`. Keep existing migration paths when adding new ones. + +When changing initialization: + +- Create required tables before migrating them. `CREATE TABLE IF NOT EXISTS` + leaves existing columns unchanged. +- Add missing columns before creating indexes or triggers, or running queries, + that depend on those columns. Put indexes depending on migrated columns in + `INDEX_MIGRATION_STATEMENTS`, after `COLUMN_MIGRATION_STATEMENTS`, rather than + in the earlier schema creation phase. +- Preserve existing data and make migrations safe on repeated startup. Record + completion only after the associated migration succeeds. +- Exercise the actual initialization path with real SQLite and historical + schema fixtures containing representative playlists, favorites, history, and + playback positions. Verify both schema changes and preservation of those rows; + mocked SQL calls alone do not establish upgrade compatibility. +- Include direct upgrades across skipped releases, the previous release, a fresh + install, and repeated startup. If a release changes migration ordering, cover + each distinct affected historical schema. + +For the upgrade failure reported in #1580, the 0.24 fix should cover databases +from 0.19, 0.20, 0.21, 0.22, and 0.23: the `epg_channel_id` column is absent in +0.19, present from 0.20, and indexed from 0.23. The index must be created only +after the column migration; an existing index must remain valid. This documents +the required regression coverage, not a claim that the fix is already applied.