H4: add internal_api_base_url setting to config.py (default http://localhost:8888,
env-overridable via INTERNAL_API_BASE_URL); replace all 5 hardcoded base_url
strings in chat_service.py.
H6: add post-read size check in both Excel and STEP upload handlers;
raises HTTP 413 when content exceeds settings.max_upload_size_mb.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
H2: list_invoices now passes tenant_id (from current_user) to get_invoices;
get_invoices applies WHERE tenant_id filter for non-global-admin users;
get_invoice_endpoint returns 404 when tenant mismatch for non-admins.
H3: InvoiceStatusUpdate.status changed to Literal["draft","sent","paid","cancelled"]
for schema-level validation; guard also added in update_invoice_status service.
H5: _settings_to_out masks smtp_password as "***" when set, "" when empty;
update_settings skips writing when value is the "***" sentinel.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_render_turntable: Option B — resolved objects as params (render_invocation, step_path,
output_path, template, emit, pl). Session and PipelineLogger stay in the caller so
no second DB connection is opened and log steps roll up to the main task.
_handle_render_task_exhausted: extracted 68-line mark-as-failed block; retry/raise
logic with Celery self.retry stays in render_order_line_task since it needs the
bound-task context.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Save button disabled for non-admins (canSave prop threaded through
WorkflowEditor → WorkflowCanvas → WorkflowCanvasToolbar); tooltip
explains why when hovered
- Optimistic concurrency: migration 072 adds updated_at to
workflow_definitions; PUT /workflows/:id returns 409 when client sends
a stale updated_at; frontend shows a specific reload-prompt toast
- _legacy_dispatch now routes through dispatch_order_line_render instead
of calling render_order_line_task directly, so cancelled/rejected
order lines are skipped before queueing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
canonicalize_workflow_config was silently rebuilding any workflow with
ui.blueprint or ui.preset == still_graph from the canonical template on
every save, preflight, and read — making blueprint-based workflows
effectively read-only.
Add preserve_user_graph=True flag that skips the rebuild blocks. Only
create_workflow still uses preserve_user_graph=False so blueprints are
correctly expanded at creation time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds app_name and app_subtitle as system settings with a dedicated
Branding tab in the Admin panel. Both values are served via a public
GET /api/admin/branding endpoint (no auth) so the login page can also
show the configured name before the user signs in.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Migration 070: seeds 'Cinematic Highlight' output type (legacy_only, no
workflow link) for fresh installs
- Migration 071: patches existing cinematic output types — clears
workflow_definition_id and forces legacy_only rollout mode. The row
existed since 2026-03 with shadow mode + a linked workflow def;
no BLENDER_CINEMATIC graph node exists so shadow execution would fail.
- API guard in output_types POST + PATCH: cinematic output types cannot
receive a workflow_definition_id (HTTP 400)
- Defense-in-depth in dispatch_service: early legacy exit if
render_settings.cinematic is true, regardless of rollout mode
- docs: learning erfasst — cinematic rollout mode footgun
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drei Bugs aus Cinematic-Render-Session dokumentiert:
- is_cinematic immer False wegen Invocation-Override-Filter
- usd_path.exists() auf str (fehlender str→Path-Cast in turntable/cinematic)
- NameError stdout/stderr in cinematic error path
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three bugs causing all cinematic renders to silently fall through to the
turntable path and then immediately crash:
1. is_cinematic read from filtered invocation-override dict — 'cinematic' key
is not in the allowed override key list for turntable_video, so it gets
stripped. Fixed: read directly from output_type.render_settings.
2. render_turntable_to_file and render_cinematic_to_file both call
usd_path.exists() but receive a str from the caller. Added the same
isinstance str→Path conversion that render_still_to_file already had.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Completed renders no longer overwrite a cancelled status — a Blender job
that finishes after a cancel is issued is now silently dropped instead of
flipping the line back to completed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- `render_cinematic_to_file` referenced undefined `stdout`/`stderr` in the
Blender error path; replaced with `log_lines`/`stderr_lines` so the real
Blender error is actually stored in render_log instead of a Python NameError
- Progress callback hardcoded 480 frames; now uses the `frame_count` variable
- Updated docstring to reflect actual 250 frames @ 25fps (not 480 @ 24fps)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>