- CRM_USE_STUB: local runs no longer reach the live CRM. With only the
Checkbox stub, a stub receipt would still move the real order to PACKED.
Refused in production, same as CHECKBOX_USE_STUB.
- scripts/deploy.sh: backup, fast-forward main, build, health check and
code rollback on failure. scripts/backup.sh: pg_dump with verification
and 14-day rotation (used by cron and deploy.sh).
- Gitea Actions CI: ruff + pytest, oxlint + build.
- DEPLOY.md runbook; CLAUDE.md rules for safe local development.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ExoCrmClient.set_status: live SetStatus needs {Orders: [id], Status} and
replies per order, unlike the documented {ID, Status}
- receipts.crm_status_set_at (migration 0006); set right after creation,
retried by cron, row-locked to avoid a repeat PACKED overwriting a newer status
- CRM errors under capitalized 'Errors' and non-JSON replies are reported
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Wires the CRM (exoCRM GetOrders) into the dashboard as a locally
persisted order queue instead of the previous static mockup:
- CrmClient Protocol + ExoCrmClient/StubCrmClient for the CRM's
signed JSON-RPC API
- Order model + migration, synced from CRM on each queue view;
soft-deleted orders stay hidden across re-syncs
- GET/DELETE /api/v1/orders with "no receipt"/"receipt issued" tabs
(the latter is empty until Checkbox fiscalization lands)
- Dashboard: real order list, item-detail modal, tab switcher,
one-click delete
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>