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>
Previously every executor took `_state: AppState` (unused) and `check_auth`
discarded the matched downstream key id, so `usage_logs` was orphan code.
This change plumbs the key id from auth → handlers → executors → billing,
adds the OpenAI Responses API endpoint, and exposes shim aliases under
`/api/comfyui-agent/proxy/openai/*` so embedded ComfyUI's OpenAI nodes
flow through the same auth/conductor/billing pipeline.
- check_auth now returns Option<i64> (managed key id) instead of unit
- record_billing helper writes usage_logs after each successful upstream call
- extract_usage handles both chat-completions and responses usage shapes
- conductor wrappers record billing post-Success; stream variant scans
chunks in reverse for the final usage event
- POST /v1/responses (stream + non-stream) via ProxyConductor
- shim aliases mounted on the same Router so auth/failover/billing work for free
- ComfyUIProcess injects BOOSAPI_BUILTIN_KEY env + --comfy-api-base on spawn
- bootstrap built-in `comfyui-agent` downstream key at startup (idempotent)
- get_auth_header in vendored ComfyUI falls back to BOOSAPI_BUILTIN_KEY env
Co-Authored-By: Kiro <noreply@kiro.dev>
- New system prompt with 【CHARACTER】【SCENE】【TTS】【WORKFLOW】 markers
- Backend parses structured sections, auto-calls gpt-image-2 for character/scene images
- Auto-calls TTS API for dialogue lines
- Case-insensitive field parsing, robust whitespace handling
- Static file serving with SPA fallback for frontend
- No Node.js runtime dependency for serving