fix(saas): migration robusta — recria state e anchor_session se schema legado, índices user_id após ALTER
This commit is contained in:
parent
85b60a800c
commit
a80adc7bdf
1 changed files with 59 additions and 5 deletions
|
|
@ -59,7 +59,6 @@ db.exec(`
|
|||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_media_parent ON media(parent_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_media_user ON media(user_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS anchor_session (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
|
|
@ -101,7 +100,6 @@ db.exec(`
|
|||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_shares_expires ON shares(expires_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_shares_user ON shares(user_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS share_positions (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
|
|
@ -133,18 +131,74 @@ try {
|
|||
}
|
||||
} catch (e) { /* ignore */ }
|
||||
|
||||
// ===== Migração multi-tenant: adicionar user_id em tabelas existentes =====
|
||||
// Idempotente: roda toda startup, só ALTER se coluna não existir
|
||||
// ===== Migração multi-tenant =====
|
||||
// 1) Tabelas que mudaram PRIMARY KEY (state, anchor_session): se schema antigo detectado,
|
||||
// recriar limpo. Sem perda de dados crítica neste momento (deploy inicial).
|
||||
function recreateIfLegacy(table, newSchema) {
|
||||
try {
|
||||
const cols = db.prepare(`PRAGMA table_info(${table})`).all();
|
||||
if (cols.length === 0) return; // tabela ainda não existe (CREATE TABLE pegou o schema novo)
|
||||
const hasUserId = cols.some(c => c.name === 'user_id');
|
||||
const idCol = cols.find(c => c.name === 'id');
|
||||
// Schema antigo: id é PRIMARY KEY mas NÃO é AUTOINCREMENT (rowid alias com CHECK constraint)
|
||||
const isLegacyPK = idCol && idCol.pk === 1 && !cols.some(c => c.type === 'INTEGER' && c.pk && c.name === 'id' && (c.dflt_value || '').toString().includes('AUTO'));
|
||||
if (!hasUserId || isLegacyPK) {
|
||||
console.log(`[migration] recreating ${table} (legacy schema detected)`);
|
||||
db.exec(`DROP TABLE IF EXISTS ${table}; ${newSchema}`);
|
||||
}
|
||||
} catch (e) { console.warn(`[migration] recreate ${table}:`, e.message); }
|
||||
}
|
||||
|
||||
recreateIfLegacy('state', `
|
||||
CREATE TABLE state (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL DEFAULT 1,
|
||||
data TEXT NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE(user_id),
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
recreateIfLegacy('anchor_session', `
|
||||
CREATE TABLE anchor_session (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL DEFAULT 1,
|
||||
active INTEGER NOT NULL DEFAULT 0,
|
||||
boat_name TEXT,
|
||||
anchor_lat REAL,
|
||||
anchor_lng REAL,
|
||||
radius INTEGER,
|
||||
started_at INTEGER,
|
||||
last_heartbeat INTEGER,
|
||||
last_lat REAL,
|
||||
last_lng REAL,
|
||||
last_distance REAL,
|
||||
alarm_fired INTEGER DEFAULT 0,
|
||||
UNIQUE(user_id),
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
|
||||
// 2) Tabelas que só ganharam coluna user_id: ALTER TABLE ADD COLUMN
|
||||
function ensureUserIdColumn(table) {
|
||||
try {
|
||||
const cols = db.prepare(`PRAGMA table_info(${table})`).all();
|
||||
if (cols.length === 0) return;
|
||||
if (!cols.some(c => c.name === 'user_id')) {
|
||||
db.exec(`ALTER TABLE ${table} ADD COLUMN user_id INTEGER NOT NULL DEFAULT 1`);
|
||||
console.log(`[migration] added user_id to ${table}`);
|
||||
}
|
||||
} catch (e) { console.warn(`[migration] ${table}:`, e.message); }
|
||||
}
|
||||
['state', 'media', 'anchor_session', 'alarm_log', 'shares', 'audit_log'].forEach(ensureUserIdColumn);
|
||||
['media', 'alarm_log', 'shares', 'audit_log'].forEach(ensureUserIdColumn);
|
||||
|
||||
// 3) Índices em user_id rodam DEPOIS do ALTER TABLE (senão "no such column")
|
||||
try {
|
||||
db.exec(`
|
||||
CREATE INDEX IF NOT EXISTS idx_media_user ON media(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_shares_user ON shares(user_id);
|
||||
`);
|
||||
} catch (e) { console.warn('[migration] user_id indexes:', e.message); }
|
||||
|
||||
// Garante user default (id=1, Karlão) — donos de dados pré-multi-tenant
|
||||
function ensureDefaultUser() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue