This backend does three things using Arcade tools:
- On GitHub PR opened, it comments on the Jira issue found in the branch name.
- It runs delayed consistency checks between GitHub and Jira.
- It applies Policy-as-Code rules from YAML to decide which Slack alerts to send.
The 1-minute consistency check can be triggered by:
- GitHub PR opened/reopened webhook
- Jira issue closed webhook
Github.GetPullRequestGithub.ListPullRequests(authorized and available)Jira.GetIssueCommentsJira.AddCommentToIssueJira.GetIssueByIdSlack.SendMessage
- GitHub sends
pull_requestwebhook (openedorreopened) - Backend extracts Jira key from branch name (
JIRA-123) - Backend gets PR details with Arcade
Github.GetPullRequest - Backend comments on Jira with Arcade
Jira.AddCommentToIssue(deduped) - Backend waits 60s (configurable)
- Backend re-checks PR + Jira via Arcade
- If PR open and Jira closed, backend sends Slack alert via Arcade
Slack.SendMessage
- Jira sends issue webhook to
/jira/webhook - If issue is closed, backend schedules 60s delayed check for linked PR records
- Backend re-checks PR + Jira via Arcade
- Policy rules decide whether to send Slack alert via Arcade
- Rules are loaded from
rules/*.yamlat startup. - Default policy file:
rules/default.yaml. - Current default rules:
pr_open=trueandjira_closed=true-> alert (pr_open_jira_closed)pr_open=falseandjira_closed=false-> alert (pr_closed_jira_open)
- You can add repo-specific rules by creating more YAML files in
rules/. - Message templates support placeholders like
{{jira_issue_key}},{{pr_url}},{{owner}},{{repo}}.
- Docker Desktop
- Arcade account + API key
- Arcade integrations connected for GitHub, Jira, Slack
- GitHub repo admin rights (webhook setup)
- Jira project admin rights (webhook setup)
Relevant docs:
cp .env.example .envRequired in .env:
ARCADE_API_KEYARCADE_USER_IDGITHUB_WEBHOOK_SECRET- One of:
SLACK_ALERT_CHANNELSLACK_ALERT_CONVERSATION_ID
Recommended:
JIRA_WEBHOOK_TOKEN
Defaults:
ALERT_DELAY_SECONDS=60JIRA_CLOSED_STATUS_KEYWORDS=done,closed,resolved
Multi-user optional:
TENANTS_CONFIG_PATH=./tenants.jsonADMIN_API_TOKEN=<strong-secret>- When enabled, tenant mappings override global routing for Arcade user, webhook validation, and Slack destination.
- Keep your existing
.envas-is (do not overwrite it). - Copy tenant template:
cp tenants.example.json tenants.json
- Edit
tenants.jsonwith each team/user:idarcade_user_idgithubowner/repo + webhook secretjiraproject key + webhook tokenslackdestination
- Add in
.env:TENANTS_CONFIG_PATH=./tenants.json
- Restart backend:
docker compose up --build -d
- Verify tenants loaded:
curl http://localhost:3000/tenants
- Tenant-specific auth check:
curl http://localhost:3000/auth/check/<tenant-id>
Use x-admin-token: <ADMIN_API_TOKEN> header.
Create tenant:
curl -X POST http://localhost:3000/admin/tenants \
-H "Content-Type: application/json" \
-H "x-admin-token: <ADMIN_API_TOKEN>" \
-d '{
"id": "team-kan",
"arcade_user_id": "team-kan@example.com",
"github": [{ "owner": "kinba09", "repo": "My_mini_pytorch", "webhook_secret": "..." }],
"jira": { "project_keys": ["KAN"], "webhook_token": "..." },
"slack": { "conversation_id": "C0123456789" }
}'Update tenant:
curl -X PUT http://localhost:3000/admin/tenants/team-kan \
-H "Content-Type: application/json" \
-H "x-admin-token: <ADMIN_API_TOKEN>" \
-d '<same JSON with updates>'Delete tenant:
curl -X DELETE http://localhost:3000/admin/tenants/team-kan \
-H "x-admin-token: <ADMIN_API_TOKEN>"docker compose up --buildHealth check:
curl http://localhost:3000/healthcurl http://localhost:3000/auth/checkOpen every authorization_url that is not completed.
For local development:
ngrok http 3000Use resulting HTTPS base URL for webhook endpoints.
GitHub -> Settings -> Webhooks -> Add webhook
- Payload URL:
https://<public-url>/webhook - Content type:
application/json - Secret: same as
GITHUB_WEBHOOK_SECRET - Events:
Pull requests
Jira -> System -> Webhooks -> Create
- URL:
- With token in query (easy setup):
https://<public-url>/jira/webhook?token=<JIRA_WEBHOOK_TOKEN>
- Or send header
x-jira-webhook-token: <JIRA_WEBHOOK_TOKEN>
- With token in query (easy setup):
- Events: Issue updated / transitioned (any event where closed status can be emitted)
- JQL (optional): narrow to your project
- Create Jira issue
JIRA-123. - Create branch
JIRA-123, push, open PR. - Close Jira issue but keep PR open.
- Wait 60 seconds.
- Verify Slack alert appears.
Also verify reverse trigger path:
- Merge or close PR.
- Keep Jira issue open (for example
To Do). - Wait 60 seconds.
- Verify Slack alert appears.
GET /healthGET /auth/checkGET /auth/check/:tenantIdGET /tenantsPOST /admin/tenantsPUT /admin/tenants/:tenantIdDELETE /admin/tenants/:tenantIdPOST /webhook(GitHub)POST /jira/webhook(Jira)
- The delayed checker uses local persisted state in
data/monitor-state.json. - State is local to this service instance.
- If you run multiple replicas, you should move state/timers to a shared queue/store (Redis + worker).