# Redmine Issue API Helpdesk Include Patch

This repository carries a local RedmineUP Helpdesk API extension so external
indexers can keep Redmine issues as the canonical object while still seeing
Helpdesk customer metadata.

## Behavior

`GET /issues/:id.json?include=journals,helpdesk` returns the normal Redmine
issue API payload. When the issue also has a Helpdesk ticket, the issue object
includes:

```json
{
  "helpdesk_ticket": {
    "id": 35159,
    "contact_id": 1890,
    "message_id": "...",
    "source": 0,
    "is_incoming": true,
    "from_address": "customer@example.com",
    "to_address": "contact@ldrprep.com",
    "cc_address": "",
    "ticket_date": "2026-04-14T10:18:38Z",
    "contact": {
      "id": 1890,
      "name": "Customer Name",
      "company": "Customer Company",
      "email": "customer@example.com"
    }
  }
}
```

For ordinary non-Helpdesk issues, callers must tolerate either
`"helpdesk_ticket": null` or an omitted `helpdesk_ticket` field. The semantic
indexer treats both as ordinary issue data with no Helpdesk contact metadata.

## Patch Locations

- `plugins/redmine_contacts_helpdesk/app/views/issues/show.api.rsb`
  overrides Redmine 3.4.4's issue API view and adds the optional
  `include=helpdesk` block.
- `plugins/redmine_contacts_helpdesk/lib/redmine_helpdesk/issue_api_serializer.rb`
  serializes Helpdesk ticket/contact fields without changing controller logic.
- `plugins/redmine_contacts_helpdesk/lib/redmine_helpdesk.rb`
  loads the serializer during plugin preparation.

## Production Install Checklist

Install these files into the production Redmine tree, preserving paths:

```text
plugins/redmine_contacts_helpdesk/app/views/issues/show.api.rsb
plugins/redmine_contacts_helpdesk/lib/redmine_helpdesk/issue_api_serializer.rb
plugins/redmine_contacts_helpdesk/lib/redmine_helpdesk.rb
plugins/redmine_contacts_helpdesk/LOCAL_CHANGELOG.md
```

Before copying, create a production rollback directory and preserve any existing
versions of those files:

```sh
stamp=$(date -u +%Y%m%dT%H%M%SZ)
backup="$HOME/redmine-plugin-backups/helpdesk-issue-api-include-$stamp"
mkdir -p "$backup"
cd /usr/share/redmine
for path in \
  plugins/redmine_contacts_helpdesk/app/views/issues/show.api.rsb \
  plugins/redmine_contacts_helpdesk/lib/redmine_helpdesk/issue_api_serializer.rb \
  plugins/redmine_contacts_helpdesk/lib/redmine_helpdesk.rb \
  plugins/redmine_contacts_helpdesk/LOCAL_CHANGELOG.md
do
  if [ -e "$path" ]; then
    mkdir -p "$backup/$(dirname "$path")"
    cp -a "$path" "$backup/$path"
  fi
done
printf 'backup=%s\n' "$backup"
```

After copying, run syntax checks on the production host:

```sh
cd /usr/share/redmine
ruby -c plugins/redmine_contacts_helpdesk/lib/redmine_helpdesk.rb
ruby -c plugins/redmine_contacts_helpdesk/lib/redmine_helpdesk/issue_api_serializer.rb
ruby -c plugins/redmine_contacts_helpdesk/app/views/issues/show.api.rsb
```

Reload Passenger:

```sh
cd /usr/share/redmine
touch tmp/restart.txt
```

Then validate one known Helpdesk issue and one ordinary issue:

```sh
curl -sS -H "X-Redmine-API-Key: $REDMINE_API_KEY" \
  "$REDMINE_URL/issues/39779.json?include=journals,helpdesk" | jq '.issue.helpdesk_ticket'

curl -sS -H "X-Redmine-API-Key: $REDMINE_API_KEY" \
  "$REDMINE_URL/issues/<non_helpdesk_issue_id>.json?include=helpdesk" | jq '.issue.helpdesk_ticket'
```

The Helpdesk issue must include a ticket object with `contact.id`,
`contact.name`, and `contact.email`. The non-Helpdesk issue should not error;
`helpdesk_ticket` may be `null` or absent.

Rollback is copying the backup files over the deployed files and touching
`tmp/restart.txt` again. If a file did not exist before deployment, remove it
during rollback.

## Reapplying After Redmine Core Upgrade

1. Compare the upgraded Redmine `app/views/issues/show.api.rsb` against this
   repository's override.
2. Copy any new upstream issue API fields into the plugin override.
3. Keep the `include_in_api_response?('helpdesk')` block after the issue
   timestamps and before optional child/attachment/relation/journal sections.
4. Run:

```sh
ruby -c plugins/redmine_contacts_helpdesk/app/views/issues/show.api.rsb
ruby tests/redmine_contacts_helpdesk/test_issue_api_serializer.rb
```

5. On the LAN test instance, confirm:

```sh
curl -H "X-Redmine-API-Key: $REDMINE_API_KEY" \
  "http://192.168.50.170/issues/39779.json?include=journals,helpdesk"
```

The response should include `helpdesk_ticket.contact.id`,
`helpdesk_ticket.contact.name`, and `helpdesk_ticket.contact.email` for a
known Helpdesk issue.

## LAN Test Result

On 2026-04-25, the patch was deployed to the LAN Redmine copy at
`192.168.50.170`.

- Remote backup:
  `/home/reddev/redmine-plugin-backups/helpdesk-issue-api-include-20260425T094236Z`
- Syntax checks passed on the LAN host for the loader, serializer, and API view.
- `GET /issues/39779.json?include=journals,helpdesk` returned contact
  `#1890 Callum Mackeonis <callum@safetagtracking.com>`.
- `semantic_index inspect preview-redmine --limit 3 --project customer-service`
  showed contact metadata on issue, journal, and contact chunks before Qdrant
  rebuild.
