# BREEDR Database Schema ## Overview This document describes the clean database schema for BREEDR. **NO migrations** - fresh installs create the correct schema automatically. ## Schema Design ### Core Principle: Parents Table Approach The `dogs` table **does NOT have sire/dam columns**. Parent relationships are stored in the separate `parents` table. This design: - Keeps the schema clean and normalized - Allows flexible parent relationships - Supports future extensions (multiple sires, surrogates, etc.) ## Tables ### dogs Core registry for all dogs. ```sql CREATE TABLE dogs ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, registration_number TEXT UNIQUE, breed TEXT NOT NULL, sex TEXT NOT NULL CHECK(sex IN ('male', 'female')), birth_date DATE, color TEXT, microchip TEXT, photo_urls TEXT, -- JSON array notes TEXT, litter_id INTEGER, -- Links to litters table is_active INTEGER DEFAULT 1, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (litter_id) REFERENCES litters(id) ON DELETE SET NULL ); ``` **Important:** NO `sire_id` or `dam_id` columns! ### parents Stores sire/dam relationships. ```sql CREATE TABLE parents ( id INTEGER PRIMARY KEY AUTOINCREMENT, dog_id INTEGER NOT NULL, -- The puppy parent_id INTEGER NOT NULL, -- The parent parent_type TEXT NOT NULL CHECK(parent_type IN ('sire', 'dam')), FOREIGN KEY (dog_id) REFERENCES dogs(id) ON DELETE CASCADE, FOREIGN KEY (parent_id) REFERENCES dogs(id) ON DELETE CASCADE, UNIQUE(dog_id, parent_type) -- One sire, one dam per dog ); ``` ### litters Breeding records and litter tracking. ```sql CREATE TABLE litters ( id INTEGER PRIMARY KEY AUTOINCREMENT, sire_id INTEGER NOT NULL, dam_id INTEGER NOT NULL, breeding_date DATE NOT NULL, whelping_date DATE, puppy_count INTEGER DEFAULT 0, notes TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (sire_id) REFERENCES dogs(id) ON DELETE CASCADE, FOREIGN KEY (dam_id) REFERENCES dogs(id) ON DELETE CASCADE ); ``` ### health_records Health tests, vaccinations, exams, treatments. ```sql CREATE TABLE health_records ( id INTEGER PRIMARY KEY AUTOINCREMENT, dog_id INTEGER NOT NULL, record_type TEXT NOT NULL CHECK(record_type IN ('test', 'vaccination', 'exam', 'treatment', 'certification')), test_name TEXT, test_date DATE NOT NULL, result TEXT, document_url TEXT, notes TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (dog_id) REFERENCES dogs(id) ON DELETE CASCADE ); ``` ### heat_cycles Female heat cycle tracking for breeding timing. ```sql CREATE TABLE heat_cycles ( id INTEGER PRIMARY KEY AUTOINCREMENT, dog_id INTEGER NOT NULL, start_date DATE NOT NULL, end_date DATE, progesterone_peak_date DATE, breeding_date DATE, breeding_successful INTEGER DEFAULT 0, notes TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (dog_id) REFERENCES dogs(id) ON DELETE CASCADE ); ``` ### traits Genetic trait tracking and inheritance. ```sql CREATE TABLE traits ( id INTEGER PRIMARY KEY AUTOINCREMENT, dog_id INTEGER NOT NULL, trait_category TEXT NOT NULL, trait_name TEXT NOT NULL, trait_value TEXT NOT NULL, inherited_from INTEGER, -- Parent dog ID notes TEXT, FOREIGN KEY (dog_id) REFERENCES dogs(id) ON DELETE CASCADE, FOREIGN KEY (inherited_from) REFERENCES dogs(id) ON DELETE SET NULL ); ``` ## API Usage ### Creating a Dog with Parents ```javascript POST /api/dogs { "name": "Puppy Name", "breed": "Breed Name", "sex": "male", "sire_id": 5, // Parent male dog ID "dam_id": 8, // Parent female dog ID "litter_id": 2 // Optional: link to litter } ``` The API route automatically: 1. Inserts the dog into `dogs` table (without sire/dam columns) 2. Creates entries in `parents` table linking to sire and dam ### Querying Parents ```sql -- Get a dog's parents SELECT p.parent_type, d.* FROM parents p JOIN dogs d ON p.parent_id = d.id WHERE p.dog_id = ?; -- Get a dog's offspring SELECT d.* FROM dogs d JOIN parents p ON d.id = p.dog_id WHERE p.parent_id = ?; ``` ## Fresh Install For a fresh install: 1. **Delete the old database** (if upgrading): ```bash rm data/breedr.db ``` 2. **Start the server** - it will create the correct schema automatically: ```bash npm run dev ``` 3. **Verify the schema**: ```bash sqlite3 data/breedr.db ".schema dogs" ``` You should see `litter_id` but **NO** `sire_id` or `dam_id` columns. ## Troubleshooting ### "no such column: weight" or "no such column: sire_id" **Solution:** Your database has an old schema. Delete it and let the app recreate it: ```bash rm data/breedr.db npm run dev ``` ### Parent relationships not saving Check server logs. You should see: ``` ✓ Dog inserted with ID: 123 Adding sire relationship: dog 123 -> sire 5 ✓ Sire relationship added Adding dam relationship: dog 123 -> dam 8 ✓ Dam relationship added ``` If relationships aren't being created, check that `sire_id` and `dam_id` are being sent in the API request. ## Database Files - `server/db/init.js` - Creates clean schema, no migrations - `server/routes/dogs.js` - Handles parent relationships via `parents` table - `server/index.js` - Initializes database on startup **NO MIGRATIONS!** The init file is the source of truth.