feature/ui-redesign #5

Merged
jason merged 3 commits from feature/ui-redesign into master 2026-03-08 23:56:29 -05:00
3 changed files with 370 additions and 2 deletions

View File

@@ -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)

37
migrate-now.sh Normal file
View File

@@ -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

View File

@@ -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 // GET all dogs
router.get('/', (req, res) => { router.get('/', (req, res) => {
try { try {
@@ -96,10 +101,21 @@ router.post('/', (req, res) => {
const db = getDatabase(); const db = getDatabase();
// Convert empty strings to null for optional fields
const result = db.prepare(` const result = db.prepare(`
INSERT INTO dogs (name, registration_number, breed, sex, birth_date, color, microchip, notes, photo_urls) INSERT INTO dogs (name, registration_number, breed, sex, birth_date, color, microchip, notes, photo_urls)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) 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; const dogId = result.lastInsertRowid;
@@ -127,12 +143,23 @@ router.put('/:id', (req, res) => {
const db = getDatabase(); const db = getDatabase();
// Convert empty strings to null for optional fields
db.prepare(` db.prepare(`
UPDATE dogs UPDATE dogs
SET name = ?, registration_number = ?, breed = ?, sex = ?, SET name = ?, registration_number = ?, breed = ?, sex = ?,
birth_date = ?, color = ?, microchip = ?, notes = ? birth_date = ?, color = ?, microchip = ?, notes = ?
WHERE id = ? 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 // Update parent relationships
db.prepare('DELETE FROM parents WHERE dog_id = ?').run(req.params.id); db.prepare('DELETE FROM parents WHERE dog_id = ?').run(req.params.id);