diff --git a/server/db/init.js b/server/db/init.js index bc7d937..44685f4 100644 --- a/server/db/init.js +++ b/server/db/init.js @@ -16,28 +16,37 @@ function initDatabase() { // ── Dogs ──────────────────────────────────────────────────────────── db.exec(` CREATE TABLE IF NOT EXISTS dogs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - registration_number TEXT, - breed TEXT NOT NULL, - sex TEXT NOT NULL CHECK(sex IN ('male', 'female')), - birth_date TEXT, - color TEXT, - microchip TEXT, - litter_id INTEGER, - is_active INTEGER DEFAULT 1, - is_champion INTEGER DEFAULT 0, - photo_urls TEXT DEFAULT '[]', - notes TEXT, - created_at TEXT DEFAULT (datetime('now')), - updated_at TEXT DEFAULT (datetime('now')) + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + registration_number TEXT, + breed TEXT NOT NULL, + sex TEXT NOT NULL CHECK(sex IN ('male', 'female')), + birth_date TEXT, + color TEXT, + microchip TEXT, + litter_id INTEGER, + is_active INTEGER DEFAULT 1, + is_champion INTEGER DEFAULT 0, + chic_number TEXT, + age_at_death TEXT, + cause_of_death TEXT, + photo_urls TEXT DEFAULT '[]', + notes TEXT, + created_at TEXT DEFAULT (datetime('now')), + updated_at TEXT DEFAULT (datetime('now')) ) `); - // migrate: add is_champion if missing (safe on existing DBs) - try { - db.exec(`ALTER TABLE dogs ADD COLUMN is_champion INTEGER DEFAULT 0`); - } catch (_) { /* column already exists */ } + // migrate: add columns if missing (safe on existing DBs) + const dogMigrations = [ + ['is_champion', 'INTEGER DEFAULT 0'], + ['chic_number', 'TEXT'], + ['age_at_death', 'TEXT'], + ['cause_of_death', 'TEXT'], + ]; + for (const [col, def] of dogMigrations) { + try { db.exec(`ALTER TABLE dogs ADD COLUMN ${col} ${def}`); } catch (_) { /* already exists */ } + } // ── Parents ───────────────────────────────────────────────────────── db.exec(` @@ -51,24 +60,24 @@ function initDatabase() { ) `); - // ── Breeding Records ──────────────────────────────────────────────── + // ── Breeding Records ───────────────────────────────────────────────── db.exec(` CREATE TABLE IF NOT EXISTS breeding_records ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - sire_id INTEGER NOT NULL, - dam_id INTEGER NOT NULL, - breeding_date TEXT, - due_date TEXT, - conception_method TEXT CHECK(conception_method IN ('natural', 'ai', 'frozen', 'surgical')), - notes TEXT, - created_at TEXT DEFAULT (datetime('now')), - updated_at TEXT DEFAULT (datetime('now')), + id INTEGER PRIMARY KEY AUTOINCREMENT, + sire_id INTEGER NOT NULL, + dam_id INTEGER NOT NULL, + breeding_date TEXT, + due_date TEXT, + conception_method TEXT CHECK(conception_method IN ('natural', 'ai', 'frozen', 'surgical')), + notes TEXT, + created_at TEXT DEFAULT (datetime('now')), + updated_at TEXT DEFAULT (datetime('now')), FOREIGN KEY (sire_id) REFERENCES dogs(id), FOREIGN KEY (dam_id) REFERENCES dogs(id) ) `); - // ── Litters ───────────────────────────────────────────────────────── + // ── Litters ────────────────────────────────────────────────────────── db.exec(` CREATE TABLE IF NOT EXISTS litters ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -89,21 +98,81 @@ function initDatabase() { ) `); - // ── Health Records ────────────────────────────────────────────────── + // ── Health Records (OFA-extended) ──────────────────────────────────── + // test_type values: hip_ofa | hip_pennhip | elbow_ofa | heart_ofa | + // heart_echo | eye_caer | thyroid_ofa | dna_panel | vaccination | + // other + // ofa_result values: excellent | good | fair | borderline | mild | + // moderate | severe | normal | abnormal | pass | fail | carrier | + // clear | affected | n/a db.exec(` CREATE TABLE IF NOT EXISTS health_records ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - dog_id INTEGER NOT NULL, - record_type TEXT NOT NULL, - date TEXT NOT NULL, - title TEXT NOT NULL, - description TEXT, - vet_name TEXT, - notes TEXT, - result TEXT, - next_due TEXT, - created_at TEXT DEFAULT (datetime('now')), - updated_at TEXT DEFAULT (datetime('now')), + id INTEGER PRIMARY KEY AUTOINCREMENT, + dog_id INTEGER NOT NULL, + record_type TEXT NOT NULL, + test_type TEXT, + test_name TEXT, + test_date TEXT NOT NULL, + ofa_result TEXT, + ofa_number TEXT, + performed_by TEXT, + expires_at TEXT, + document_url TEXT, + result TEXT, + vet_name TEXT, + next_due TEXT, + notes TEXT, + created_at TEXT DEFAULT (datetime('now')), + updated_at TEXT DEFAULT (datetime('now')), + FOREIGN KEY (dog_id) REFERENCES dogs(id) + ) + `); + + // migrate: add OFA-specific columns if missing + const healthMigrations = [ + ['test_type', 'TEXT'], + ['ofa_result', 'TEXT'], + ['ofa_number', 'TEXT'], + ['performed_by', 'TEXT'], + ['expires_at', 'TEXT'], + ['document_url', 'TEXT'], + ]; + for (const [col, def] of healthMigrations) { + try { db.exec(`ALTER TABLE health_records ADD COLUMN ${col} ${def}`); } catch (_) { /* already exists */ } + } + + // ── Genetic Tests (DNA Panel) ───────────────────────────────────────── + // result values: clear | carrier | affected | not_tested + // marker examples: PRA1, PRA2, prcd-PRA, GR-PRA1, GR-PRA2, ICH1, + // ICH2, NCL, DM, MD + db.exec(` + CREATE TABLE IF NOT EXISTS genetic_tests ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + dog_id INTEGER NOT NULL, + test_provider TEXT, + marker TEXT NOT NULL, + result TEXT NOT NULL CHECK(result IN ('clear', 'carrier', 'affected', 'not_tested')), + test_date TEXT, + document_url TEXT, + notes TEXT, + created_at TEXT DEFAULT (datetime('now')), + updated_at TEXT DEFAULT (datetime('now')), + FOREIGN KEY (dog_id) REFERENCES dogs(id) + ) + `); + + // ── Cancer History ─────────────────────────────────────────────────── + db.exec(` + CREATE TABLE IF NOT EXISTS cancer_history ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + dog_id INTEGER NOT NULL, + cancer_type TEXT, + age_at_diagnosis TEXT, + age_at_death TEXT, + cause_of_death TEXT, + notes TEXT, + created_at TEXT DEFAULT (datetime('now')), + updated_at TEXT DEFAULT (datetime('now')), FOREIGN KEY (dog_id) REFERENCES dogs(id) ) `); @@ -126,7 +195,6 @@ function initDatabase() { ) `); - // migrate: add new kennel columns if missing (safe on existing DBs) const kennelCols = [ ['kennel_name', "TEXT DEFAULT 'BREEDR'"], ['kennel_tagline', 'TEXT'], @@ -139,12 +207,9 @@ function initDatabase() { ['owner_name', 'TEXT'], ]; for (const [col, def] of kennelCols) { - try { - db.exec(`ALTER TABLE settings ADD COLUMN ${col} ${def}`); - } catch (_) { /* already exists */ } + try { db.exec(`ALTER TABLE settings ADD COLUMN ${col} ${def}`); } catch (_) { /* already exists */ } } - // Seed a default settings row if none exists const existing = db.prepare('SELECT id FROM settings LIMIT 1').get(); if (!existing) { db.prepare(`INSERT INTO settings (kennel_name) VALUES (?)`).run('BREEDR');