`just openapi [dir]` (go run ./cmd/openapi) writes openapi.json (3.1) and openapi-3.0.json without a database or configuration. A test checks it matches the spec the server serves.
The spec is now built from the same calls that register the routes, so it
can't drift from the router like the swag comments did (all /api/v1
routes were missing).
- /api/v1 endpoints are typed Huma operations; the spec is OpenAPI 3.1 at
/openapi.json (3.0 at /openapi-3.0.json, YAML too), docs at /docs.
/openapi and /swagger/* redirect there
- Bearer token security is declared per operation; token creation and
the new GET /api/v1/health are public
- Legacy routes use the same handlers, are hidden from the spec and keep
the Deprecation header
- /sync/reset is hidden (debug only); the /sync/new, /sync/quick and
/sync/new/full aliases are removed (use /sync and /sync/full)
- Invalid parameters return 422 (validation); every error is
{"error": "..."}; empty lists are [] instead of null
- /sync/progress is documented as progress or result (oneOf)
- Tests validate the spec and check real responses of every documented
operation against it (kin-openapi)
- Removed swag annotations, cmd/docs, echo-swagger and the swag tool
Echo errors, middleware and handlers used three different formats (message object, error object, bare string). One error handler now writes all of them the same way; status codes are unchanged.
- New /api/v1 endpoints: GET /soundtracks, /soundtracks/{uuid},
/songs/{uuid} and /songs/{uuid}/file (streams the song, Range support,
locked during sync)
- UUIDs added to every response with soundtracks or songs: queue info and
list (SoundtrackUuid, SongUuid) and statistics (soundtrack_uuid,
song_uuid). Existing fields stay for backward compatibility
- Play counts and broken-song removal use song UUIDs instead of
soundtrack ID + song name, so songs with the same name are counted
separately
- Statistics return an empty song list for soundtracks without songs
instead of a single empty entry
- The legacy .id file cleanup stays until Phase 4 (#31)
Closes#29
Security
- Serve character images through os.Root so names like ../ can't escape
the characters folder
- Sync start and /sync/reset are POST only (legacy and /api/v1)
- /api/v1/token/cleanup requires a token, password compared in constant
time, tokens no longer logged
- Echo's rate limiter replaces the custom one; TRUSTED_PROXIES enables
X-Forwarded-For for reverse proxies
Crashes and races
- Sync state lives in SyncService with atomics and a mutex instead of
unsynchronised globals (fixes concurrent map writes during full sync)
- Only one sync can run; /api/v1 sync and music routes are locked during
sync like the legacy ones
- No log.Fatal outside startup: errors become 4xx/5xx responses
- Search uses an in-order character match instead of unescaped regexes
- Empty queue / no songs return 404 instead of panicking or looping
Behaviour
- Sync result is computed once and stays the same between polls
- Swagger and /openapi serve the embedded spec
- Shutdown stops HTTP before closing the database
- Expired tokens are deleted with a context that outlives the request
- Files are served with Range support and correct content types; audio
has no write deadline
Performance
- Migration 000006 adds soundtrack.fingerprint (names, sizes, mtimes) so
unchanged folders are skipped without reading any files
- Songs are reconciled per soundtrack with one query plus needed writes;
renames keep play counts
- Moved MUSIC_PATH updates soundtrack and song paths
- .id cleanup only runs for changed soundtracks or a full sync
- Classic random uses one SQL query; Gitea release lookups are cached
with a timeout
Structure
- internal/config reads all environment variables once
- sqlc emits a Querier interface; backend globals become services
injected into handlers
- One route registration shared by legacy and /api/v1
- Removed dead code (dbHelper.go, unused middleware, duplicate Gitea
functions, embedded Swagger UI copy) and lib/pq
- templ and swag pinned as go tools
- Create middleware/deprecation.go with DeprecationMiddleware
- Adds Warning and Deprecation headers to old endpoints
- Apply middleware to all non-/api/v1 routes:
/version, /dbtest, /health, /character*, /download*, /sync/*,
/music/*
- Message: 'Deprecated: This endpoint is deprecated. Use /api/v1/ endpoints instead.'
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
- Add Database struct in internal/db/database.go with Pool, Ctx, and RunMigrations()
- Update server.go to use Database struct with NewServerInstance()
- Add backend.go with InitBackend(), BackendRepo(), BackendCtx(), BackendPool()
- Update music.go and sync.go to use BackendRepo() and BackendCtx() instead of db.Dbpool/db.Ctx
- Update token_handler.go to accept pool parameter
- Update routes.go to use s.db.Pool for middleware
- Update cmd/main.go to use NewServerInstance() and HTTPServer()
- Update test_helpers.go to initialize backend with test database
- Update test files to use backend.BackendPool() and backend.BackendCtx()
Benefits:
- Easier to mock database for unit tests
- Follows Go best practices (dependency injection)
- Better architecture with explicit dependencies
- RunMigrations() replaces old Migrate_db() function
Note: Global db.Dbpool and db.Ctx still exist in dbHelper.go for backward compatibility
with test_helpers.go, but production code no longer uses them.
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
- Add Database struct in internal/db/database.go with Pool, Ctx, and RunMigrations()
- Update server.go to use Database struct with NewServerInstance()
- Add backend.go with InitBackend(), BackendRepo(), BackendCtx(), BackendPool()
- Update music.go and sync.go to use BackendRepo() and BackendCtx() instead of db.Dbpool/db.Ctx
- Update token_handler.go to accept pool parameter
- Update routes.go to use s.db.Pool for middleware
- Update cmd/main.go to use NewServerInstance() and HTTPServer()
- Update test_helpers.go to initialize backend with test database
- Update test files to use backend.BackendPool() and backend.BackendCtx()
Benefits:
- Easier to mock database for unit tests
- Follows Go best practices (dependency injection)
- Better architecture with explicit dependencies
- RunMigrations() replaces old Migrate_db() function
Note: Global db.Dbpool and db.Ctx still exist in dbHelper.go for backward compatibility
with test_helpers.go, but production code no longer uses them.
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
- Split IndexHandler into HealthHandler, VersionHandler, and CharacterHandler
- Rename index.go to version.go in backend
- Change VersionData.Changelog from string to []string
- Add changelog entries for issues #16-#23
- Remove TestDB function and related code
- Fix import ordering in several files
Closes#21, #22
References #16, #17, #18, #19, #20, #23
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
#2 - Added request to download the newest version of the app
#3 - Added request to check progress during sync
#4 - Now blocking all request while sync is in progress
#5 - Implemented ants for thread pooling
#6 - Changed the sync request to now only start the sync