Skip to content

Data Schema Migration

Runeya maintains backwards compatibility with previous versions of ./.runeya/ via an automatic migration system at startup.

How It Works

Au démarrage, le serveur lit schema-version.json et applique les migrations nécessaires dans l'ordre :

schema-version.json: { "version": 2 }

                  migrations disponibles
                      v2 → v3 (appliquée)

                  schema-version.json: { "version": 3 }

Available Migrations

migrate-from-legacy.ts (v1 → v3)

Migration principale depuis le format legacy :

  • Crée des environnements service-scoped depuis les anciens inheritAllEnv et serviceVariables
  • Supprime les champs obsolètes
  • Met à jour le schéma de version

Adding a Migration

typescript
// apps/server/src/migrations/v3-to-v4.ts
export async function migrateV3ToV4(dataDir: string): Promise<void> {
  const services = await readJson(join(dataDir, 'services.json'))

  const migrated = services.map(service => ({
    ...service,
    newField: 'default-value',  // nouveau champ avec valeur par défaut
  }))

  await writeJsonAtomic(join(dataDir, 'services.json'), migrated)
}

Puis dans le runner de migrations :

typescript
// apps/server/src/migrations/index.ts
const migrations = [
  { from: 1, to: 3, fn: migrateFromLegacy },
  { from: 3, to: 4, fn: migrateV3ToV4 },  // nouvelle
]

Atomic Writes

Toutes les migrations utilisent l'écriture atomique pour éviter la corruption :

typescript
async function writeJsonAtomic(path: string, data: unknown): Promise<void> {
  const tmp = path + '.tmp'
  await fs.writeFile(tmp, JSON.stringify(data, null, 2))
  await fs.rename(tmp, path)  // atomique sur POSIX
}

Backup Before Migration

TIP

Runeya automatically creates a backup of ./.runeya/ before applying migrations. Backups are stored in ./.runeya/backups/.

Released under the MIT License.