# Forgejo Integration The application syncs support tickets with Forgejo issues, providing a bridge between the customer-facing UI and internal issue tracking. ## Configuration Two environment variables are required for the integration: | Variable | Description | |----------|-------------| | `FORGEJO_URL` | Base URL of your Forgejo instance (e.g. `https://forgejo.example.com`) | | `FORGEJO_API_TOKEN` | Personal access token with permission to create issues and comments | See [Configuration](./configuration.md#forgejo) for the full reference. ## Ticket-to-Issue Sync When a customer creates a ticket: 1. The ticket is saved to the database immediately. 2. A goroutine asynchronously calls the Forgejo API to create a corresponding issue: - **Endpoint**: `POST /api/v1/repos/{owner}/{repo}/issues` - **Title**: Same as the ticket title - **Body**: Ticket description + a footer line identifying the submitting user's email 3. On success, the Forgejo issue number is stored on the ticket (`forgejo_issue_number`). If the API call fails, the error is logged but the ticket remains valid. The issue number will be `NULL`, meaning no further syncing occurs for that ticket. ## Comment Sync When a customer adds a comment to a ticket that has a linked Forgejo issue: 1. The comment is saved to the database immediately. 2. A goroutine asynchronously calls the Forgejo API to create a comment on the issue: - **Endpoint**: `POST /api/v1/repos/{owner}/{repo}/issues/{number}/comments` - **Body**: Comment text + a footer line identifying the commenting user's email 3. On success, the Forgejo comment ID is stored on the ticket comment (`forgejo_comment_id`). Comments are only synced if `forgejo_issue_number` is set on the ticket. ## Webhook Setup To receive events from Forgejo (e.g. issue closed), configure a webhook in each Forgejo repository: ### 1. Get the Webhook URL The URL follows the pattern: ``` {BASE_URL}/webhooks/forgejo/{slug} ``` Where `{slug}` is the repo slug configured in the [admin panel](./admin-guide.md#repos). For example: ``` https://tickets.example.com/webhooks/forgejo/my-product ``` ### 2. Configure in Forgejo In the Forgejo repository settings, go to **Webhooks** and add a new webhook: - **Target URL**: The webhook URL from step 1 - **HTTP Method**: POST - **Content Type**: `application/json` - **Secret**: Must match the webhook secret configured for this repo in the admin panel - **Events**: Select "Issues" (or use "Custom Events" and check "Issues") ### 3. Signature Verification All webhook requests are verified using HMAC-SHA256. The signature is read from the `X-Forgejo-Signature` header and compared against the computed HMAC of the request body using the repo's webhook secret. Requests with missing or invalid signatures are rejected with `401 Unauthorized`. ## Auto-Close Flow When an issue is closed in Forgejo, the following happens: 1. Forgejo sends a webhook POST to `{BASE_URL}/webhooks/forgejo/{slug}`. 2. The app verifies the HMAC-SHA256 signature against the repo's webhook secret. 3. The payload is parsed. Only `"action": "closed"` events are processed; all others return `200 OK` with no action. 4. The app looks up the ticket by `repo_id` and `forgejo_issue_number`. 5. If found, the ticket status is updated to `closed`. 6. A notification email is sent asynchronously to the ticket owner informing them their ticket has been resolved. This enables the internal team to close issues directly in Forgejo and have the status reflected in the customer-facing UI automatically. ## Architecture Notes - All Forgejo API calls (issue creation, comment creation) are **asynchronous** — they run in goroutines and don't block the HTTP response. - The API client uses a 30-second HTTP timeout. - Authentication uses the `Authorization: token {api_token}` header. - Webhook processing is **synchronous** — the ticket status update happens before returning the response to Forgejo. See [Admin Guide](./admin-guide.md#repos) for managing repos through the admin UI and [Deployment](./deployment.md) for webhook URL configuration in production.