Major refactoring milestone - migrate all routes from main.go to internal/router/ package: ## Changes ### cmd/server/main.go - Reduced from 858 lines to 163 lines (81% reduction) - Removed all inline route definitions - Added router.RegisterRoutes() call with full config - Clean separation: setup → router registration → server start ### internal/router/ package Created comprehensive route organization: - router.go: Main router setup and JWT middleware - auth.go: Authentication routes (login, register, profile, etc.) - library.go: Library management routes - device.go: Device registration and management - sync.go: KOReader/Kobo sync + book matching + WebSocket - media.go: Media download, shelves, bulk operations - conflicts.go: Conflict resolution routes - analytics.go: Analytics API routes - queue.go: Sync queue management - opds.go: OPDS feed routes - frontend.go: SSR pages (/login, /admin, /dashboard, etc.) - docs.go: Documentation routes - helpers.go: Template rendering helpers ## Verification ✅ All 26 guideline checks pass ✅ Code compiles successfully ✅ Zero API behavior changes (100% compatible) ✅ Follows Go standard project layout ## Breaking Changes None - API compatibility fully maintained
13 KiB
Router Refactoring Execution Plan
Objective
Refactor 858-line cmd/server/main.go by migrating route definitions to internal/router/ package while maintaining 100% API compatibility and passing all verification tests.
Current State
- ✅
internal/router/package created with 7 files - ✅ Route stubs implemented for: auth, library, device, frontend, docs
- ❌ Router package NOT integrated (never called from main.go)
- ❌ All routes still defined in main.go (duplicates)
- ⚠️ main.go: 858 lines (target: ~200 lines)
Success Criteria
- All 26 verification checks pass (
scripts/verify-guidelines.sh) - All Go tests pass (
go test ./...) - All Bruno/curl API tests pass
- No API behavior changes (routes, handlers, responses identical)
- main.go reduced to ~200 lines
- Code compiles without errors
- Application runs successfully (containers start, health check returns 200)
Migration Strategy: Incremental with Rollback Safety
Phase 1: Create Safety Branch ✅
- Create branch
continue-router-refactor - Router package structure exists
Phase 2: Integrate Router Package (DO THIS FIRST)
Step 2.1: Add Router Import and Config
File: cmd/server/main.go
Add to imports:
"bookhoard/internal/router"
Add after line 130 (after rateLimiter initialization):
// ========================================================================
// ROUTER REGISTRATION - Migrate routes to internal/router/ package
// ========================================================================
routerConfig := &router.Config{
Echo: e,
Queries: queries,
Cfg: cfg,
DBPool: dbPool,
AuthHandler: authHandler,
LibraryHandler: libraryHandler,
DeviceHandler: deviceHandler,
KOReaderHandler: koreaderHandler,
WSHandler: wsHandler,
ConflictHandler: conflictHandler,
AnalyticsHandler: analyticsHandler,
QueueHandler: queueHandler,
CollectionHandler: collectionHandler,
OPDSHandler: opdsHandler,
ConnManager: connManager,
QueueProcessor: queueProcessor,
DeviceAuthMiddleware: deviceAuthMiddleware,
LoginTracker: loginAttemptTracker,
}
Step 2.2: Call Router.RegisterRoutes()
Add immediately after routerConfig:
router.RegisterRoutes(routerConfig)
IMPORTANT: Do NOT remove any routes from main.go yet!
Step 2.3: Test Compilation
go build ./cmd/server
Expected: Should compile (routes will be duplicated but that's OK temporarily)
Step 2.4: Test Application
# Stop containers if running
podman-compose down
# Rebuild and start
podman-compose up -d --build
# Wait for startup
sleep 10
# Test health endpoint
curl -s http://localhost:8765/health | jq .
# Test frontend
curl -s http://localhost:8765/ | grep -o "<title>.*</title>"
# Run verification
bash scripts/verify-guidelines.sh
Expected: All should pass (duplicate routes don't break Echo)
ROLLBACK IF: Compilation fails or health check returns non-200
git checkout -- cmd/server/main.go
Phase 3: Remove Duplicate Routes from main.go
⚠️ CRITICAL: Remove ONE route group at a time, test after each removal!
Step 3.1: Remove Auth Routes (lines 132-191)
Lines to remove: From // Auth routes to // JWT middleware for protected routes (before jwtMiddleware creation)
Actually: Keep jwtMiddleware creation (it's used by other routes) Remove: auth POST endpoints and protected auth routes that are now in router/auth.go
Test after removal:
go build ./cmd/server
podman-compose up -d --build
sleep 10
# Test auth endpoints
curl -X POST http://localhost:8765/api/auth/register -H "Content-Type: application/json" -d '{"email":"test@test.com","username":"test","password":"Test123!"}'
Step 3.2: Remove Library Routes (lines 192-235)
Lines to remove: From // Library management routes to visibility routes
Test after removal:
go build ./cmd/server
podman-compose up -d --build
# Test library endpoints
curl -s http://localhost:8765/api/libraries/types | jq .
Step 3.3: Remove Device Registration Routes (lines 236-239)
Lines to remove: Device register and status endpoints
Test after removal:
go build ./cmd/server
# Device registration test
Step 3.4: Remove Frontend Routes (lines 627-823)
Lines to remove: From // FRONTEND ROUTES to before // HEALTH CHECK
Test after removal:
go build ./cmd/server
curl -s http://localhost:8765/ | grep -o "<title>.*</title>"
Step 3.5: Remove Health Check (lines 824-844)
Lines to remove: From // HEALTH CHECK to before // DOCUMENTATION ROUTES
Test after removal:
go build ./cmd/server
curl -s http://localhost:8765/health | jq .
Step 3.6: Remove Documentation Routes (lines 845-858)
Lines to remove: From // DOCUMENTATION ROUTES to end
Test after removal:
go build ./cmd/server
curl -s http://localhost:8765/docs | grep -o "<title>.*</title>"
Phase 4: Implement Remaining Router Stubs
Step 4.1: Create router/sync.go
# Create file with sync routes (KOReader, Kobo, websocket)
# Copy sync route definitions from main.go
Routes to migrate:
- KOReader sync routes (device authentication required)
- Kobo sync routes (device authentication required)
- Book matching routes
- WebSocket endpoint
Step 4.2: Create router/media.go
Routes to migrate:
- Media item routes (download, shelf management)
- Bulk book operations
Step 4.3: Create router/analytics.go
Routes to migrate:
- Analytics routes (API + SSR)
Step 4.4: Create router/queue.go
Routes to migrate:
- Sync queue management routes (API + SSR)
Step 4.5: Create router/opds.go
Routes to migrate:
- OPDS routes (public - device authentication optional)
Step 4.6: Update router/collections.go
Routes to migrate:
- Collection routes (API + SSR)
Phase 5: Complete Migration
For each new route file created in Phase 4:
- Add
registerXYZRoutes(cfg *Config)function - Call it from
router.RegisterRoutes()in router.go - Remove corresponding routes from main.go
- Test with:
go build ./cmd/server - Test with:
podman-compose up -d --build - Test specific endpoints with curl
- Run:
bash scripts/verify-guidelines.sh
Phase 6: Final Verification
Step 6.1: Full Test Suite
# Compilation
go build ./cmd/server
go test ./...
# Verification
bash scripts/verify-guidelines.sh
# Container test
podman-compose down
podman-compose up -d --build
sleep 15
# Critical endpoint tests
curl -s http://localhost:8765/health | jq .
curl -s http://localhost:8765/ | grep -o "<title>.*</title>"
curl -s http://localhost:8765/api/libraries/types | jq .
curl -s http://localhost:8765/docs | grep -o "<title>.*</title>"
# Run Bruno tests (if available)
# bruno test ...
Step 6.2: Verify main.go Size
wc -l cmd/server/main.go
Expected: ~200 lines (down from 858)
Step 6.3: Code Review Checklist
- No routes duplicated (each route defined once)
- All route groups use JWT middleware correctly
- Admin middleware applied where needed
- Rate limiting applied to auth endpoints
- No compilation errors
- All imports used
- Consistent code style with rest of codebase
Phase 7: Commit and Push
Step 7.1: Review Changes
git diff cmd/server/main.go | head -100
git diff internal/router/
Step 7.2: Run Verification
bash scripts/verify-guidelines.sh
Step 7.3: Commit Changes
git add cmd/server/main.go internal/router/
git commit -m "refactor: complete router package migration
- Migrate all routes from main.go to internal/router/ package
- Reduce main.go from 858 lines to ~200 lines
- Create separate files for route groups:
- auth.go: Authentication routes
- library.go: Library management
- device.go: Device registration & management
- sync.go: KOReader/Kobo/WebSocket sync routes
- media.go: Media items and bulk operations
- analytics.go: Analytics API + SSR
- queue.go: Sync queue management
- opds.go: OPDS feeds
- collections.go: Collection management
- frontend.go: SSR pages and health check
- docs.go: Documentation routes
- All 26 verification checks pass
- All API endpoints tested and working
- Zero API behavior changes (100% compatible)
- Follows Go standard project layout
Breaking Change: None - API compatibility maintained"
Step 7.4: Push
git push origin continue-router-refactor
Rollback Procedures
If compilation fails at any point:
git checkout -- cmd/server/main.go
# Or
git reset --hard HEAD
If tests fail:
- Check which endpoint failed
- Verify route is registered in router package
- Check handler method exists
- Check middleware is applied correctly
- Review error logs:
podman logs bookhoard
If verification fails:
- Check which specific check failed
- Fix the issue
- Re-run verification
- Commit the fix separately
Testing Commands (Quick Reference)
# Compile
go build ./cmd/server
# Verification
bash scripts/verify-guidelines.sh
# Unit tests
go test ./...
# Rebuild containers
podman-compose down
podman-compose up -d --build
# Wait for startup
sleep 10
# Health check
curl -s http://localhost:8765/health | jq .
# Frontend
curl -s http://localhost:8765/ | grep -o "<title>.*</title>"
# Auth endpoint test
curl -X POST http://localhost:8765/api/auth/login \
-H "Content-Type: application/json" \
-d '{"login":"test","password":"wrong"}'
# Library types
curl -s http://localhost:8765/api/libraries/types | jq .
# Documentation
curl -s http://localhost:8765/docs | grep -o "<title>.*</title>"
# Check container logs
podman logs bookhoard | tail -30
# Check container status
podman ps
Files Created/Modified
Created:
internal/router/router.go- Main router configurationinternal/router/auth.go- Authentication routesinternal/router/library.go- Library management routesinternal/router/device.go- Device routesinternal/router/frontend.go- Frontend SSR routesinternal/router/docs.go- Documentation routesinternal/router/helpers.go- Template helpersinternal/router/sync.go- Sync routes (Phase 4)internal/router/media.go- Media routes (Phase 4)internal/router/analytics.go- Analytics routes (Phase 4)internal/router/queue.go- Queue routes (Phase 4)internal/router/opds.go- OPDS routes (Phase 4)internal/router/collections.go- Collection routes (Phase 4)
Modified:
cmd/server/main.go- Reduced from 858 to ~200 lines
Estimated Time
- Phase 2: 15 minutes (integration and initial testing)
- Phase 3: 45 minutes (incremental route removal and testing)
- Phase 4: 90 minutes (implement remaining route groups)
- Phase 5: 30 minutes (complete migration)
- Phase 6: 30 minutes (final verification)
- Phase 7: 15 minutes (commit and push)
Total: ~4 hours
Notes for AI Assistants
- Always test after each change - don't batch multiple route removals
- Keep main.go functional - it should compile at all times
- Verify API compatibility - routes must respond identically
- Use git commits - commit after each successful phase to enable rollback
- Check logs - if something fails, check
podman logs bookhoard - Verification script is authority - if it fails, fix before continuing
- Echo allows duplicate routes - temporarily OK during migration
- Middleware order matters - maintain exact middleware application order
- Import statements - remove unused imports after route removal
- Handler methods - verify handler methods exist before calling them
Troubleshooting
Error: "route already registered"
- Cause: Route defined multiple times
- Fix: Remove from main.go, keep in router package only
Error: "handler method not found"
- Cause: Typo in method name or handler not initialized in Config
- Fix: Check method name in handler file, ensure handler is passed in Config
Error: "undefined: jwtMiddleware"
- Cause: JWT middleware not created in that route file
- Fix: Add JWT middleware creation at top of register function
Error: "404 on previously working endpoint"
- Cause: Route not registered or middleware blocking access
- Fix: Check route is registered, check middleware conditions
Health check returns 503
- Cause: Database not connected or dbPool not passed to router
- Fix: Ensure DBPool is set in routerConfig
Verification fails with "Build failed"
- Cause: Compilation error
- Fix: Run
go build ./cmd/serverto see specific error
Success Metrics
Before:
cmd/server/main.go: 858 lines- All routes defined inline
- Mixed concerns (setup + routes + server start)
After:
cmd/server/main.go: ~200 lines- Routes organized by domain in
internal/router/ - Clear separation: setup → router registration → server start
- Follows Go standard project layout
- Easy to maintain and extend