Skip to content

feat(wow): add crafting order board with persistent order management #227

@karaktaka

Description

@karaktaka

Summary

Add a crafting order board to the WoW module. An admin slash command posts a persistent board embed in a chosen channel. The board's available profession roles are set at creation time. Craftable items are fetched from the Blizzard Game Data API, filtered to only those requiring the in-game Crafting Order System (BOP items, not tradeable on the Auction House), and cached locally alongside their item IDs and icon URLs. A dedicated admin command refreshes the cache on demand. Each crafting order is tracked as its own embed — including the item's icon — with interactive buttons for status transitions, and includes a fallback thread for DM-gated communication.


Feature Description

1. Board Setup — /wow craftingorder create

An admin-only slash command that creates the order board in a target channel.

Parameter Type Description
channel TextChannel Channel where the board embed is posted
description str Body text shown in the board embed
roles str Space- or comma-separated role mentions — one per craftable profession

The command stores the channel, board message ID, and configured role list in the database. It then posts a persistent embed in the target channel containing a Create Crafting Order button.


2. Recipe Cache — /wow craftingorder recipe-sync

An admin-only slash command that fetches craftable item data from the Blizzard Game Data API, filters to crafting-order-eligible items only, and stores the result locally. Because recipes change only on major content patches, this is intentionally manual.

Fetch and filter sequence (via blizzapi.RetailClient):

  1. professions_index() — enumerate all profession IDs
  2. profession(professionId) — retrieve skill tiers; select only the current expansion skill tier
  3. profession_skill_tier(professionId, skillTierId) — retrieve the full recipe list for that tier
  4. For each recipe: recipe(recipeId) — retrieve the crafted item ID
  5. For each crafted item: item(itemId) — inspect the binding type field
  6. Filter: keep only items where binding type is BOP (Bind on Pickup — requires the Crafting Order System; not tradeable on the Auction House)
  7. For each kept item: item_media(itemId) — fetch the icon URL using the existing get_asset_url(response, "icon") helper from utils/blizzard.py

Stored per recipe:

Column Source Purpose
profession_id Step 2 Links recipe to profession
recipe_id Step 3 Original recipe identifier
item_id Step 4 Enables icon refresh and external links (e.g. Wowhead)
item_name Step 4/5 Shown in the Select menu and order embed
icon_url Step 7 Displayed as thumbnail in the order embed
last_synced Sync time Shown in the sync command's confirmation response

Implementation note: The exact response field path for binding type (expected: preview_item.binding.type, values "BOP" / "BOE") must be confirmed against a live Blizzard API response during implementation, as blizzapi is a schema-free HTTP wrapper.

Rate limiting: blizzapi does not auto-retry on 429 — every response must be checked via the existing check_rate_limit() in utils/blizzard.py. Add a small delay between item/media lookups and report a user-friendly error if rate-limited mid-sync.


3. Order Creation Flow

Because Discord modals only support text inputs (no dropdowns), item and profession selection happen as separate steps before the modal opens:

Step 1 — Profession select (ephemeral Select menu)
Options populated from the roles configured at board creation; labels are the role names.

Step 2 — Item select (ephemeral Select menu)
Options populated from the cached BOP item names for the chosen profession.

  • Discord Select menus support a maximum of 25 options; if the filtered list exceeds 25, show the first 25 alphabetically
  • Always appends "Other (specify below)" as the final option
  • Skipped entirely if no cache exists for the profession

Step 3 — Modal

  • Item Name — pre-filled with the selected item name; empty when "Other" or no cache
  • Additional Notes — free text (optional)

4. Order Embed

After submission, a new embed is posted in the board channel. If the item was selected from the dropdown and an icon_url is cached, it is displayed as the embed thumbnail — following the same pattern used by achievements and mounts elsewhere in the WoW module (embed.set_thumbnail(url=icon_url)).

Field Value
Item Name As submitted / selected
Profession Role name + role mention (e.g. Blacksmithing @Blacksmith)
Additional Notes As submitted
Posted by Mention of the order creator
Status Open / In Progress (@CrafterName) / Completed
(Thumbnail) Item icon from cached icon_url, if available

5. Order Buttons & Transitions

Button Who can use it Action
Accept Members with the order's profession role Sets status → In Progress (@Crafter)
Drop Active crafter or Admins Sets status → Open; clears crafter mention
Complete Active crafter or Admins Sets status → Completed; DMs creator; deletes embed
Cancel Order creator or Admins Sets status → Completed; deletes embed (see DM rules)
Ask Question Anyone Opens a modal with a Message field; creates a thread; pings creator

DM rules for Complete/Cancel:

  • Complete — DM to creator: "Your crafting order has been completed!"
  • Cancel by creator — no DM
  • Cancel by Admin — DM to creator: "Your crafting order has been cancelled!"
  • DM failure fallback — creates thread if absent, posts message there and pings creator

6. State Machine

Open
 └─[Accept]──► In Progress
                ├─[Drop]────► Open
                └─[Complete]► Completed (embed deleted)
Open / In Progress
 └─[Cancel]──► Completed (embed deleted)

Acceptance Criteria

  • /wow craftingorder create is guild-only and restricted to Admins
  • Command accepts channel, description, and roles parameters
  • Board embed is posted in the target channel and survives bot restarts
  • /wow craftingorder recipe-sync fetches profession recipe data from the Blizzard API
  • Sync filters to current expansion skill tier only
  • Sync filters to BOP items only (not tradeable on AH; require Crafting Order System)
  • Sync stores item_id, item_name, and icon_url per recipe entry
  • Sync stores a last_synced timestamp and reports it in the confirmation response
  • Sync handles 429 rate limits gracefully using the existing check_rate_limit() helper
  • Profession select menu is populated from the roles configured at board creation
  • Item select menu is shown after profession selection if cached BOP data exists; skipped otherwise
  • Item select always includes an "Other (specify below)" fallback option
  • If filtered item count exceeds 25, show first 25 alphabetically plus "Other"
  • Modal pre-fills Item Name when a specific item was selected; empty for "Other"/no-cache
  • Order embed displays all required fields including profession role mention
  • Order embed shows the item icon as thumbnail when icon_url is available
  • Status transitions enforce correct role/permission gating
  • Order embed is deleted after Completed or Cancelled
  • DMs are sent per the rules above; DM failure triggers thread fallback
  • Thread is created on "Ask Question"; creator is pinged inside it

Technical Notes

  • Store board config (channel ID, message ID, role IDs), recipe cache (per recipe: profession_id, recipe_id, item_id, item_name, icon_url, last_synced), and order metadata (including icon_url snapshot) in the database — new tables, no migration needed per project convention
  • Snapshot icon_url onto the order row at creation time so the embed can be reconstructed after restarts without a DB join on the cache
  • Use discord.ui.View with timeout=None and persistent custom_ids (e.g. crafting:accept:<order_id>) on order buttons; re-register on startup
  • Ephemeral Step 1/2 select views are short-lived — pass selected state into the modal via hidden TextInput with preset default, or store temporarily server-side keyed by user_id
  • Implement DM fallback before deleting the embed so the thread exists when needed

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions