fix: migration dedup and legacy reconcile gaps

- Removed double log line in runMigrations (migration name printed twice)
- Added v0.54 (user_settings) and v0.55 (user_login_history device metadata) to reconcileLegacyMigrations
- Both are idempotent, no data was ever lost, but legacy upgrades were re-running them unnecessarily
This commit is contained in:
null 2026-05-28 23:28:53 -05:00
parent a1f679f7b0
commit 1b9518a5d7
2 changed files with 45 additions and 3 deletions

View File

@ -877,6 +877,50 @@ function reconcileLegacyMigrations() {
console.log('[migration] user_login_history table created');
}
},
{
version: 'v0.54',
description: 'user_settings: per-user display and billing preferences',
check: function() {
return !!db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='user_settings'").get();
},
run: function() {
db.exec(`
CREATE TABLE IF NOT EXISTS user_settings (
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
key TEXT NOT NULL,
value TEXT NOT NULL,
updated_at TEXT DEFAULT (datetime('now')),
PRIMARY KEY (user_id, key)
)
`);
const userSettingKeys = ['currency', 'date_format', 'grace_period_days', 'notify_days_before'];
const users = db.prepare('SELECT id FROM users').all();
const getCurrent = db.prepare('SELECT value FROM settings WHERE key = ?');
const insert = db.prepare('INSERT OR IGNORE INTO user_settings (user_id, key, value) VALUES (?, ?, ?)');
for (const user of users) {
for (const key of userSettingKeys) {
const row = getCurrent.get(key);
if (row) insert.run(user.id, key, row.value);
}
}
console.log('[migration] user_settings table ensured');
}
},
{
version: 'v0.55',
description: 'user_login_history: parsed device metadata and fingerprint',
check: function() {
const cols = db.prepare('PRAGMA table_info(user_login_history)').all().map(c => c.name);
return ['browser', 'os', 'device_type', 'device_fingerprint'].every(c => cols.includes(c));
},
run: function() {
const cols = db.prepare('PRAGMA table_info(user_login_history)').all().map(c => c.name);
for (const col of ['browser', 'os', 'device_type', 'device_fingerprint']) {
if (!cols.includes(col)) db.exec(`ALTER TABLE user_login_history ADD COLUMN ${col} TEXT`);
}
console.log('[migration] user_login_history device metadata columns ensured');
}
},
{
version: 'v0.56',
description: 'bills/categories: soft-delete columns',
@ -1895,8 +1939,6 @@ function runMigrations() {
if (!hasMigrationBeenApplied(migration.version)) {
// Validate dependencies before applying
const depCheck = validateMigrationDependencies(migration, appliedVersions);
console.log(`[migration] Applying ${migration.version}: ${migration.description}`);
if (!depCheck.valid) {
console.error(`[migration-error] ${migration.version} depends on [${depCheck.missing.join(', ')}] which have not been applied. Skipping.`);
continue;

View File

@ -1,6 +1,6 @@
{
"name": "bill-tracker",
"version": "0.30.1",
"version": "0.30.2",
"description": "Monthly bill tracking system",
"main": "server.js",
"scripts": {