fix(swagger): respect base URL for API docs routes - #758
Conversation
WalkthroughRoutes for Swagger UI and OpenAPI now use a normalized base URL (via httphelpers.NormalizeBasePath) when registered, and the Vite navigateFallback denylist regex for API routes was adjusted to match trailing-slash or end-of-path cases and its order was swapped. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
internal/web/swagger/openapi.yaml (1)
3743-3750: OpenAPInullable: trueforindexerNamedoesn’t match the Go shape (string +omitempty).
If the API never returnsnull(only omits or returns a string), dropnullable: true. Otherwise, make the Go field*stringsonullis representable.internal/models/crossseed.go (1)
160-170:IndexerNamefield has inconsistent null/omit/required representation across Go, OpenAPI, and TypeScript types.OpenAPI spec defines
indexerNameasnullable: true, but:
- Go struct uses
omitempty(field is omitted if empty, not sent asnull)- TypeScript interface treats it as a required field (no
?optional marker)Align the three to use consistent representation: either all nullable, all optional, or all required.
internal/services/crossseed/service.go (4)
1619-1666: Use the resolvedsourceIndexerforIndexerName(currently usesresult.Indexer). You already mapresult.IndexerID→ friendly name intosourceIndexer(Lines 1620-1623), but the run results here still use the rawresult.Indexer, which can diverge from the resolved name.run.Results = append(run.Results, models.CrossSeedRunResult{ InstanceName: result.Indexer, - IndexerName: result.Indexer, + IndexerName: sourceIndexer, Success: false, Status: "no_match", Message: fmt.Sprintf("No matching torrents for %s", result.Title), }) run.Results = append(run.Results, models.CrossSeedRunResult{ InstanceName: result.Indexer, - IndexerName: result.Indexer, + IndexerName: sourceIndexer, Success: true, Status: "dry-run", Message: fmt.Sprintf("Dry run: %d viable candidates", candidateCount), })
1694-1723: SameIndexerNameinconsistency in “exists” pre-check results. These blocks also setIndexerName: result.Indexerbut should likely usesourceIndexerfor consistency with the resolved indexer name.existingResults = append(existingResults, models.CrossSeedRunResult{ InstanceID: candidate.InstanceID, InstanceName: candidate.InstanceName, - IndexerName: result.Indexer, + IndexerName: sourceIndexer, Success: false, Status: "exists", Message: "Torrent already exists (infohash pre-check)", ... }) existingResults = append(existingResults, models.CrossSeedRunResult{ InstanceID: candidate.InstanceID, InstanceName: candidate.InstanceName, - IndexerName: result.Indexer, + IndexerName: sourceIndexer, Success: false, Status: "exists", Message: "Torrent already exists (comment URL pre-check)", ... })Also applies to: 1752-1780
1833-1893: PropagateIndexerNameconsistently for “no_result” and per-instance mapped results. Same issue:IndexerNameusesresult.Indexerinstead ofsourceIndexer.run.Results = append(run.Results, models.CrossSeedRunResult{ InstanceName: result.Indexer, - IndexerName: result.Indexer, + IndexerName: sourceIndexer, Success: false, Status: "no_result", Message: fmt.Sprintf("Cross-seed returned no actionable instances for %s", result.Title), }) mapped := models.CrossSeedRunResult{ InstanceID: instanceResult.InstanceID, InstanceName: instanceResult.InstanceName, - IndexerName: result.Indexer, + IndexerName: sourceIndexer, Success: instanceResult.Success, Status: instanceResult.Status, Message: instanceResult.Message, }
6521-6545: Tag matching uses exact case-sensitive comparison, creating a breaking change if configs historically used different casing. The code at lines 6521-6545 and 6547-6554 matches tags with exact equality (tag == allowed,tag == excluded,tag == "cross-seed") rather than case-insensitive comparison. Other services in the codebase (reannounce, trackerrules) consistently usestrings.EqualFoldfor tag matching, but crossseed does not. Users with tags like"Cross-Seed"or"TAG1"will silently fail to match, sincesplitTagsdoes not normalize casing before comparison. Confirm this breaking behavior is intentional or apply case-insensitive matching to align with existing patterns.
🧹 Nitpick comments (7)
web/src/types/index.ts (1)
1404-1417: Consider backward-compat: requiredrssSource*fields can break older API responses.
If the UI can connect to older qui versions, make these optional (or ensure the fetch/normalization layer defaults missing fields to[]). If server/UI are always deployed together, current typing is fine.Also applies to: 1437-1450
internal/api/handlers/crossseed.go (1)
198-210: Patch application forrssSource*is straightforward and correct.
Optional follow-up: consider normalizing (trim/dedupe) before persisting if you want consistent matching behavior.internal/models/crossseed.go (1)
415-431: Store write-path wiring forrss_source_*looks consistent (columns/placeholders/args).
Optional: normalize (trim/dedupe)RSSSource*before encoding to keep stored settings canonical (there’s alreadynormalizeStringSlicein this file).Also applies to: 451-494, 507-535
internal/services/crossseed/service.go (1)
1919-2002: RSS source filtering integration looks good; consider normalizing filters to avoid whitespace surprises.splitTags()trims torrent tags, but settings-provided tags/categories may include whitespace and won’t match as expected. A lightweight fix is to normalize the settings slices once whenhasRSSSourceFiltersis true (either here or at settings-validation time).web/src/pages/CrossSeedPage.tsx (3)
384-395: Normalize rssSource lists before persisting (avoid dupes / whitespace variants).*
Search filters are typically “set-like”; saving duplicates can lead to confusing UI and non-deterministic backend behavior.setAutomationForm({ enabled: settings.enabled, runIntervalMinutes: settings.runIntervalMinutes, targetInstanceIds: settings.targetInstanceIds, targetIndexerIds: settings.targetIndexerIds, - rssSourceCategories: settings.rssSourceCategories ?? [], - rssSourceTags: settings.rssSourceTags ?? [], - rssSourceExcludeCategories: settings.rssSourceExcludeCategories ?? [], - rssSourceExcludeTags: settings.rssSourceExcludeTags ?? [], + rssSourceCategories: normalizeStringList(settings.rssSourceCategories ?? []), + rssSourceTags: normalizeStringList(settings.rssSourceTags ?? []), + rssSourceExcludeCategories: normalizeStringList(settings.rssSourceExcludeCategories ?? []), + rssSourceExcludeTags: normalizeStringList(settings.rssSourceExcludeTags ?? []), })return { enabled: automationSource.enabled, runIntervalMinutes: automationSource.runIntervalMinutes, targetInstanceIds: automationSource.targetInstanceIds, targetIndexerIds: automationSource.targetIndexerIds, - rssSourceCategories: automationSource.rssSourceCategories, - rssSourceTags: automationSource.rssSourceTags, - rssSourceExcludeCategories: automationSource.rssSourceExcludeCategories, - rssSourceExcludeTags: automationSource.rssSourceExcludeTags, + rssSourceCategories: normalizeStringList(automationSource.rssSourceCategories), + rssSourceTags: normalizeStringList(automationSource.rssSourceTags), + rssSourceExcludeCategories: normalizeStringList(automationSource.rssSourceExcludeCategories), + rssSourceExcludeTags: normalizeStringList(automationSource.rssSourceExcludeTags), }Also applies to: 482-507
835-874: Select option derivation looks good; consider guarding against include/exclude overlap.
Right now the UI can select the same category/tag in both include and exclude lists; if backend precedence is “exclude wins”, consider enforcing that in UI (or surfacing a warning).
989-998: Defensive reduce for stats (avoid NaN if backend ever sends null/undefined).return { - totalAdded: runs.reduce((sum, run) => sum + run.torrentsAdded, 0), - totalFailed: runs.reduce((sum, run) => sum + run.torrentsFailed, 0), + totalAdded: runs.reduce((sum, run) => sum + (run.torrentsAdded ?? 0), 0), + totalFailed: runs.reduce((sum, run) => sum + (run.torrentsFailed ?? 0), 0), totalRuns: runs.length, }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
internal/api/handlers/crossseed.go(3 hunks)internal/database/migrations/032_add_rss_source_filters.sql(1 hunks)internal/models/crossseed.go(11 hunks)internal/services/crossseed/service.go(15 hunks)internal/web/swagger/openapi.yaml(1 hunks)internal/web/swagger/swagger.go(1 hunks)web/src/pages/CrossSeedPage.tsx(9 hunks)web/src/types/index.ts(3 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-28T20:32:30.126Z
Learnt from: s0up4200
Repo: autobrr/qui PR: 641
File: internal/services/crossseed/service.go:209-212
Timestamp: 2025-11-28T20:32:30.126Z
Learning: Repo: autobrr/qui PR: 641
File: internal/services/crossseed/service.go
Learning: The cross-seed recheck-resume worker intentionally runs for the process lifetime and keys pending entries by hash only. This is acceptable under the current constraint that background seeded-search runs operate on a single instance at a time; graceful shutdown and instanceID|hash keying are deferred by design.
Applied to files:
internal/models/crossseed.gointernal/services/crossseed/service.go
📚 Learning: 2025-11-28T22:21:20.730Z
Learnt from: s0up4200
Repo: autobrr/qui PR: 641
File: internal/services/crossseed/service.go:2415-2457
Timestamp: 2025-11-28T22:21:20.730Z
Learning: Repo: autobrr/qui PR: 641
File: internal/services/crossseed/service.go
Learning: The determineSavePath function intentionally includes a contentLayout string parameter for future/content-layout branching and API consistency. Its presence is by design even if unused in the current body; do not flag as an issue in reviews.
Applied to files:
internal/models/crossseed.gointernal/services/crossseed/service.go
📚 Learning: 2025-11-27T15:33:39.007Z
Learnt from: s0up4200
Repo: autobrr/qui PR: 641
File: internal/services/jackett/service.go:309-330
Timestamp: 2025-11-27T15:33:39.007Z
Learning: In internal/services/jackett/service.go, synchronous execution paths (test executors, interactive searches with explicit indexer selection, and scheduler-unavailable fallback) intentionally pass jobID=0 to result callbacks. This is acceptable because outcome tracking via ReportIndexerOutcome is only used for async cross-seed operations that always use the scheduler and receive unique jobIDs. Interactive searches and tests do not use outcome tracking.
Applied to files:
internal/services/crossseed/service.go
🧬 Code graph analysis (2)
internal/models/crossseed.go (1)
web/src/types/index.ts (2)
CrossSeedAutomationSettings(1404-1435)Category(427-430)
internal/services/crossseed/service.go (3)
pkg/prowlarr/client.go (1)
Indexer(76-84)internal/models/crossseed.go (1)
CrossSeedAutomationSettings(20-64)web/src/types/index.ts (3)
CrossSeedAutomationSettings(1404-1435)Torrent(226-283)Category(427-430)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Run tests
🔇 Additional comments (10)
internal/database/migrations/032_add_rss_source_filters.sql (1)
1-8: LGTM: safe defaults for new filter columns.
Default'[]'is a good compatibility choice for existing rows and for JSON-slice decoding.web/src/types/index.ts (1)
1375-1384:indexerName?: stringaligns with Goomitempty.
No concerns here.internal/api/handlers/crossseed.go (1)
135-162:isEmpty()correctly accounts for the new RSS source filter fields.internal/models/crossseed.go (3)
31-36: Good: rssSource fields are explicit and documented on the settings model.*
76-92: Good defaults: empty slices avoid nulls and simplify client logic.
273-314: Store read-path wiring forrss_source_*looks correct.
Given the migration defaults to'[]', decode should be stable for both new and existing rows.Also applies to: 357-369
internal/services/crossseed/service.go (2)
1539-1542: Signature update usage looks correct.buildAutomationSnapshotsis now called withsettings, enabling RSS source filtering during snapshot construction.
6434-6463: The original review comment is incorrect. Tags are already normalized upstream before reachingmatchesSearchFilters. At line 1374 invalidateSearchRunOptions,opts.Tags = normalizeStringSlice(opts.Tags)trims whitespace and removes duplicates from all input tags. This normalization happens during validation (line 1172) beforestateis created at line 1235, so the concern about spacing mismatches silently filtering torrents is unfounded. Case sensitivity is by design, as noted in comments ("case-sensitive to match qBittorrent behavior"), not a bug.web/src/pages/CrossSeedPage.tsx (2)
39-66: Nice, cohesive wiring for the new RSS source filter fields (types + icons used later).
TheAutomationFormStateadditions look consistent with the rest of the form model.
104-113: Defaults correctly include the new rssSource arrays.*
Swagger docs were registered at hardcoded /api/docs and /api/openapi.json paths, ignoring the configured baseURL. This caused docs to be inaccessible when using a custom base URL (e.g., /qui/ on seedboxes). The handler already received baseURL but didn't use it in RegisterRoutes(). Now routes are prefixed with baseURL so /qui/api/docs works correctly.
The navigateFallbackDenylist regex only matched paths starting with /api, causing the service worker to serve the SPA shell for /qui/api/docs when using a custom base URL. Remove the ^ anchor so /api is matched anywhere in the path.
6ae9888 to
0fe48ae
Compare
Use the existing httphelpers.NormalizeBasePath function instead of manual TrimSuffix. This ensures baseURL always has a leading slash (e.g., "qui" becomes "/qui"), preventing malformed routes like "qui/api/docs".
This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/autobrr/qui](https://github.com/autobrr/qui) | minor | `v1.9.1` -> `v1.10.0` | --- ### Release Notes <details> <summary>autobrr/qui (ghcr.io/autobrr/qui)</summary> ### [`v1.10.0`](https://github.com/autobrr/qui/releases/tag/v1.10.0) [Compare Source](autobrr/qui@v1.9.1...v1.10.0) #### Changelog ##### New Features - [`f2b17e6`](autobrr/qui@f2b17e6): feat(config): add SESSION\_SECRET\_FILE env var ([#​661](autobrr/qui#661)) ([@​undefined-landmark](https://github.com/undefined-landmark)) - [`f5ede56`](autobrr/qui@f5ede56): feat(crossseed): add RSS source filters for categories and tags ([#​757](autobrr/qui#757)) ([@​s0up4200](https://github.com/s0up4200)) - [`9dee7bb`](autobrr/qui@9dee7bb): feat(crossseed): add Unicode normalization for title and file matching ([#​742](autobrr/qui#742)) ([@​s0up4200](https://github.com/s0up4200)) - [`d44058f`](autobrr/qui@d44058f): feat(crossseed): add skip auto-resume settings per mode ([#​755](autobrr/qui#755)) ([@​s0up4200](https://github.com/s0up4200)) - [`9e3534a`](autobrr/qui@9e3534a): feat(crossseed): add webhook source filters for categories and tags ([#​763](autobrr/qui#763)) ([@​s0up4200](https://github.com/s0up4200)) - [`c8bbe07`](autobrr/qui@c8bbe07): feat(crossseed): only poll status endpoints when features are enabled ([#​738](autobrr/qui#738)) ([@​s0up4200](https://github.com/s0up4200)) - [`fda8101`](autobrr/qui@fda8101): feat(sidebar): add size tooltips and deduplicate cross-seed sizes ([#​724](autobrr/qui#724)) ([@​s0up4200](https://github.com/s0up4200)) - [`e4c0556`](autobrr/qui@e4c0556): feat(torrent): add sequential download toggles ([#​776](autobrr/qui#776)) ([@​rare-magma](https://github.com/rare-magma)) - [`2a43f15`](autobrr/qui@2a43f15): feat(torrents): autocomplete paths ([#​634](autobrr/qui#634)) ([@​rare-magma](https://github.com/rare-magma)) - [`1c07b33`](autobrr/qui@1c07b33): feat(torrents): replace filtered speeds with global ([#​745](autobrr/qui#745)) ([@​jabloink](https://github.com/jabloink)) - [`cd0deee`](autobrr/qui@cd0deee): feat(tracker): add per-domain stats inclusion toggle for merged trackers ([#​781](autobrr/qui#781)) ([@​s0up4200](https://github.com/s0up4200)) - [`b6a6200`](autobrr/qui@b6a6200): feat(web): add Size column to Tracker Breakdown table ([#​770](autobrr/qui#770)) ([@​s0up4200](https://github.com/s0up4200)) - [`560071b`](autobrr/qui@560071b): feat(web): add zebra striping to torrent table ([#​726](autobrr/qui#726)) ([@​s0up4200](https://github.com/s0up4200)) - [`f8f65a8`](autobrr/qui@f8f65a8): feat(web): improve auto-search on completion UX ([#​743](autobrr/qui#743)) ([@​s0up4200](https://github.com/s0up4200)) - [`e36312f`](autobrr/qui@e36312f): feat(web): improve torrent selection UX with unified click and escape behavior ([#​782](autobrr/qui#782)) ([@​s0up4200](https://github.com/s0up4200)) - [`27c1daa`](autobrr/qui@27c1daa): feat(web): napster theme ([#​728](autobrr/qui#728)) ([@​s0up4200](https://github.com/s0up4200)) - [`e3950de`](autobrr/qui@e3950de): feat(web): new torrent details panel for desktop ([#​760](autobrr/qui#760)) ([@​s0up4200](https://github.com/s0up4200)) - [`6c66ba5`](autobrr/qui@6c66ba5): feat(web): persist tab state in URL for CrossSeed and Settings pages ([#​775](autobrr/qui#775)) ([@​s0up4200](https://github.com/s0up4200)) - [`59884a9`](autobrr/qui@59884a9): feat(web): share tracker customizations with filtersidebar ([#​717](autobrr/qui#717)) ([@​s0up4200](https://github.com/s0up4200)) ##### Bug Fixes - [`fafd278`](autobrr/qui@fafd278): fix(api): add webhook source filter fields to PATCH settings endpoint ([#​774](autobrr/qui#774)) ([@​s0up4200](https://github.com/s0up4200)) - [`bdf0339`](autobrr/qui@bdf0339): fix(api): support apikey query param with custom base URL ([#​748](autobrr/qui#748)) ([@​s0up4200](https://github.com/s0up4200)) - [`c3c8d66`](autobrr/qui@c3c8d66): fix(crossseed): compare Site and Sum fields for anime releases ([#​769](autobrr/qui#769)) ([@​s0up4200](https://github.com/s0up4200)) - [`cb4c965`](autobrr/qui@cb4c965): fix(crossseed): detect file name differences and fix hasExtraSourceFiles ([#​741](autobrr/qui#741)) ([@​s0up4200](https://github.com/s0up4200)) - [`fd9e054`](autobrr/qui@fd9e054): fix(crossseed): fix batch completion searches and remove legacy settings ([#​744](autobrr/qui#744)) ([@​s0up4200](https://github.com/s0up4200)) - [`26706a0`](autobrr/qui@26706a0): fix(crossseed): normalize punctuation in title matching ([#​718](autobrr/qui#718)) ([@​s0up4200](https://github.com/s0up4200)) - [`db30566`](autobrr/qui@db30566): fix(crossseed): rename files before folder to avoid path conflicts ([#​752](autobrr/qui#752)) ([@​s0up4200](https://github.com/s0up4200)) - [`8886ac4`](autobrr/qui@8886ac4): fix(crossseed): resolve category creation race condition and relax autoTMM ([#​767](autobrr/qui#767)) ([@​s0up4200](https://github.com/s0up4200)) - [`f8f2a05`](autobrr/qui@f8f2a05): fix(crossseed): support game scene releases with RAR files ([#​768](autobrr/qui#768)) ([@​s0up4200](https://github.com/s0up4200)) - [`918adee`](autobrr/qui@918adee): fix(crossseed): treat x264/H.264/H264/AVC as equivalent codecs ([#​766](autobrr/qui#766)) ([@​s0up4200](https://github.com/s0up4200)) - [`c4b1f0a`](autobrr/qui@c4b1f0a): fix(dashboard): merge tracker customizations with duplicate displayName ([#​751](autobrr/qui#751)) ([@​jabloink](https://github.com/jabloink)) - [`3c6e0f9`](autobrr/qui@3c6e0f9): fix(license): remove redundant validation call after activation ([#​749](autobrr/qui#749)) ([@​s0up4200](https://github.com/s0up4200)) - [`a9c7754`](autobrr/qui@a9c7754): fix(reannounce): simplify tracker detection to match qbrr logic ([#​746](autobrr/qui#746)) ([@​s0up4200](https://github.com/s0up4200)) - [`3baa007`](autobrr/qui@3baa007): fix(rss): skip download when torrent already exists by infohash ([#​715](autobrr/qui#715)) ([@​s0up4200](https://github.com/s0up4200)) - [`55d0ccc`](autobrr/qui@55d0ccc): fix(swagger): respect base URL for API docs routes ([#​758](autobrr/qui#758)) ([@​s0up4200](https://github.com/s0up4200)) - [`47695fd`](autobrr/qui@47695fd): fix(web): add height constraint to filter sidebar wrapper for proper scrolling ([#​778](autobrr/qui#778)) ([@​s0up4200](https://github.com/s0up4200)) - [`4b3bfea`](autobrr/qui@4b3bfea): fix(web): default torrent format to v1 in creator dialog ([#​723](autobrr/qui#723)) ([@​s0up4200](https://github.com/s0up4200)) - [`2d54b79`](autobrr/qui@2d54b79): fix(web): pin submit button in Services sheet footer ([#​756](autobrr/qui#756)) ([@​s0up4200](https://github.com/s0up4200)) - [`2bcd6a3`](autobrr/qui@2bcd6a3): fix(web): preserve folder collapse state during file tree sync ([#​740](autobrr/qui#740)) ([@​ewenjo](https://github.com/ewenjo)) - [`57f3f1d`](autobrr/qui@57f3f1d): fix(web): sort Peers column by total peers instead of connected ([#​759](autobrr/qui#759)) ([@​s0up4200](https://github.com/s0up4200)) - [`53a8818`](autobrr/qui@53a8818): fix(web): sort Seeds column by total seeds instead of connected ([#​747](autobrr/qui#747)) ([@​s0up4200](https://github.com/s0up4200)) - [`d171915`](autobrr/qui@d171915): fix(web): sort folders before files in torrent file tree ([#​764](autobrr/qui#764)) ([@​s0up4200](https://github.com/s0up4200)) ##### Other Changes - [`172b4aa`](autobrr/qui@172b4aa): chore(assets): replace napster.svg with napster.png for logo update ([@​s0up4200](https://github.com/s0up4200)) - [`dc83102`](autobrr/qui@dc83102): chore(deps): bump the github group with 3 updates ([#​761](autobrr/qui#761)) ([@​dependabot](https://github.com/dependabot)\[bot]) - [`75357d3`](autobrr/qui@75357d3): chore: fix napster logo ([@​s0up4200](https://github.com/s0up4200)) - [`206c4b2`](autobrr/qui@206c4b2): refactor(web): extract CrossSeed completion to accordion component ([#​762](autobrr/qui#762)) ([@​s0up4200](https://github.com/s0up4200)) **Full Changelog**: <autobrr/qui@v1.9.1...v1.10.0> #### Docker images - `docker pull ghcr.io/autobrr/qui:v1.10.0` - `docker pull ghcr.io/autobrr/qui:latest` #### What to do next? - Join our [Discord server](https://discord.autobrr.com/qui) Thank you for using qui! </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0Mi4zOS4xIiwidXBkYXRlZEluVmVyIjoiNDIuMzkuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW1hZ2UiXX0=--> Reviewed-on: https://gitea.alexlebens.dev/alexlebens/infrastructure/pulls/2664 Co-authored-by: Renovate Bot <renovate-bot@alexlebens.net> Co-committed-by: Renovate Bot <renovate-bot@alexlebens.net>
Summary
/qui/on seedboxes)/api/docsand/api/openapi.json, ignoring the configuredbaseURLbaseURLso/qui/api/docsworks correctlyTest plan
/api/docsstill works with default config (no baseURL)/qui/api/docsloads correctly whenbaseUrl: "/qui/"is configuredSummary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.