- Remove dead kitchen->KDS internal API (api/internal.py, verify_internal_secret)
— KDS reads kitchen_db directly (E16), nothing ever called this endpoint
- Add expires_at to dispute_attachments; public attachment links now expire
after 30 days instead of staying valid forever (A4)
- Add services/upload_validation.py: sniff real file content via python-magic
instead of trusting the client-supplied Content-Type header, plus a 20MB
cap. Applied across invoices/logbook/food_flags/credit_notes/disputes
upload endpoints (A5) — disputes previously had no file-type check at all
- Fix nginx client_max_body_size drift (800m -> the plan's intended 20m)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- settings/src/integrations/schema.js: rename azure from 'Azure AD' to
'Azure Document Intelligence', swap fields to endpoint + api_key
- Add use_global_azure column (migration + model)
- global_settings_service: add azure to check_global_status and apply_global_overrides
- api/settings.py: expose use_global_azure in response/update; apply overrides
in test_azure_connection before credential check
- Settings.tsx: add 'Use credentials from main stack settings' toggle for
Azure OCR section (endpoint/key disabled when on, test button enabled when
global is configured); remove Users section (managed centrally via auth
service), clean up UserData interface, users query and mutations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each of Newbook, Resos, SambaPOS, SMTP, and Nextcloud now has a checkbox at the
top of its credentials block. When enabled, the app reads auth credentials from
the central stack settings service (SETTINGS_URL + STACK_INTERNAL_SECRET) and
the local auth fields are grayed out. App-specific fields (base path, GL codes,
keywords, sync intervals, etc.) remain editable regardless.
Backend: new use_global_* columns on kitchen_settings, migration, global_settings_service
with apply_global_overrides() for in-memory credential injection, GET /api/settings/global-status
endpoint, and apply_global_overrides() called in test-connection endpoints and FileArchivalService.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Migrations used try/except around ADD COLUMN inside a single engine.begin()
block. When a 'column already exists' error was caught, asyncpg left the
transaction in aborted state, causing all subsequent DDL in the block to fail
with InFailedSQLTransactionError. Replace with IF NOT EXISTS to prevent the
error entirely.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>