diff --git a/docs/VERIFICATION_CHECKLIST.md b/docs/VERIFICATION_CHECKLIST.md new file mode 100644 index 0000000..b8fbd49 --- /dev/null +++ b/docs/VERIFICATION_CHECKLIST.md @@ -0,0 +1,304 @@ +# BREEDR Verification Checklist + +## Microchip Field Fix Verification + +### ✅ Schema Files (All Correct) + +#### 1. Database Schema: `server/db/init.js` +- [x] **Line 29:** `microchip TEXT,` (no UNIQUE constraint) +- [x] **Lines 38-43:** Partial unique index created + ```sql + CREATE UNIQUE INDEX IF NOT EXISTS idx_dogs_microchip + ON dogs(microchip) + WHERE microchip IS NOT NULL + ``` + +**Status:** ✅ Correct for future installations + +--- + +#### 2. UI Form: `client/src/components/DogForm.jsx` +- [x] **Line 150:** Microchip input has NO `required` attribute +- [x] Label shows "Microchip Number" (no asterisk) +- [x] Field is truly optional in the UI + +**Status:** ✅ Correct - users can leave microchip blank + +--- + +#### 3. Migration Script: `server/db/migrate_microchip.js` +- [x] Exists and is executable +- [x] Safely migrates existing databases +- [x] Idempotent (can run multiple times) +- [x] Preserves all data during migration + +**Status:** ✅ Available for existing installations + +--- + +#### 4. Migration Helper: `migrate-now.sh` +- [x] Shell script for easy execution +- [x] Checks if container is running +- [x] Runs migration inside container +- [x] Restarts container after migration + +**Status:** ✅ User-friendly migration tool + +--- + +#### 5. Documentation: `docs/MICROCHIP_FIX.md` +- [x] Problem explanation +- [x] Solution details +- [x] Migration instructions (3 options) +- [x] Verification tests +- [x] Troubleshooting guide + +**Status:** ✅ Complete documentation + +--- + +#### 6. README: `README.md` +- [x] Migration notice at top +- [x] Link to detailed documentation +- [x] Upgrade instructions included +- [x] Recent updates section added + +**Status:** ✅ Users will see migration notice + +--- + +## For Future Installations + +### Fresh Install (No Migration Needed) + +When a user does a **fresh install** (no existing database): + +1. Container starts +2. `server/db/init.js` runs automatically +3. Database created with **correct schema** +4. Microchip field is **optional from the start** +5. No migration required ✅ + +### Existing Installation (Migration Required) + +When a user **upgrades** from an old version: + +1. Pull latest code +2. Rebuild Docker image +3. Start container +4. **Must run migration:** `docker exec -it breedr node server/db/migrate_microchip.js` +5. Restart container +6. Microchip field now optional ✅ + +--- + +## Testing Checklist + +### Test 1: Add Dog Without Microchip +```bash +curl -X POST http://localhost:3000/api/dogs \ + -H "Content-Type: application/json" \ + -d '{"name":"TestDog1","breed":"Lab","sex":"male"}' +``` +**Expected:** ✅ Success (201 Created) + +### Test 2: Add Multiple Dogs Without Microchips +```bash +curl -X POST http://localhost:3000/api/dogs \ + -H "Content-Type: application/json" \ + -d '{"name":"TestDog2","breed":"Lab","sex":"female"}' +``` +**Expected:** ✅ Success (multiple NULL values allowed) + +### Test 3: Add Dog With Microchip +```bash +curl -X POST http://localhost:3000/api/dogs \ + -H "Content-Type: application/json" \ + -d '{"name":"TestDog3","breed":"Lab","sex":"male","microchip":"123456789"}' +``` +**Expected:** ✅ Success + +### Test 4: Duplicate Microchip Should Fail +```bash +curl -X POST http://localhost:3000/api/dogs \ + -H "Content-Type: application/json" \ + -d '{"name":"TestDog4","breed":"Lab","sex":"female","microchip":"123456789"}' +``` +**Expected:** ❌ Error (UNIQUE constraint still enforced for non-NULL) + +--- + +## Database Verification + +### Check Schema Directly + +```bash +# Enter container +docker exec -it breedr sh + +# Open SQLite CLI +sqlite3 /app/data/breedr.db + +# Check table schema +.schema dogs + +# Should show: +# microchip TEXT, (no UNIQUE) + +# Check indexes +.indexes dogs + +# Should show: +# idx_dogs_microchip (partial index) + +# Verify partial index +SELECT sql FROM sqlite_master +WHERE type='index' AND name='idx_dogs_microchip'; + +# Should show: +# CREATE UNIQUE INDEX idx_dogs_microchip +# ON dogs(microchip) WHERE microchip IS NOT NULL +``` + +--- + +## Rollback Plan + +If something goes wrong: + +### Option A: Restore Backup +```bash +docker stop breedr +cp /mnt/user/appdata/breedr/breedr.db.backup \ + /mnt/user/appdata/breedr/breedr.db +docker start breedr +``` + +### Option B: Re-run Migration +```bash +docker exec -it breedr node server/db/migrate_microchip.js +docker restart breedr +``` + +### Option C: Fresh Database (Data Loss) +```bash +docker stop breedr +rm /mnt/user/appdata/breedr/breedr.db +docker start breedr +``` + +--- + +## Deployment Verification + +After deploying to production: + +- [ ] Check container logs for schema initialization +- [ ] Verify database schema with SQLite CLI +- [ ] Test adding dog without microchip via UI +- [ ] Test adding dog with microchip via UI +- [ ] Confirm no UNIQUE constraint errors +- [ ] Verify partial index exists +- [ ] Test duplicate microchip still fails + +--- + +## Common Issues + +### Issue: Still Getting UNIQUE Constraint Error + +**Cause:** Migration not run on existing database + +**Solution:** +```bash +docker exec -it breedr node server/db/migrate_microchip.js +docker restart breedr +``` + +### Issue: Migration Script Not Found + +**Cause:** Old code still in container + +**Solution:** +```bash +cd /mnt/user/appdata/breedr-build +git pull +docker build -t breedr:latest . +docker stop breedr && docker rm breedr +# Recreate container with new image +``` + +### Issue: Microchip Required in UI + +**Cause:** Browser cached old JavaScript + +**Solution:** +- Hard refresh: Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (Mac) +- Clear browser cache +- Try incognito/private window + +--- + +## File Manifest + +### Core Files (Must Be Present) +- ✅ `server/db/init.js` - Database schema (corrected) +- ✅ `server/db/migrate_microchip.js` - Migration script +- ✅ `client/src/components/DogForm.jsx` - UI form (microchip optional) +- ✅ `migrate-now.sh` - Helper script +- ✅ `docs/MICROCHIP_FIX.md` - Detailed documentation +- ✅ `docs/VERIFICATION_CHECKLIST.md` - This file +- ✅ `README.md` - Updated with migration notice + +### Validation Commands + +```bash +# Check all files exist +ls -la server/db/init.js +ls -la server/db/migrate_microchip.js +ls -la client/src/components/DogForm.jsx +ls -la migrate-now.sh +ls -la docs/MICROCHIP_FIX.md +ls -la docs/VERIFICATION_CHECKLIST.md + +# Verify microchip field in init.js +grep -n "microchip TEXT" server/db/init.js +# Should show line 29 with NO UNIQUE + +# Verify partial index +grep -A2 "idx_dogs_microchip" server/db/init.js +# Should show WHERE clause + +# Verify form has no required +grep -n 'name="microchip"' client/src/components/DogForm.jsx +# Should NOT have required attribute +``` + +--- + +## Sign-Off + +### Pre-Deployment Checklist +- [x] Schema file correct (no UNIQUE on microchip) +- [x] Partial index created (WHERE IS NOT NULL) +- [x] UI form allows empty microchip +- [x] Migration script tested +- [x] Documentation complete +- [x] README updated +- [x] Tests passing + +### Post-Deployment Checklist +- [ ] Container started successfully +- [ ] Schema verified in database +- [ ] UI allows empty microchip +- [ ] Multiple NULL values work +- [ ] Unique constraint still enforced for non-NULL +- [ ] No errors in logs + +--- + +**Last Verified:** March 8, 2026 + +**Status:** ✅ All files correct for future installations + +**Migration Required:** Only for existing databases (one-time) \ No newline at end of file diff --git a/migrate-now.sh b/migrate-now.sh new file mode 100644 index 0000000..647723b --- /dev/null +++ b/migrate-now.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# Quick migration script for microchip field fix +# Run this after deploying the updated code + +echo "======================================================" +echo "BREEDR: Microchip Field Migration" +echo "======================================================" +echo "" + +# Check if container is running +if ! docker ps | grep -q breedr; then + echo "Error: breedr container is not running" + echo "Please start the container first: docker start breedr" + exit 1 +fi + +echo "Running migration inside container..." +echo "" + +docker exec breedr node server/db/migrate_microchip.js + +if [ $? -eq 0 ]; then + echo "" + echo "======================================================" + echo "Migration completed successfully!" + echo "======================================================" + echo "" + echo "Restarting container to apply changes..." + docker restart breedr + echo "" + echo "Done! Microchip field is now optional." +else + echo "" + echo "Migration failed. Check the error above." + exit 1 +fi \ No newline at end of file diff --git a/server/routes/dogs.js b/server/routes/dogs.js index 631ecfa..9fc25ad 100644 --- a/server/routes/dogs.js +++ b/server/routes/dogs.js @@ -32,6 +32,11 @@ const upload = multer({ } }); +// Helper function to convert empty strings to null +const emptyToNull = (value) => { + return (value === '' || value === undefined) ? null : value; +}; + // GET all dogs router.get('/', (req, res) => { try { @@ -96,10 +101,21 @@ router.post('/', (req, res) => { const db = getDatabase(); + // Convert empty strings to null for optional fields const result = db.prepare(` INSERT INTO dogs (name, registration_number, breed, sex, birth_date, color, microchip, notes, photo_urls) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) - `).run(name, registration_number, breed, sex, birth_date, color, microchip, notes, '[]'); + `).run( + name, + emptyToNull(registration_number), + breed, + sex, + emptyToNull(birth_date), + emptyToNull(color), + emptyToNull(microchip), // Convert empty string to NULL + emptyToNull(notes), + '[]' + ); const dogId = result.lastInsertRowid; @@ -127,12 +143,23 @@ router.put('/:id', (req, res) => { const db = getDatabase(); + // Convert empty strings to null for optional fields db.prepare(` UPDATE dogs SET name = ?, registration_number = ?, breed = ?, sex = ?, birth_date = ?, color = ?, microchip = ?, notes = ? WHERE id = ? - `).run(name, registration_number, breed, sex, birth_date, color, microchip, notes, req.params.id); + `).run( + name, + emptyToNull(registration_number), + breed, + sex, + emptyToNull(birth_date), + emptyToNull(color), + emptyToNull(microchip), // Convert empty string to NULL + emptyToNull(notes), + req.params.id + ); // Update parent relationships db.prepare('DELETE FROM parents WHERE dog_id = ?').run(req.params.id);