# ZtoD Automation

AI-powered FastAPI service that bridges **Zammad** (support ticketing) and **Azure DevOps** (work tracking).

![Python](https://img.shields.io/badge/Python-3.11+-blue) ![FastAPI](https://img.shields.io/badge/FastAPI-0.110+-green) ![Docker](https://img.shields.io/badge/Docker-compose-blue)

## Features

- **Webhook automation** — receives Zammad `ticket.created` events, creates a DevOps Task under the current month's iteration and User Story
- **AI acknowledgment** — auto-replies to new tickets in the customer's language using Gemini, OpenAI, or Anthropic
- **AI tag suggestions** — suggests relevant tags from full ticket context (description, replies, customer email/org, domain aliases)
- **Activity classification** — AI classifies ticket into Design / Development / Deployment / Documentation / Requirements / Testing
- **Web UI** — create DevOps tasks manually from a Zammad ticket URL; dark/light mode, live SSE notifications
- **Form-based auth** — cookie session login with configurable timeout; HTTP Basic also accepted for API access
- **Monthly automation** — auto-creates iteration (`M_MAY_2026`) and User Story (`Maintenance :: May 2026`) if missing
- **Monthly log rotation** — separate `logs/YYYY-MM.log` and `logs/YYYY-MM-error.log`

## Quick Start

### Local

```bash
pip install -r requirements.txt
cp .env.example .env   # fill in credentials
uvicorn app.main:app --reload
```

### Docker

```bash
cp .env.example .env
mkdir -p logs
docker compose up --build -d
```

## Configuration

| Variable | Required | Default | Description |
|---|---|---|---|
| `ZAMMAD_URL` | Yes | — | Base URL of Zammad instance |
| `ZAMMAD_TOKEN` | Yes | — | Zammad API token |
| `DEVOPS_ORG` | Yes | — | Azure DevOps organisation name |
| `DEVOPS_PROJECT` | Yes | — | Project name |
| `DEVOPS_TEAM` | Yes | — | Team name (for iteration assignment) |
| `DEVOPS_PAT` | Yes | — | Personal access token (Work Items: Read & Write) |
| `DEVOPS_URL` | No | `https://dev.azure.com` | Override for self-hosted DevOps |
| `DEVOPS_ENABLED` | No | `true` | Set `false` to disable DevOps integration |
| `AI_PROVIDER` | No | `anthropic` | `anthropic` / `openai` / `gemini` |
| `ANTHROPIC_API_KEY` | No | — | Anthropic API key |
| `OPENAI_API_KEY` | No | — | OpenAI API key |
| `GEMINI_API_KEY` | No | — | Google Gemini API key (free tier: aistudio.google.com) |
| `WEBHOOK_SECRET` | No | — | HMAC-SHA1 secret; leave blank to skip verification |
| `WEBHOOK_ALLOWED_IPS` | No | — | Comma-separated IP allowlist; empty = allow all |
| `WEBHOOK_RATE_LIMIT` | No | `20/minute` | Rate limit in slowapi format |
| `WEB_USERNAME` | No | `admin` | Web UI username |
| `WEB_PASSWORD` | No | — | Web UI password; leave blank to disable auth |
| `SESSION_SECRET` | No | auto | Cookie signing key; auto-generated per process if blank |
| `SESSION_TIMEOUT` | No | `1800` | Session duration in seconds (default 30 min) |
| `NOTIFICATIONS_ENABLED` | No | `true` | Enable SSE live notifications in the web UI |
| `FIRST_COMMENT` | No | (built-in) | Text prepended to the Zammad acknowledgment comment |
| `VIRTUAL_HOST` | No | — | Hostname for Traefik routing |
| `DEBUG` | No | `false` | Enable debug logging |

## Webhook Setup (Zammad)

1. **Admin → Triggers → New Trigger**
   - Condition: `Ticket → Created`
   - Action: `Webhook → POST https://<host>/webhook/ticket-created`

2. If `WEBHOOK_SECRET` is set, add the same secret in the Zammad webhook config.

## Automation Flow

```
Zammad ticket created
  → POST /webhook/ticket-created  (HMAC-SHA1 verified, IP-filtered)
  → Fetch full ticket + articles + customer info from Zammad API
  → AI generates acknowledgment (language-detected)
  → Post acknowledgment comment to Zammad ticket
  → AI classifies activity type
  → Ensure monthly iteration exists in DevOps  (M_MAY_2026)
  → Ensure monthly User Story exists           (Maintenance :: May 2026)
  → Create Task under story with ticket link, estimates, activity
  → Broadcast SSE event to connected web UI clients
```

## Web Interface

Open `http://<host>:8000` → sign in → task creator.

1. Paste Zammad ticket URL → **Fetch** (resolves ticket ID, title, state, priority)
2. Click **✦ Suggest Tags** — AI reads full ticket + replies + customer org to suggest relevant tags
3. Pick tags from AI suggestions or type manually with autocomplete
4. Enter iteration name and User Story ID
5. **Verify & Create Task** — idempotently checks iteration/story, prevents duplicates

The UI supports **dark and light mode** (toggle in the top bar, persists via `localStorage`, respects `prefers-color-scheme` on first visit).

## Endpoints

| Method | Path | Description |
|---|---|---|
| `GET` | `/` | Web UI (task creator) |
| `GET` | `/login` | Login page |
| `POST` | `/login` | Submit credentials |
| `GET` | `/logout` | Clear session |
| `GET` | `/events` | SSE stream for live notifications |
| `GET` | `/web/ticket-info?url=` | Fetch ticket details from Zammad |
| `GET` | `/web/suggest-tags?ticket_id=` | AI tag suggestions for a ticket |
| `POST` | `/web/create-task` | Manually create DevOps task |
| `POST` | `/webhook/ticket-created` | Zammad webhook receiver |
| `GET` | `/health` | Health check |

## Logs

```
logs/
  2026-05.log          # INFO + WARNING
  2026-05-error.log    # ERROR + CRITICAL only
```

## Iteration Naming

Format: `M_{MONTH}_{YEAR}` → `M_MAY_2026`  
Story title: `Maintenance :: May 2026`  
Both auto-created if missing on first webhook for that month.
