# JIRA AI Fixer - Developer Guide ## Overview JIRA AI Fixer is a universal AI-powered issue analysis engine that integrates with multiple issue tracking systems to automatically analyze support cases and suggest code fixes. ## Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ JIRA AI Fixer │ ├─────────────────────────────────────────────────────────────────┤ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │TicketHub │ │ JIRA │ │ServiceNow│ │ Zendesk │ ... │ │ │ Webhook │ │ Webhook │ │ Webhook │ │ Webhook │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ │ │ │ │ │ └─────────────┴──────┬──────┴─────────────┘ │ │ │ │ │ ┌───────▼───────┐ │ │ │ Normalizer │ (Adapter Pattern) │ │ └───────┬───────┘ │ │ │ │ │ ┌───────▼───────┐ │ │ │ Analyzer │ (LLM + Code Analysis) │ │ └───────┬───────┘ │ │ │ │ │ ┌─────────────┼─────────────┐ │ │ │ │ │ │ │ ┌──────▼─────┐ ┌─────▼─────┐ ┌────▼────┐ │ │ │ Database │ │ PR Gen │ │Callback │ │ │ │ PostgreSQL │ │ Gitea │ │ to Src │ │ │ └────────────┘ └───────────┘ └─────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ## Tech Stack - **Language**: Python 3.11 - **Framework**: FastAPI (async) - **Database**: PostgreSQL 15 - **LLM**: OpenRouter API (Llama 3.3 70B free tier) - **Code Hosting**: Gitea (self-hosted) ## Project Structure ``` jira-ai-fixer/ ├── api/ │ └── main_v3.py # Main application (monolith) ├── docs/ │ ├── DEVELOPER_GUIDE.md │ ├── USER_GUIDE.md │ └── ARCHITECTURE.md └── README.md ``` ## Key Components ### 1. Webhook Adapters Each supported system has a dedicated adapter that normalizes payloads: ```python def normalize_jira(payload: dict) -> Optional[NormalizedIssue]: """Normalize JIRA webhook payload""" issue = payload.get("issue", {}) fields = issue.get("fields", {}) return NormalizedIssue( external_id=str(issue.get("id")), external_key=issue.get("key"), source="jira", title=fields.get("summary"), description=fields.get("description"), callback_url=f"{base_url}/rest/api/2/issue/{issue.get('key')}/comment" ) ``` ### 2. Analysis Pipeline ```python async def analyze_issue(issue_id: int, issue: NormalizedIssue): # 1. Fetch source code from repositories cobol_files = await fetch_cobol_files() # 2. Build LLM prompt prompt = build_analysis_prompt(issue, cobol_files) # 3. Call LLM API analysis = await call_llm(prompt) # 4. Parse response result = parse_analysis(analysis) # 5. Create fix branch and PR pr_info = await create_fix_branch_and_pr(issue, result) # 6. Post back to source system await post_analysis_to_source(issue, result, pr_info) ``` ### 3. Callback System Results are posted back to the source system in their native format: | System | Method | Format | |--------|--------|--------| | TicketHub | POST /tickets/{id}/comments | `{"author": "...", "content": "..."}` | | JIRA | POST /rest/api/2/issue/{key}/comment | `{"body": "..."}` | | ServiceNow | PATCH /api/now/table/incident/{sys_id} | `{"work_notes": "..."}` | | Zendesk | PUT /api/v2/tickets/{id}.json | `{"ticket": {"comment": {...}}}` | | Azure DevOps | POST /workitems/{id}/comments | `{"text": "..."}` | | GitHub | POST /repos/.../issues/{n}/comments | `{"body": "..."}` | ## Adding a New Integration 1. Create normalizer function: ```python def normalize_newsystem(payload: dict) -> Optional[NormalizedIssue]: # Extract fields from payload return NormalizedIssue( external_id=..., external_key=..., source="newsystem", title=..., description=..., callback_url=... ) ``` 2. Add webhook endpoint: ```python @app.post("/api/webhook/newsystem") async def webhook_newsystem(payload: dict, background_tasks: BackgroundTasks): issue = normalize_newsystem(payload) if not issue: return WebhookResponse(status="ignored", message="Event not handled") issue_id = await save_and_queue_issue(issue, background_tasks) return WebhookResponse(status="accepted", issue_id=issue_id) ``` 3. Add callback format in `post_analysis_to_source()`: ```python elif issue.source == "newsystem": await client.post(issue.callback_url, json={...}) ``` ## Environment Variables | Variable | Description | Default | |----------|-------------|---------| | `DATABASE_URL` | PostgreSQL connection string | `postgresql://jira:jira_secret_2026@postgres:5432/jira_fixer` | | `OPENROUTER_API_KEY` | OpenRouter API key for LLM | (empty = mock mode) | | `GITEA_URL` | Gitea instance URL | `https://gitea.startdata.com.br` | | `GITEA_TOKEN` | Gitea API token | (empty) | | `COBOL_REPO` | Default repository to analyze | `startdata/cobol-sample-app` | ## API Endpoints ### Webhooks | Endpoint | Description | |----------|-------------| | `POST /api/webhook/tickethub` | TicketHub webhooks | | `POST /api/webhook/jira` | JIRA webhooks | | `POST /api/webhook/servicenow` | ServiceNow webhooks | | `POST /api/webhook/zendesk` | Zendesk webhooks | | `POST /api/webhook/azure-devops` | Azure DevOps webhooks | | `POST /api/webhook/github` | GitHub Issues webhooks | | `POST /api/webhook/gitlab` | GitLab Issues webhooks | | `POST /api/webhook/generic` | Generic webhook format | ### Management | Endpoint | Description | |----------|-------------| | `GET /api/health` | Health check | | `GET /api/issues` | List issues | | `GET /api/issues/{id}` | Get issue details | | `GET /api/integrations` | List integrations | | `GET /api/stats` | Dashboard statistics | ## Running Locally ```bash # Install dependencies pip install fastapi uvicorn httpx asyncpg pydantic # Run with PostgreSQL export DATABASE_URL="postgresql://user:pass@localhost:5432/jira_fixer" uvicorn main:app --reload --port 8000 ``` ## Testing Webhooks ```bash # Test TicketHub webhook curl -X POST http://localhost:8000/api/webhook/tickethub \ -H "Content-Type: application/json" \ -d '{ "event": "ticket.created", "timestamp": "2026-02-18T18:00:00Z", "data": { "id": 1, "key": "SUPP-1", "title": "Test issue", "description": "Test description" } }' # Test generic webhook curl -X POST http://localhost:8000/api/webhook/generic \ -H "Content-Type: application/json" \ -d '{ "id": "123", "key": "CUSTOM-1", "title": "Custom issue", "description": "From custom system", "source": "my-system", "callback_url": "https://my-system.com/api/issues/123/comments" }' ``` ## License MIT License - StartData 2026