The per-route loop in `rebuild_routes` only visits routes whose model_pattern
appears in the current `by_model` set. When the last active account for a
model goes away (account deleted, status flipped, model dropped from
model_availability), the model falls out of `by_model` entirely and its
existing auto-managed channels are never reconciled — they stay behind
pointing at a route nothing can serve.
Add a final orphan sweep over all auto-managed route_channels. Anything whose
route wasn't processed in the per-route loop gets hard-deleted. Manual-override
channels still get the same exemption as before.
Covered by two new in-memory sqlite tests:
- orphan_channel_is_cleaned_when_last_account_goes_inactive
- orphan_sweep_preserves_manual_channels
- skip docker build when boosapi-comfyui:multi-tenant already exists;
--rebuild-image opts back into a fresh build
- fall back to `docker load` from docker/boosapi-comfyui-multi-tenant-*.tar
when the image is absent but the saved tar is present
- gate the whole block on `docker info` so a client-only host doesn't hang
on build when the daemon is unreachable
- spawn_route_rebuild after create / delete / model refresh / manual model
upsert; gate update_account on status change so cosmetic edits don't
burn a transaction
- list_accounts now accepts ?segment=apikey|session|oauth, filtered against
extra_config.$.credentialMode (legacy null rows treated as apikey)
Frontend reads main's drizzle-generated camelCase fields (siteId,
accessToken, oauthProvider, etc.) and a nested `site: {...}` on each
account row. Rust models were serializing snake_case with no nested
site, so PUT /api/sites/undefined/disabled-models 404s, account.site?.id
is undefined everywhere, and similar shape mismatches break Accounts,
Sites, Tokens, and Dashboard pages.
- Add #[serde(rename_all = "camelCase")] to every model struct in
src/db/models/* (Account, AccountToken, Site, User, Event,
TokenRoute, RouteChannel, BackgroundTask, DownstreamApiKey,
Organization/Member/Invitation, SiteAnnouncement)
- list_accounts now nests `site: {...}` per row, matching main's
`{...account, site: {...}}` shape from accountsOverviewService
- admin user-detail endpoint emits camelCase keys (totalRequests,
totalCost, last7DaysCost, recentLogs, promptTokens, completionTokens,
totalTokens, createdAt) to match the frontend
- routes refresh endpoint now emits both affected_routes and
affectedRoutes for forward compat
Co-Authored-By: Kiro <noreply@kiro.dev>