# Discord Updates Notifications — setup guide

Posts to Discord whenever a thread is created in **GCC > Updates** (Help Center
`ca=200`) — both auto-generated patch threads and admin-posted ones. The game
code is already wired (`app/s_discord_notify.cfm`, called from
`app/s_patch_threads.cfm` on auto-creation and `app/f_he_new.cfm` on manual
posts). It ships **inert**: until the webhook is configured, nothing happens.

## Why a webhook, not a hosted bot

The job is "post a message when the game creates a thread" — a Discord
**incoming webhook** does exactly this with zero hosting: no bot process, no
token to keep alive, no gateway connection. In the channel it looks like a bot
(custom name + avatar). A full bot application is only worth it if you later
want slash commands, scheduled posts, or reaction roles — see the last section.

## Message format (edit in `app/s_discord_notify.cfm`)

```
**GC Patch #107** is live.

Notes available here:
https://gcc.wrindustries.com/Forum/index.cfm?f=he_detail&hi=<threadId>&ch=200
https://gcc.wrindustries.com/i.cfm?p=changelog#patch-107

<blurb — per-def discordBlurb, or the post summary for manual posts>

@everyone        ← only when the def sets discordPing=true (majors);
                   manual admin posts always ping
```

Discord links must be **absolute** — the in-app relative-URL rule does not
apply to outbound content. `allowed_mentions` is set explicitly, so a
non-pinging post can never accidentally ping even if "@everyone" appears in
its text.

## Setup — step by step

1. **Create the webhook** (2 minutes, needs Manage Webhooks on the server):
   Discord → your server → the announcements channel (e.g. `#updates`) →
   Edit Channel → **Integrations → Webhooks → New Webhook**. Name it
   `GC Updates`, set an avatar if you like, **Copy Webhook URL**.
2. **Treat the URL as a secret.** Anyone holding it can post to the channel.
   Don't commit it, don't paste it in public channels. If it ever leaks:
   delete the webhook and make a new one (URL changes).
3. **Give it to the game via environment variable** `GCC_DISCORD_WEBHOOK`
   (read the same way as `GCC_ENV` / the DB credentials):
   - **Local dev**: add `GCC_DISCORD_WEBHOOK=https://discord.com/api/webhooks/…`
     to `dev/.env` (gitignored). `dev/docker-compose.yml` already passes it
     through to the app container. `docker compose up -d` to recreate.
   - **Prod**: set the same variable in the server environment where the other
     GCC_* variables live, then restart Lucee.
   - Leave it **unset** anywhere you don't want posts (that's the off switch —
     e.g. keep local dev unset, or point it at a private test channel's webhook).
4. **Test before go-live** (optional but recommended): make a second webhook in
   a private staff channel, set it in `dev/.env`, then on the local stack
   delete the System rows (`DELETE FROM he WHERE usernic='System' AND userid=0`),
   restart the app container, and load `i.cfm?p=changelog`. Three posts should
   arrive in order: #106.1, #106.2, then #107 (only #107 pings @everyone).
5. **Go-live**: with the prod webhook set, merge + deploy, then load the change
   log page once. The backlog clears itself: #106.1 → #106.2 → #107 threads are
   created oldest-first and announced in that order.
6. **Channel hygiene**: if you don't want members replying in the announcements
   channel, restrict Send Messages there; the webhook is unaffected.

## Quiet one-off entries — hand over the text, don't auto-post

The auto-post fires on forum-thread creation. **Minor one-off changelog entries
that get no forum thread** (see "Quiet entries" in `changelog-system.md`) also
get **no auto Discord** — instead, hand the user ready-to-paste text in chat
(no `@everyone`), and only when the change is worth announcing. Example shape:

```
**Patch #107.1** is live.

Notes here:
https://gcc.wrindustries.com/i.cfm?p=changelog#patch-107-1

The in-game chat display has been improved.
```

## Ongoing behavior — nothing to do per patch

- Adding a new patch def (`patch-forum-threads` skill) includes the
  `discordTitle` / `discordBlurb` / `discordPing` fields — the announcement
  fires automatically when the thread is generated on the first change log load.
- An admin manually posting an Update through the Help Center form (ca=200)
  also triggers a post automatically (title + links + the post's summary line,
  with @everyone).
- Failures are swallowed: Discord being down can never break thread creation
  or page rendering (fire-and-forget thread + try/catch at every layer).
- Multiple notifications in one page load (the backlog case) are staggered
  2.5s apart in their background threads so Discord receives them
  **oldest → newest** instead of racing; the page itself is never delayed.

## If you later want a full bot instead

1. discord.com/developers/applications → New Application → Bot → copy token.
2. Invite with `Send Messages` + `Mention Everyone` permissions.
3. Host a small service (Node/discord.js or Python/discord.py) that either
   polls `he` for new `type=200` rows or receives an HTTP call from the game
   (same call site as `gc_discordNotify`).
4. The game-side hook stays identical — you'd just point it at your service
   instead of the Discord webhook URL. Not needed for the current goal.
