# Custom Issue Statuses

Custom issue statuses extend Gitea's binary Open/Closed model with org-defined workflow states. Each status has a name, color, and an optional "closes issue" flag that triggers automatic close/reopen when selected.

## Overview

Statuses are defined at the **organization level** and appear in the issue sidebar for all repositories under that organization. This is the same pattern as org-level labels and custom fields.

### Key Concepts

- **Status definitions** are managed in Org Settings > Issue Statuses
- **Status selection** appears as a dropdown in the issue sidebar
- **Auto close/reopen** — selecting a status with `closes_issue = true` automatically closes the issue; switching to a non-closing status reopens it
- **Status is supplemental** — the existing Open/Closed binary state is preserved; statuses add granularity on top

## Org Settings

Navigate to **Organization Settings > Issue Statuses** to manage status definitions.

Each status has:

| Field | Description |
|-------|-------------|
| Name | Display name (e.g., "In Progress", "Won't Fix", "Blocked") |
| Color | Hex color for visual distinction (e.g., `#2563eb`) |
| Description | Help text shown to users |
| Closes Issue | When checked, selecting this status automatically closes the issue |
| Sort Order | Controls display order in dropdowns (ascending) |
| Is Active | Inactive statuses are hidden from dropdowns but preserved on existing issues |

### Default Statuses (auto-seeded)

| Status | Color | Closes Issue | Use Case |
|--------|-------|:------------:|----------|
| In Progress | Blue | No | Work is actively being done |
| Needs Info | Yellow | No | Waiting for more information |
| Blocked | Red | No | Cannot proceed due to dependency |
| Resolved | Green | Yes | Fix implemented and verified |
| Won't Fix | Gray | Yes | Decided not to address |
| Duplicate | Purple | Yes | Already tracked elsewhere |
| Pending: Design | Lavender | No | Waiting on design work |
| Pending: Testing | Yellow | No | Waiting for testing |
| Pending: Review | Green | No | Waiting for code review |
| Pending: Feedback | Pink | No | Waiting for feedback |
| Pending: Documentation | Purple | No | Waiting for docs |
| Pending: Deployment | Blue | No | Ready to deploy |
| Pending: Dependency | Light Blue | No | Blocked by external dependency |

Statuses are auto-seeded when an org first accesses them. Admins can add, edit, reorder, or deactivate statuses.

## Comment Form Integration

The status dropdown **replaces the close/reopen button** in the comment form footer for issues with org statuses:
- Open issues show all statuses plus a "Close" option
- Selecting a status with `closes_issue = true` auto-closes the issue
- Closed issues show only "Reopen" for non-admin users
- Admins see the full dropdown on closed issues including "Reopen"
- PRs still use the standard close/reopen button

## Issue List Badges

Status shows as a colored badge on each issue in the issue list view, alongside Type and Priority badges.

## Issue Sidebar

Status also appears as a read-only display in the sidebar (the editable control is in the comment form). The dropdown:
- Displays a colored left border on each option
- Shows a power symbol on statuses that close the issue
- Selecting "—" (empty) clears the status

### Auto Close/Reopen Behavior

| Current State | Selected Status | Result |
|:---:|---|---|
| Open | Status with `closes_issue = true` | Issue is closed automatically |
| Closed | Status with `closes_issue = false` | Issue is reopened automatically |
| Open | Status with `closes_issue = false` | Status set, issue stays open |
| Closed | Status with `closes_issue = true` | Status set, issue stays closed |

All close/reopen actions go through the standard Gitea service layer, so webhooks, notifications, and timeline events fire normally.

## Database

### Tables

**`issue_status_def`** (migration v346) — org-level status definitions

| Column | Type | Description |
|--------|------|-------------|
| id | bigint | Primary key |
| org_id | bigint | Organization ID |
| name | varchar | Status name |
| color | varchar(7) | Hex color |
| description | text | Help text |
| closes_issue | bool | Auto-close flag |
| sort_order | int | Display order |
| is_active | bool | Visibility flag |

**`issue`** table — added `status_id` column (bigint, default 0)

### Cascade on Delete

When a status definition is deleted, all issues referencing it have their `status_id` set to 0 (cleared). Issues are not closed or reopened during deletion.

## Routes

### Web Routes (Org Settings)

| Method | Path | Handler |
|--------|------|---------|
| GET | `/org/{org}/settings/issue-statuses` | `SettingsIssueStatuses` |
| POST | `/org/{org}/settings/issue-statuses` | `SettingsIssueStatusesCreatePost` |
| POST | `/org/{org}/settings/issue-statuses/{id}/edit` | `SettingsIssueStatusesEditPost` |
| POST | `/org/{org}/settings/issue-statuses/{id}/delete` | `SettingsIssueStatusesDeletePost` |

### Web Routes (Issue Sidebar)

| Method | Path | Handler |
|--------|------|---------|
| POST | `/{owner}/{repo}/issues/{id}/custom-status` | `UpdateIssueCustomStatus` |

---

| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-06-06 | Jonathan Miller (@jmiller) | Initial version |
