Files
ERP/bot/integration
whqreza 638076dbaa refactor(bot)!: rename 'ai procurement' -> 'bot/' so the compose build context is committed
The bot service in docker-compose.yml builds from ./bot, but the agent code lived in 'ai procurement/' and ./bot was only a Windows junction on reza.g's machine (and was gitignored) — exactly as the team reported: 'bot/ was never committed — prod-v7's bot is un-buildable from the repo.'

- junction removed; 'ai procurement/' renamed to 'bot/' via git mv (all 41 files keep their history as pure renames)
- 'bot/' dropped from .gitignore (voice/ stays ignored — runtime voice notes; bot/.env stays ignored by bot/.gitignore)
- compose needs no change: context: ./bot and ./bot/app now resolve to committed files
- bot/INTEGRATION-REPORT.md added: full story (problem, root cause, git state, security note on the committed BALE_BOT_TOKEN / AI_API_KEY compose defaults, and usage instructions for the team)

Verified: 41 renames staged with zero secret/cache files; voice/ and bot/.env still ignored.
2026-10-02 12:52:25 +03:30
..

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 -f files (e.g. a prod_v2 checkout + port-remap override), keep using the same chain — the bot service 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_actor returns the raw Authorization: Bearer … string and quote_events.actor stores 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 with CREATE 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).