docs: add testing strategy and version requirements to schema plan

- Add PostgreSQL version requirements section (min 13, rec 15)
- Add unit testing section for schema.go functions
- Add concurrent startup manual test with 5 instances
- Add debug hint in executeSchema error messages
- Add PostgreSQL troubleshooting section
- Update documentation requirements to include testing
This commit is contained in:
2026-02-10 16:40:35 -05:00
parent ffa8de3661
commit 8689dc0847
+107 -3
View File
@@ -16,6 +16,17 @@
## 📊 Technical Decisions
### PostgreSQL Version Requirements
**Minimum: PostgreSQL 13** (for `gen_random_uuid()`)
**Recommended: PostgreSQL 15** (matches `docker-compose.yml`)
**IF NOT EXISTS syntax:** PostgreSQL 9.5+ (already satisfied by minimum version)
**Rationale:**
- PostgreSQL 13 introduced `gen_random_uuid()` as a built-in function
- PostgreSQL 15 is the current stable release and matches our deployment target
- All schema features (IF NOT EXISTS, CREATE OR REPLACE FUNCTION) work with PostgreSQL 9.5+
### 1. File Structure: Single Source of Truth
**Decision:** Single `internal/database/schema.go` file referencing existing `database/schema/schema.sql`.
@@ -300,6 +311,7 @@ func executeSchema(ctx context.Context, db *pgxpool.Pool) error {
_, err = tx.Exec(ctx, SchemaFile)
if err != nil {
log.Printf("HINT: Run manually to debug: psql -h localhost -U postgres -d bookhoard -f database/schema/schema.sql")
return fmt.Errorf("schema execution failed: %w", err)
}
@@ -414,6 +426,53 @@ ls -la ../../database/schema/schema.sql
# Should show the file exists at the correct relative location
```
#### Step 2.3: Add Unit Tests for schema.go
Create `internal/database/schema_test.go`:
```go
package database
import (
"context"
"testing"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/stretchr/testify/assert"
)
func TestParseTableNames(t *testing.T) {
tables, err := parseTableNames()
assert.NoError(t, err)
assert.Greater(t, len(tables), 20, "Should parse at least 20 tables")
// Verify critical tables are detected
tableMap := make(map[string]bool)
for _, table := range tables {
tableMap[table] = true
}
assert.True(t, tableMap["users"], "Should find 'users' table")
assert.True(t, tableMap["libraries"], "Should find 'libraries' table")
assert.True(t, tableMap["media_items"], "Should find 'media_items' table")
}
func TestGenerateLockID(t *testing.T) {
result := generateLockID("bookhoard:schema:init")
assert.Equal(t, int64(7804706162000639061), result, "FNV-1a hash must match expected value")
}
func TestVerifyTables_MissingTables(t *testing.T) {
// This would require a mock database or test setup
// For now, skip or implement with pgxpool mock
t.Skip("Requires database connection - implement in integration tests")
}
```
Run tests with:
```bash
go test ./internal/database -v
```
---
### Phase 3: Integrate into main.go
@@ -481,6 +540,7 @@ func main() {
- [ ] No schema file duplication (single source of truth)
- [ ] Verifies critical functions exist, not just tables
- [ ] Provides clear error messages for missing schema components
- [ ] Includes debug hint when schema execution fails (psql command)
**Phase 3 Verification:**
- [ ] `cmd/server/main.go` compiles without errors
@@ -491,7 +551,7 @@ func main() {
**Integration Testing:**
- [ ] Fresh database initializes correctly
- [ ] Existing database doesn't break
- [ ] Concurrent startup works with advisory locks
- [ ] Concurrent startup works with advisory locks (manual test below)
- [ ] Partial state recovers successfully
- [ ] TestKoboInitialization passes
- [ ] All integration tests pass
@@ -502,6 +562,32 @@ func main() {
- [ ] `go build ./...` succeeds for entire project
- [ ] `bash scripts/verify-guidelines.sh` passes (0 errors)
**Concurrent Startup Test (Manual):**
```bash
# Test advisory locks work correctly with multiple instances
# Start 5 instances simultaneously
for i in {1..5}; do
podman compose -p test$i up -d app
sleep 0.5 # Stagger starts slightly
done
# Wait 10 seconds for all to initialize
sleep 10
# Check all logs for successful initialization
for i in {1..5}; do
echo "=== Instance $i ==="
podman logs test$i_bookhoard_app 2>&1 | grep "schema initialization complete"
done
# Cleanup
for i in {1..5}; do
podman compose -p test$i down
done
```
**Expected result:** All 5 instances should show "schema initialization complete" in logs, proving advisory locks prevent race conditions.
---
## 📈 Expected Outcomes
@@ -585,6 +671,23 @@ If new version has schema issues:
## 📞 Support
### PostgreSQL Version Issues
If you see errors about `gen_random_uuid()` not existing:
```bash
# Check PostgreSQL version
podman exec bookhoard_db psql --version
# Should be 13.0 or higher
```
If using an older PostgreSQL version, update `docker-compose.yml`:
```yaml
db:
image: postgres:15-alpine # Or postgres:13-alpine minimum
```
### Troubleshooting
If issues occur:
### Check logs first:
@@ -623,8 +726,9 @@ podman compose up -d
## 📚 Documentation
Create documentation explaining the automatic schema initialization:
- **docs/contributing/database-schema.md** - How schema initialization works, how to modify schema safely
- **README.md** - Add "Database Initialization" section documenting first-run behavior
- **docs/contributing/database-schema.md** - How schema initialization works, how to modify schema safely, PostgreSQL version requirements
- **README.md** - Add "Database Initialization" section documenting first-run behavior and PostgreSQL version requirements
- **internal/database/schema_test.go** - Unit tests for schema parsing and verification functions
---