Skip to content

🎫 Tickets & Recruitment

Magikal has a panel-based ticket system for Support and Recruitment.

It is designed to keep user-facing flows simple while still giving staff proper logs, private channels, role handling, and permanent recruitment records.


🧭 What this system does

Area What it does
πŸ›Ÿ Support tickets Lets users open a private support channel from a panel button
πŸ“ Recruitment tickets Runs a guided application flow for Member/Affiliate applicants
❓ Quick Q&A Collects extra recruitment answers through a modal
🧾 Permanent records Posts long-term recruitment application records to a configured channel
βœ… Staff decisions Supports approve, decline, close, and finalise actions
πŸ”” Staff pings Pings configured support/recruitment staff roles
πŸ›°οΈ RSI integration Can show RSI profile/org info and optionally sync nickname on approve

Live source

This page is based on the current live files:

  • bot/cogs/tickets.py
  • bot/cogs/recruit_config.py
  • bot/storage/pg_config.py
  • bot/database.py

πŸ›Ÿ Support tickets

Support tickets are opened from a static support panel.

The user clicks Open Support Ticket, fills in an opening question, and the bot creates a private ticket channel.

Support flow

User clicks Support panel
        ↓
Bot opens modal for opening question
        ↓
Bot creates private ticket channel
        ↓
Optional support role is pinged
        ↓
Staff resolve the ticket
        ↓
Bot logs the result and deletes the channel

Support controls

Control Who uses it Purpose
Open Support Ticket Members Opens a private support ticket
Resolve (Staff) Staff with Manage Channels Opens a resolution modal, logs the result, then closes/deletes the ticket

Support ticket channels are deleted

Support ticket channels are deleted when resolved.

Users should save anything important before staff close the ticket.


πŸ“ Recruitment tickets

Recruitment tickets are more detailed than support tickets.

They are used for Member and Affiliate applications and include a guided application wizard, Q&A, staff review, RSI acceptance, and finalisation.

Recruitment flow

Applicant clicks Recruitment panel
        ↓
Private recruitment channel is created
        ↓
Applicant completes Step 1
        ↓
Applicant completes Quick Q&A
        ↓
Staff review the application
        ↓
Staff approve or decline
        ↓
If approved: applicant applies/gets accepted on RSI
        ↓
Staff finalise the ticket

🧩 Recruitment Step 1

When a recruitment ticket opens, the applicant completes Step 1 inside the private ticket channel.

They select:

Field Purpose
Member or Affiliate Decides which org role they are applying for
Main area/focus Example: medical, salvage, logistics, general
Time zone Used to understand availability
RSI handle Used for RSI lookup and optional nickname sync
Short intro/notes Free text from the applicant

The available area/focus options are managed by staff with /tickets add-option, /tickets remove-option, and /tickets list-options.

Keep options simple

Good recruitment options are short and obvious.

Examples: medical, salvage, logistics, security, industrial, general.


❓ Quick Q&A

After Step 1, the bot posts a Quick Q&A button in the applicant’s private ticket.

The applicant clicks Answer Q&A and fills in the configured questions.

Default Q&A questions

If no custom Q&A is configured, the bot falls back to a safe default set:

Question Type
Strengths Keywords
Availability Time range
Voice comms / mic ready Yes/No
Anything else we should know Paragraph

Q&A result

When Q&A is submitted, the bot:

Action Result
Saves answers Merges them into the recruitment application payload
Updates private ticket Shows Q&A as completed
Updates permanent record Marks the central embed as Q&A received
Removes the active button The Q&A tile becomes completed

Timezone handling

Availability is asked in the applicant’s local time.

The bot also stores a UK-time version where possible, using the selected time zone.


🧾 Permanent recruitment records

Recruitment applications can be posted to a configured permanent record channel.

This is separate from the temporary private ticket channel.

The permanent record contains:

Field Purpose
Status Pending, Q&A received, Approved, Declined, Finalised, Removed
Applicant Discord applicant mention
Requested role Member or Affiliate
Area/focus Selected recruitment option
RSI handle Applicant’s RSI handle
Ticket link Link to the private ticket while it exists
Time zone Local/UTC offset info
Notes/Q&A Applicant notes and Q&A answers

Permanent record matters

The private ticket channel may be deleted, but the permanent recruitment record remains.

This is the main place staff should use for long-term application tracking.


βœ… Approve, decline, and finalise

Recruitment uses a two-step approval model.

Approve

When staff click Approve, the bot:

Step Result
Assigns role Uses AutoRoles to grant Member/Affiliate role
Updates logs Sends an action log
Updates record Marks the application as approved
Keeps ticket open The channel remains open for RSI acceptance
Posts finalise control Staff get a Finalize β€” RSI accepted button

Approve does not delete the ticket

Approval is only Step 1.

The ticket stays open until staff confirm the RSI-side acceptance and click Finalize β€” RSI accepted.

Decline

When staff click Reject, the bot asks for a required decline reason.

The bot then:

Step Result
Saves reason Stores the staff reason on the permanent record
Updates status Marks the application as declined
Logs action Sends an action log
Deletes channel Closes and deletes the private ticket
DMs applicant Sends a generic rejection DM

Decline reason

The decline reason is saved on the permanent embed.

The applicant DM is generic and does not include sensitive internal notes.

Finalise

When staff click Finalize β€” RSI accepted, the bot:

Step Result
Updates permanent record Marks the application as finalised
Logs action Sends a finalisation log
Closes ticket Deletes the private ticket channel

πŸ”” Staff pings

Ticket pings are configured separately for support and recruitment.

Command Purpose
/tickets set-ping Set support and recruitment ping roles
/tickets show-ping Show current ping roles

The ping roles are also granted access to the private ticket channels.


πŸ“‚ Panel channels and ticket categories

Ticket panels and ticket creation categories are configured with:

/tickets set-targets

This command can set:

Target Purpose
Support panel channel Where the Support panel is posted
Recruitment panel channel Where the Recruitment panel is posted
Support category Where support ticket channels are created
Recruitment category Where recruitment ticket channels are created

The command also posts fresh panel messages and tries to remove older duplicate panel messages.

Use this to check current setup:

/tickets show-targets

Panel target behaviour

/tickets set-targets is not just a config command.

It also posts/refreshes the public support and recruitment panel messages.


πŸ›°οΈ RSI org settings

Recruitment embeds can include a configured RSI org page and image.

Command Purpose
/tickets set-org Set RSI org URL and optional image
/tickets show-org Show current RSI org settings

The recruitment panel can include an Apply on RSI button when an org URL is configured.


🧬 RSI nickname sync

Nickname sync is controlled by:

/tickets set-nick-sync enabled:true

When enabled, approval attempts to set the member’s nickname from their RSI handle/profile.

Nickname sync depends on Discord permissions

The bot must have Manage Nicknames and must be higher than the target member in the role hierarchy.

If Discord blocks the nickname change, the application can still continue.


πŸ“¨ DM-on-close behaviour

DM-on-close is controlled by:

/tickets set-dm-on-close enabled:true

Current behaviour:

Ticket type DM behaviour
Support Uses the configured DM-on-close setting
Recruitment declined Sends a generic rejection DM
Recruitment finalised/closed No DM

πŸ› οΈ Admin command summary

Ticket setup commands

Command Purpose
/tickets set-targets Set panel channels and ticket categories
/tickets show-targets Show current panel/category setup
/tickets set-ping Set support/recruitment ping roles
/tickets show-ping Show current ping roles
/tickets set-dm-on-close Enable/disable support close DMs
/tickets set-nick-sync Enable/disable RSI nickname sync
/tickets set-org Set RSI org URL/image
/tickets show-org Show RSI org URL/image
/tickets post-support-about Post a static support explainer embed

Recruitment option commands

Command Purpose
/tickets add-option Add a selectable recruitment area
/tickets remove-option Remove a selectable recruitment area
/tickets list-options List recruitment options and ping roles

Q&A recovery commands

Command Purpose
/tickets reopen-qna Repost Q&A button in the current recruitment ticket
!reopen_qna Prefix fallback for reposting Q&A

βš™οΈ Recruitment config commands

Recruitment configuration is handled by:

/recruit-config

These commands require the recruitment capability.

Command Purpose
/recruit-config set-log-channel Set permanent application record channel
/recruit-config set-access-mode Configure applicant access mode after approve
/recruit-config qa-list Show current Q&A questions
/recruit-config qa-add Add a Q&A question
/recruit-config qa-edit Edit a Q&A question
/recruit-config qa-move Reorder a Q&A question
/recruit-config qa-remove Remove a Q&A question
/recruit-config qa-reset-defaults Restore the recommended Q&A set
/recruit-config remove-member Mark a member as removed and update the record

Known access note

/recruit-config uses the recruitment capability.

Make sure the Recruitment role is correctly mapped in /roles set, otherwise intended staff may not be able to use these commands.


🧱 Storage model

Tickets and recruitment use Postgres via PgConfigStorage.

Data Table/model area
Ticket rows cfg.tickets
Ticket ping roles cfg.ticket_notify_roles
Ticket panel/category config cfg.ticket_panel_config
Recruitment options cfg.ticket_recruitment_options
RSI org panel settings cfg.recruit_panel_settings
Recruitment settings/Q&A cfg.recruit_settings
Recruitment applications cfg.recruit_applications

User-related records use PIDs where stored long-term.


πŸ” Privacy and logging

The ticket system follows the project privacy model:

Area Rule
Discord embeds Mentions and readable names are allowed for staff-facing Discord context
Database records Applicant/staff identity is stored with PIDs where applicable
Logs Should use structured key/value logs and avoid raw user IDs
Channel topics May contain operational markers such as TID, REQ, APP, TZ, and OPENER

Topic markers are operational

Ticket channel topics store markers used by persistent buttons after restarts.

Do not manually remove markers such as TID:, REQ:, APP:, TZ:, or OPENER: unless you know exactly why.


🩺 Troubleshooting

Q&A button is missing

Use this in the recruitment ticket channel:

/tickets reopen-qna

or fallback:

!reopen_qna

Approve says requested role is missing

Check the ticket channel topic contains:

REQ:member

or:

REQ:affiliate

If the topic marker is missing, the bot may try to recover from the application record.

Finalise says Ticket ID is missing

Check the topic contains:

TID:<ticket_id>
APP:<app_id>

The bot has fallback recovery from the application payload, but old tickets or manually edited topics can still lose context.

Applicant cannot see ticket

Check:

Item What to check
Category permissions Category is not blocking the user
Channel overwrites Applicant has View Channel and Send Messages
Ping role Recruitment/support role has access
Bot role Bot can Manage Channels

Staff cannot click controls

Most staff controls require Discord permissions such as:

Control Likely required permission
Resolve support Manage Channels
Approve/reject recruitment Manage Channels
Finalise recruitment Manage Guild

Safe edit warnings after deletion

The bot uses a debounced safe edit helper to reduce Discord PATCH spam.

If a ticket closes while an edit is pending, the code is designed to skip missing-channel edits instead of treating them as fatal.


βœ… Testing checklist

After ticket changes, test:

  • Support panel opens a private channel
  • Support resolve logs and deletes the channel
  • Recruitment panel opens a private channel
  • Step 1 wizard works
  • Q&A saves and updates both ticket and permanent record
  • Approve grants the correct role
  • Decline requires a reason and updates the permanent record
  • Finalise updates the permanent record and deletes the channel
  • Staff pings are correct
  • Panel channels and categories are correct
  • Logs do not expose raw Discord IDs
  • Permanent record channel receives application embeds

🧠 Rule

Ticket channels are temporary.

Recruitment records are permanent.

The bot should keep the applicant flow simple, give staff clear controls, and preserve important recruitment history in the configured record channel.