Add safe database migration workflow and note history infrastructure.
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 5s

This introduces guarded migrations with automatic backups, fixes note creation after DB reset, and wires snapshot/restore history across notes surfaces.
This commit is contained in:
Sepehr Ramezani
2026-04-28 16:50:57 +02:00
parent 0fbb8aa599
commit ed807d3b2a
23 changed files with 8052 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
#!/usr/bin/env node
/* eslint-disable no-console */
const fs = require('fs')
const path = require('path')
const { spawnSync } = require('child_process')
require('dotenv').config({ path: path.join(__dirname, '..', '.env') })
function run(command, args, options = {}) {
const result = spawnSync(command, args, {
stdio: 'inherit',
shell: process.platform === 'win32',
...options,
})
if (result.status !== 0) {
process.exit(result.status || 1)
}
}
function nowStamp() {
const d = new Date()
const pad = (n) => String(n).padStart(2, '0')
return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}_${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`
}
const databaseUrl = process.env.DATABASE_URL
if (!databaseUrl) {
console.error('[safe-migrate] DATABASE_URL is missing in environment/.env')
process.exit(1)
}
const backupsDir = path.join(__dirname, '..', 'backups', 'migrations')
fs.mkdirSync(backupsDir, { recursive: true })
const isPostgres = databaseUrl.startsWith('postgres://') || databaseUrl.startsWith('postgresql://')
const isSqlite = databaseUrl.startsWith('file:')
console.log('[safe-migrate] Starting safe migration flow')
if (isPostgres) {
const backupFile = path.join(backupsDir, `pre_migrate_${nowStamp()}.sql`)
console.log(`[safe-migrate] Creating PostgreSQL backup: ${backupFile}`)
let dump = spawnSync(
'pg_dump',
['--no-owner', '--no-privileges', '--format=plain', '--file', backupFile, databaseUrl],
{ stdio: 'inherit', shell: process.platform === 'win32' }
)
if (dump.status !== 0) {
console.warn('[safe-migrate] Local pg_dump unavailable, trying Docker fallback...')
const pgUser = process.env.POSTGRES_USER || 'memento'
const pgDb = process.env.POSTGRES_DB || 'memento'
const dockerCmd = `docker exec memento-postgres pg_dump -U ${pgUser} -d ${pgDb} --no-owner --no-privileges --format=plain > "${backupFile}"`
dump = spawnSync(dockerCmd, { stdio: 'inherit', shell: true })
}
if (dump.status !== 0) {
console.error('[safe-migrate] Backup failed (local + docker). Migration aborted to protect data.')
process.exit(dump.status || 1)
}
} else if (isSqlite) {
const dbPath = databaseUrl.replace(/^file:/, '')
const absoluteDbPath = path.isAbsolute(dbPath) ? dbPath : path.join(__dirname, '..', dbPath)
if (fs.existsSync(absoluteDbPath)) {
const backupFile = path.join(backupsDir, `pre_migrate_${nowStamp()}.sqlite`)
console.log(`[safe-migrate] Creating SQLite backup: ${backupFile}`)
fs.copyFileSync(absoluteDbPath, backupFile)
} else {
console.warn(`[safe-migrate] SQLite file not found at ${absoluteDbPath}, skipping backup`)
}
} else {
console.warn('[safe-migrate] Unknown DATABASE_URL protocol, skipping backup step')
}
console.log('[safe-migrate] Applying migrations with prisma migrate deploy')
run('npx', ['prisma', 'migrate', 'deploy'])
console.log('[safe-migrate] Migration completed successfully')