Files
bookhoard/internal/config/config.go
T
john-okeefe 23ad70158c Phase 2 Week 5: Device Registration & Management
Implement device registration and management system for universal sync.

Database Changes:
- Add device queries to queries.sql (CRUD operations, registration, auth)
- Add sync queue management queries
- Add conflict resolution queries
- Regenerate sqlc models with new device-related types

Device Handler (devices.go):
- InitiateRegistration: Start device registration with auth URL and QR code
- CheckRegistrationStatus: Poll for registration approval
- ListDevices: Get all devices for current user
- GetDevice: Get specific device details
- UpdateDevice: Update device settings (name, sync settings, frequency)
- DeleteDevice: Remove device from account
- ApproveDevice: User approves device registration via web
- RejectDevice: Reject pending device registration
- ListPendingRegistrations: Show all pending registrations
- generateDeviceToken: Generate secure Bearer token for devices

Device Authentication Middleware (device_auth.go):
- Authenticate: Validate device Bearer tokens
- RequirePermission: Check device permissions by type
- hasPermission: Define permissions per device type
- UpdateLastSeen: Auto-update device last_seen timestamp

Configuration:
- Add BaseURL field to Config for device setup URLs

API Endpoints:
POST /api/devices/register - Initiate device registration
POST /api/devices/register/status - Check registration status
GET /api/devices/approve/:id - Approve device (web UI)
POST /api/devices/reject/:id - Reject device
GET /api/devices - List user's devices
GET /api/devices/:id - Get device details
PUT /api/devices/:id - Update device settings
DELETE /api/devices/:id - Delete device
GET /api/devices/pending - List pending registrations

Bruno API Collection:
- Initiate Device Registration
- Check Registration Status
- List Devices
- Get Device
- Update Device
- Delete Device

Dependencies:
- github.com/skip2/go-qrcode for QR code generation

Device Types Supported:
- koreader: Calibre-compatible sync
- kobo: Kobo sync protocol
- web: Web interface
- mobile: Mobile apps

Device Permissions:
- sync:progress
- sync:annotations
- sync:metadata
- device:manage (web only)
2026-01-30 16:45:10 -05:00

72 lines
1.8 KiB
Go

package config
import (
"fmt"
"os"
"strconv"
)
type Config struct {
ServerPort string
BaseURL string
JWTSecret string
UploadPath string
DatabaseHost string
DatabasePort string
DatabaseUser string
DatabasePassword string
DatabaseName string
TestMode bool
RateLimitEnabled bool
RequestsPerMinute int
}
func LoadConfig() *Config {
return &Config{
ServerPort: getEnv("SERVER_PORT", "8080"),
BaseURL: getEnv("BASE_URL", "http://localhost:8080"),
DatabaseHost: getEnv("DATABASE_HOST", "localhost"),
DatabasePort: getEnv("DATABASE_PORT", "5432"),
DatabaseUser: getEnv("DATABASE_USER", "postgres"),
DatabasePassword: getEnv("DATABASE_PASSWORD", "password"),
DatabaseName: getEnv("DATABASE_NAME", "bookmann"),
JWTSecret: getEnv("JWT_SECRET", "your-secret-key"),
UploadPath: getEnv("UPLOAD_PATH", "./uploads"),
TestMode: getEnvBool("TEST_MODE", false),
RateLimitEnabled: getEnvBool("RATE_LIMIT_ENABLED", true),
RequestsPerMinute: getEnvInt("REQUESTS_PER_MINUTE", 10),
}
}
func (c *Config) DatabaseURL() string {
return fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable",
c.DatabaseUser, c.DatabasePassword, c.DatabaseHost, c.DatabasePort, c.DatabaseName)
}
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
func getEnvBool(key string, defaultValue bool) bool {
if value := os.Getenv(key); value != "" {
boolVal, err := strconv.ParseBool(value)
if err == nil {
return boolVal
}
}
return defaultValue
}
func getEnvInt(key string, defaultValue int) int {
if value := os.Getenv(key); value != "" {
intVal, err := strconv.Atoi(value)
if err == nil {
return intVal
}
}
return defaultValue
}