{"id":51580003,"url":"https://github.com/erxes/erxes-ai-assistant-gateway","last_synced_at":"2026-07-11T05:02:06.457Z","repository":{"id":362623848,"uuid":"1260022324","full_name":"erxes/erxes-ai-assistant-gateway","owner":"erxes","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-25T08:54:34.000Z","size":187,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-25T10:22:17.723Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/erxes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-05T04:49:06.000Z","updated_at":"2026-06-25T08:54:39.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/erxes/erxes-ai-assistant-gateway","commit_stats":null,"previous_names":["erxes/erxes-ai-assistant-gateway"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/erxes/erxes-ai-assistant-gateway","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erxes%2Ferxes-ai-assistant-gateway","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erxes%2Ferxes-ai-assistant-gateway/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erxes%2Ferxes-ai-assistant-gateway/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erxes%2Ferxes-ai-assistant-gateway/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/erxes","download_url":"https://codeload.github.com/erxes/erxes-ai-assistant-gateway/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erxes%2Ferxes-ai-assistant-gateway/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35351426,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-11T02:00:05.354Z","response_time":104,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-11T05:02:05.719Z","updated_at":"2026-07-11T05:02:06.447Z","avatar_url":"https://github.com/erxes.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# erxes Ai Assistant Gateway\n\nCentral Discord gateway for the official erxes Ai Assistant bot.\n\n## Architecture\n\nThis service uses one official Discord application and bot named `erxes Ai Assistant`.\n\n```text\nDiscord guildId + channelId\n-\u003e erxes-ai-assistant-gateway\n-\u003e tenantId\n-\u003e assistantId\n-\u003e OpenClaw runtime URL\n-\u003e assistant answer\n-\u003e Discord reply\n```\n\nCustomers do not create Discord applications, provide bot tokens, enable privileged intents, or calculate permissions. The gateway-generated installation URL requests the configured bot permission integer, and Erxes Admin owns tenant authorization and channel binding.\n\n## Discord Application Setup\n\nCreate the Discord application manually in the Discord Developer Portal.\n\nUse:\n\n```text\nApplication name: erxes Ai Assistant\nBot name: erxes Ai Assistant\n```\n\nCollect:\n\n```text\nApplication ID\nClient ID\nClient Secret\nPublic Key\nBot Token\n```\n\nDo not enable these privileged intents for the MVP:\n\n```text\nPresence Intent\nServer Members Intent\nMessage Content Intent\n```\n\nUse OAuth installation scopes:\n\n```text\nbot\napplications.commands\n```\n\nThe gateway-generated installation flow requests Discord Administrator permission:\n\n```text\nAdministrator permission integer: 8\n```\n\nAdministrator grants the official erxes Ai Assistant bot full permissions in the selected Discord server. SaaS users do not use the Discord Developer Portal OAuth2 URL Generator directly; they use `/discord/oauth/start`, which generates the install URL with `permissions=8`.\n\nConfigure hosted URLs:\n\n```text\nInteractions Endpoint URL:\nhttps://\u003cgateway-domain\u003e/discord/interactions\n\nOAuth Redirect URI:\nhttps://\u003cgateway-domain\u003e/discord/oauth/callback\n```\n\nFor local Discord testing, expose port `3001` through an HTTPS tunnel and use the tunnel URLs for those two Discord settings.\n\n## Environment\n\nCopy `.env.example` to `.env` and fill the Discord credentials.\n\n```env\nNODE_ENV=development\nPORT=3001\nPUBLIC_BASE_URL=http://localhost:3001\nMONGO_URL=mongodb://127.0.0.1:27017/erxes_ai_assistant_gateway\n\nDISCORD_APPLICATION_ID=\nDISCORD_CLIENT_ID=\nDISCORD_CLIENT_SECRET=\nDISCORD_PUBLIC_KEY=\nDISCORD_BOT_TOKEN=\nDISCORD_REDIRECT_URI=http://localhost:3001/discord/oauth/callback\nDISCORD_TEST_GUILD_ID=\nDISCORD_BOT_PERMISSIONS=8\nENABLE_MOCK_OPENCLAW=false\n\nERXES_GATEWAY_ADMIN_SECRET=change-me\nERXES_ALLOWED_RETURN_URLS=http://localhost:3000\n\nOPENCLAW_REQUEST_TIMEOUT_MS=120000\nERXES_ASSISTANT_REPLY_MAX_CHARS=1800\nOPENCLAW_SHARED_SECRET=\n```\n\nNever commit `.env`. Never log Discord tokens, client secrets, gateway admin secrets, or OpenClaw shared secrets.\n\n## Local Development\n\n```bash\ncd /home/batzorig/Erxes/erxes-ai-assistant-gateway\ncp .env.example .env\ndocker compose -f infra/docker-compose.yml up -d\npnpm install\npnpm dev\n```\n\nChecks:\n\n```bash\npnpm typecheck\npnpm test\npnpm build\n```\n\nHealth:\n\n```bash\ncurl http://localhost:3001/health\n```\n\nOAuth start:\n\n```bash\ncurl -I \"http://localhost:3001/discord/oauth/start?tenantId=test-saas-1\u0026assistantId=support-assistant-1\u0026erxesUserId=local-admin-1\u0026returnUrl=http%3A%2F%2Flocalhost%3A3000%2Fsettings%2Fautomations%2Fagents%2Fsupport-assistant-1\"\n```\n\nRegister slash command:\n\n```bash\npnpm register:commands\n```\n\nIf `DISCORD_TEST_GUILD_ID` is set, this registers a guild command. Otherwise it registers the global command:\n\n```text\n/assistant question:\u003ctext\u003e\n```\n\nMock OpenClaw is disabled by default. Enable it only for local development or a short-lived deployed mock test:\n\n```env\nENABLE_MOCK_OPENCLAW=true\n```\n\nDo not enable the mock route in production. Startup validation rejects `ENABLE_MOCK_OPENCLAW=true` when `NODE_ENV=production`.\n\nMock OpenClaw:\n\n```bash\ncurl -X POST http://localhost:3001/mock-openclaw/api/erxes-ai-assistant/ask \\\n  -H 'content-type: application/json' \\\n  -d '{\n    \"tenantId\": \"test-saas-1\",\n    \"assistantId\": \"support-assistant-1\",\n    \"question\": \"hello\",\n    \"user\": { \"id\": \"discord-user-id\", \"username\": \"Discord Name\" },\n    \"discord\": { \"guildId\": \"guild-id\", \"channelId\": \"channel-id\" },\n    \"source\": \"discord\"\n  }'\n```\n\nCreate a test binding after a `DiscordInstallation` exists:\n\n```bash\ncurl -X POST http://localhost:3001/api/bindings \\\n  -H 'content-type: application/json' \\\n  -H 'x-erxes-gateway-admin-secret: change-me' \\\n  -d '{\n    \"installationId\": \"\u003cinstallation-object-id\u003e\",\n    \"tenantId\": \"test-saas-1\",\n    \"assistantId\": \"support-assistant-1\",\n    \"assistantName\": \"Support Assistant\",\n    \"discordGuildId\": \"\u003cdiscord-guild-id\u003e\",\n    \"discordChannelId\": \"\u003cdiscord-channel-id\u003e\",\n    \"openclawUrl\": \"http://localhost:3001/mock-openclaw\"\n  }'\n```\n\nList installations, channels, and bindings:\n\n```bash\ncurl \"http://localhost:3001/api/installations?tenantId=test-saas-1\" \\\n  -H 'x-erxes-gateway-admin-secret: change-me'\n\ncurl \"http://localhost:3001/api/installations/\u003cinstallation-object-id\u003e/channels\" \\\n  -H 'x-erxes-gateway-admin-secret: change-me'\n\ncurl \"http://localhost:3001/api/bindings?tenantId=test-saas-1\" \\\n  -H 'x-erxes-gateway-admin-secret: change-me'\n```\n\n## Routes\n\nPublic:\n\n```text\nGET /health\nGET /discord/oauth/start\nGET /discord/oauth/callback\nPOST /discord/interactions\nPOST /mock-openclaw/api/erxes-ai-assistant/ask  # only when ENABLE_MOCK_OPENCLAW=true\n```\n\nProtected with `x-erxes-gateway-admin-secret`:\n\n```text\nGET /api/installations\nGET /api/installations/:id\nGET /api/installations/:id/channels\nGET /api/bindings\nGET /api/bindings/:id\nPOST /api/bindings\nPATCH /api/bindings/:id\nDELETE /api/bindings/:id\n```\n\n## Security\n\nImplemented:\n\n- Discord Ed25519 request signature verification.\n- Raw request body preservation for interactions.\n- Secure expiring single-use OAuth state.\n- OAuth callback only saves connected installations after OAuth code exchange succeeds, Discord returns the installed guild, the bot can fetch the guild, and returned permissions include Administrator.\n- Erxes return URL allowlist.\n- Protected internal APIs with `x-erxes-gateway-admin-secret`.\n- No privileged Discord intents for MVP.\n- The gateway-generated install URL requests Administrator permission with `permissions=8`.\n- OAuth scopes remain only `bot` and `applications.commands`.\n- No customer bot tokens.\n- No secrets in redirect URLs.\n- OpenClaw request timeout handling.\n- Optional `x-erxes-ai-assistant-secret` forwarding.\n- Tenant/guild installation validation before binding writes.\n- One active binding per Discord guild/channel.\n- Production startup rejects placeholder gateway admin secrets and refuses to enable the mock OpenClaw route.\n\nTODO: replace the shared gateway admin secret with stronger service authentication, signed requests, and audit logging.\n\n## Ubuntu 24.04 Hosting\n\nAssumptions:\n\n- A DNS record points `gateway-domain` to the server.\n- MongoDB is either managed or reachable privately.\n- Node.js 22, pnpm, PM2, Nginx, and Certbot are allowed.\n\nInstall packages:\n\n```bash\nsudo apt update\nsudo apt install -y nginx certbot python3-certbot-nginx\ncurl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -\nsudo apt install -y nodejs\nsudo npm install -g pnpm pm2\n```\n\nDeploy:\n\n```bash\ngit clone \u003crepo-url\u003e /opt/erxes-ai-assistant-gateway\ncd /opt/erxes-ai-assistant-gateway\ncp .env.example .env\npnpm install\npnpm test\npnpm build\npm2 start dist/src/main.js --name erxes-ai-assistant-gateway\npm2 save\npm2 startup\n```\n\nNginx:\n\n```nginx\nserver {\n  server_name \u003cgateway-domain\u003e;\n\n  client_max_body_size 5m;\n\n  location / {\n    proxy_pass http://127.0.0.1:3001;\n    proxy_http_version 1.1;\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_set_header X-Forwarded-Proto $scheme;\n    proxy_read_timeout 130s;\n  }\n}\n```\n\nEnable SSL:\n\n```bash\nsudo nginx -t\nsudo systemctl reload nginx\nsudo certbot --nginx -d \u003cgateway-domain\u003e\n```\n\nVerify:\n\n```bash\ncurl https://\u003cgateway-domain\u003e/health\n```\n\nConfigure Discord:\n\n```text\nInteractions Endpoint URL:\nhttps://\u003cgateway-domain\u003e/discord/interactions\n\nOAuth Redirect URI:\nhttps://\u003cgateway-domain\u003e/discord/oauth/callback\n```\n\nRegister global command:\n\n```bash\ncd /opt/erxes-ai-assistant-gateway\nDISCORD_TEST_GUILD_ID= pnpm register:commands\n```\n\nUseful logs and rollback:\n\n```bash\npm2 logs erxes-ai-assistant-gateway\npm2 restart erxes-ai-assistant-gateway\npm2 stop erxes-ai-assistant-gateway\n```\n\nRollback by deploying the previous git revision, running `pnpm install \u0026\u0026 pnpm build`, then `pm2 restart erxes-ai-assistant-gateway`.\n\n## End-To-End MVP Test\n\n1. Create one official Discord application and bot named `erxes Ai Assistant`.\n2. Configure this gateway with the official Discord credentials.\n3. Register `/assistant question:\u003ctext\u003e`.\n4. Start Erxes with `ERXES_AI_ASSISTANT_GATEWAY_URL` and `ERXES_AI_ASSISTANT_GATEWAY_SECRET`.\n5. Open an Erxes AI assistant.\n6. Click `Connect Discord`.\n7. Approve the official bot in Discord.\n8. Return to Erxes and select a Discord server/channel.\n9. Click `Connect channel`.\n10. Run `/assistant question: hello` in Discord.\n11. The gateway resolves guild/channel to tenant/assistant/OpenClaw and edits the Discord reply with the final answer.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferxes%2Ferxes-ai-assistant-gateway","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ferxes%2Ferxes-ai-assistant-gateway","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferxes%2Ferxes-ai-assistant-gateway/lists"}