ERP integration pack
The agent is a standalone container — it talks to the ERP exclusively over
HTTP and keeps its own state in its own bot_* tables. Integrating it into the
ERP stack needs exactly
two things:
1. Compose service
Add erp-compose-service.yml to the ERP's
docker-compose.yml (and the Coolify variant). The bot long-polls Bale, so it
needs no ports, no webhook, no TLS — it joins the compose default network
and reaches http://api:8000/api/v1 in-network.
Credentials/env are passed at compose level from a .env next to the compose
file: BALE_BOT_TOKEN, AI_BASE_URL, AI_API_KEY, AI_LLM_MODEL
(see ../.env.example for the full list).
If your stack is started with multiple
-ffiles (e.g. a prod_v2 checkout + port-remap override), keep using the same chain — thebotservice merges in like any other service and the override's host-port remaps don't affect it.
2. Per-user attribution in the API
Apply x-actor-id.patch — a ~6-line, fully
backward-compatible change to backend/app/utils/security.py:
- before:
get_actorreturns the rawAuthorization: Bearer …string andquote_events.actorstores the bot's token; - after: an
X-Actor-Id: <users.id>header (sent by the bot for every mutating call, carrying the linked ERP user's id) takes precedence, so the audit trail records the human who asked, not the bot.
Requests without the header behave exactly as before.
What the agent does NOT touch
- No ERP code is imported by the bot (HTTP-only, own postgres tables
bot_links/bot_drafts/bot_messages/bot_meta, created idempotently at startup withCREATE TABLE IF NOT EXISTS). - No Alembic migration needed — the bot owns its schema.
- The ERP's data model stays untouched; committed drafts flow through the
ordinary public endpoints (
POST /quotes,PATCH /quotes/{id}/accept,PATCH /quotes/{id}/arrive-items,POST /suppliers,POST /materials).