Add explicit check to verify target user exists in database before
attempting deletion. Previously, the handler would return 200 OK when
trying to delete non-existent users.
Changes:
- Add userFound flag to track if target user was found in user list
- Explicitly check pgtype.UUID.Bytes against all users' IDs
- Return 404 Not Found if user doesn't exist (before last admin check)
- Supports both JSON and HTML (HTMX) response formats
This fixes the failing test:
- TestDeleteUserConsolidated/DELETE_/api/auth/profile/:id_-_Delete_non-existent_user
The check uses the existing ListUsers result, so no additional database
query is required. The pgtype.UUID.Bytes comparison ensures exact
16-byte UUID matching.
Implement DeleteUser, ResetUserPassword, and UpdateUserAdmin handlers.
Update collections handler to check soft-deleted users. Update dashboard
service to exclude deleted users from statistics.
- Add SessionDuration constant (7 days) and SessionDurationSec computed value
- Update JWT token expiration to use SessionDuration instead of 1 hour
- Update register/login cookie MaxAge to use SessionDurationSec (604800)
- Update register/login API response ExpiresIn to use SessionDurationSec
- Update refresh token endpoint ExpiresIn to use SessionDurationSec
- Remove redundant client-side document.cookie lines from login/register
- Add TODO comment for HTTPS cookie Secure flag
This provides Google-like persistent sessions with a single source of truth
for session duration, eliminating hardcoded values throughout the codebase.
- Set HTTP-only cookie in login handler for SSR authentication
- Set HTTP-only cookie in registration handler
- Change default redirect from /bookshelf to /dashboard
- Cookie enables browser page navigation without JavaScript
Clean up auth.go after migrating to system-wide settings:
- Remove UpdateScanSettings handler (moved to system_settings.go)
- Remove GetScanSettings handler (moved to system_settings.go)
- Remove UpdateScanSettingsRequest type (now in system_settings.go)
These handlers are now in SystemSettingsHandler with system-wide scope
instead of per-user functionality.
- Check if returned user record is null (user not found)
- Return 404 Not Found instead of 200 OK
- Provides accurate REST API semantics
- Fixes TestUpdateUserMaxDevicesNonExistentUser
Related: Database query change commit
- Add max_devices column to users table (default: 10)
- Add UpdateUserMaxDevices database query
- Add CountUserDevices database query
- Add UpdateUserMaxDevices handler with validation (1-100 devices)
- Add PUT /api/auth/users/:id/max-devices endpoint (admin only)
- Update UserList struct to include max_devices field
- Validate user ID format and max_devices range
- Return appropriate errors for invalid requests
- Add parseTokenUUID() helper to convert string to pgtype.UUID
- Update RefreshAccessToken to parse token string to UUID before validation
- Update Logout to parse token string to UUID before revoking
- Update CreateRefreshToken to pass UUID directly to database
- Update auth.go: fix return value order from CreateRefreshToken
- Remove unnecessary comments for cleaner code
- Add /bookshelf route as default page for logged-in users
- Update login and register handlers to redirect to /bookshelf
- Update homepage to auto-redirect to /bookshelf when logged in
- Preserve /dashboard route for backward compatibility
- Update test redirects to use /bookshelf
Changes:
- main.go: Add /bookshelf protected route
- auth.go: Change login/register redirects from /api/dashboard to /bookshelf (2 locations)
- edge_cases_test.go: Update test redirect to /bookshelf
- Maintains backward compatibility with existing /dashboard route
This makes the beautiful bookshelf the default landing page
for all authenticated users while keeping the old dashboard accessible.
- ListLibraries now returns {"data": []} instead of []
- ListUsers now returns {"data": []} instead of []
- ListMediaItems now returns {"data": []} instead of []
This provides consistent response structure across all list endpoints
and aligns with integration test expectations.
- Test password complexity requirements
- Test account lockout mechanism
- Test rate limiting functionality
- Test JWT expiration (1 hour)
- Test refresh token expiration (7 days)
- Test password requirements list
- Verify transaction manager and error handler types
- All tests passing
- Trim whitespace from usernames and validate non-empty
- Normalize role values to lowercase for case-insensitive comparison
- Prevent registration with whitespace-only usernames
- Maintain backward compatibility with existing functionality
Fixes validation gap: Username whitespace handling
- Fix database authentication error by exposing actual database error messages
- Update error handling to follow pgx v5 standards with detailed error reporting
- Restore token environment variable management in Register User.bru for subsequent requests
- Enable proper debugging of database connection issues during user registration
The registration API now provides detailed error messages instead of generic 'failed to check existing users'
when database connection or authentication fails, making debugging easier.
- Replace with 410 Gone responses directing to libraries
- Maintain API contract for backward compatibility
- Remove old user folder management functionality
- Prepare for complete library system migration
Old folder management now handled through library system
- Add role-based restrictions to POST /api/auth/register endpoint
- Only admins can create admin accounts if any admin already exists
- First user automatically gets admin role regardless of request
- Regular users can only create user accounts, not admin accounts
- Unauthenticated users can only create first admin, not subsequent admins
- Reorganize Bruno collection into logical subfolders (auth/, admin/, profile/)
- Update documentation to reflect new registration restrictions and security rules
BREAKING CHANGES:
- /api/auth/register now enforces role-based creation restrictions
- Bruno collection reorganized with subfolder structure
- First registered user automatically becomes admin regardless of request
- Prevent deletion of the last user account to protect system
- Enhanced role validation and HTMX error handling
- Proper pgx 5 database standards throughout
Security improvements:
- Auto-admin for first user ensures system always has administrator
- Last-user protection prevents system from having zero users
- Role validation ensures only 'user' or 'admin' roles accepted
- Add AdminMiddleware for protecting sensitive operations
- Update JWT generation to include user role and details
- Modify login/registration to use enhanced JWT claims
- Update main.go to set admin-protected routes
- Add user role to JWT context for downstream handlers
- Add specific pgx.ErrNoRows checks in GetProfile
- Better error handling in UpdatePassword and GetScanSettings
- Return appropriate HTTP status codes for different error types
- Improve error message consistency
- Move migrations/ to database/schema/ for clarity on database schema definitions
- Move sqlc.yaml to internal/database/ to group with database code
- Move static/ to cmd/server/static/ to co-locate with server
- Update all configuration files and documentation
- Follow Go project conventions for better organization
- Add templ dependency for type-safe HTML rendering
- Convert index.html, login.html, register.html, dashboard.html, admin.html, admin_profile.html, admin_library.html to .templ files
- Generate Go code with templ generate for compile-time safety
- Update server routes to use templ components with proper rendering
- Refactor JavaScript in dashboard to avoid backtick parsing conflicts
- Delete old HTML template files
- Clean up project by removing unnecessary files and binaries
- Update CreateUser query to explicitly select only existing columns
- Update all user SELECT queries to explicitly select columns to avoid scan_frequency_minutes column issues
- Add GetUserForLogin query that includes password_hash for authentication
- Update login handler to use GetUserForLogin instead of GetUserByEmailOrUsername
- This prevents errors when migration hasn't been applied yet, allowing user registration to work
- Add admin dashboard at /admin route consolidating all user settings
- Move user preferences (username, email, password, theme) from separate page
- Add ebook library preferences section with folder management
- Add scan settings (frequency and auto-scan toggle) with database persistence
- Create database migration for scan_frequency_minutes and auto_scan_enabled columns
- Add API endpoints for scan settings management:
- PUT /api/library/scan-settings - Update scan preferences
- GET /api/library/scan-settings - Get current scan settings
- Update dashboard navigation to link to admin dashboard
- Remove old preferences.html template (functionality moved to admin)
- Create Bruno API testing files for library endpoints
- Add real-time folder loading and management in admin interface
- Implement scan settings persistence and retrieval from database
- Add /preferences route and preferences.html template for user settings
- Implement username, email, password, and theme update functionality
- Add account deletion feature with confirmation
- Add navigation link to preferences from dashboard
- Create API endpoints:
- PUT /api/user/username - Update username
- PUT /api/user/email - Update email address
- PUT /api/user/password - Change password with verification
- DELETE /api/user/account - Delete user account
- Add database queries for user updates and account deletion
- Create Bruno API testing files for all user preference endpoints
- Add proper validation, error handling, and security checks
- Change Go module name back from 'shelf' to 'bookmann'
- Update all import paths back to 'bookmann' module
- Update README.md project name back to 'Bookmann'
- Update docker-compose.yml container names back to 'bookmann' and 'bookmann_db'
- Regenerate database code with restored module imports
- Rename project from 'bookmann' to 'shelf'
- Move all backend/ contents to root level (flatten structure)
- Update Go module name from 'bookmann' to 'shelf'
- Update all import paths to use new 'shelf' module
- Update Dockerfile to work without backend/ subdirectory
- Update docker-compose.yml to use new structure and rename containers
- Update .gitignore for new file paths
- Update README.md with new project name and structure
- Regenerate database code with new module imports