Ticket System
Ticket System provides structured two-way communication between users and administrators for customer support. Each ticket is a conversation thread with lifecycle management, priority levels, and automatic status transitions based on message activity.
Core Concept
A Ticket represents:
- Conversation thread: Series of messages between a user and admin team
- Priority: Low, Medium, or High (set by user at creation, helps admins triage)
- Status: Open, Pending, Resolved, or Closed (automatically transitions based on activity)
- Ownership: Tied to a specific user; only that user and admins can access it
- Title: Brief description for quick identification in ticket lists
Ticket Lifecycle
Status States
- Open: User has sent a message, awaiting admin response
- Pending: Admin has replied, awaiting user feedback
- Resolved: Admin has marked the issue as resolved
- Closed: Ticket is archived, no further messages allowed
Automatic Transitions
Status changes automatically based on who sends messages:
- User sends message → Open (even if previously Pending or Resolved)
- Admin replies to Open ticket → Pending
- Admin manually resolves → Resolved
- Admin manually closes → Closed
This state machine ensures tickets naturally reflect their support workflow without manual status management for most interactions.
Message Restrictions
- Resolved/Closed tickets: Cannot receive new messages
- Open/Pending tickets: Both users and admins can send messages
- Users can only edit their own messages; admins can only edit their own messages
- Admins can only delete their own messages (not for general moderation)
Architecture
Dual Service Design
The module exposes two separate gRPC services:
SupportService (User-facing):
- Create tickets
- List own tickets
- View ticket details (ownership validated)
- Send and edit own messages
- Close own tickets
SupportAdminService (Admin-facing):
- List all tickets (with pagination and optional unreplied filter)
- View any ticket detail
- Send admin responses
- Edit own messages
- Delete own messages
- Manually close or resolve tickets
This separation ensures clear permission boundaries and prevents accidental exposure of admin capabilities.
RBAC and Audit Logging
Admin operations integrate with the manage module’s RBAC system:
- Allowed Roles: SuperAdmin, Moderator, CustomerSupport, and SupportBot
- Audit Trail: All admin operations are logged with operation name, target, and input parameters
- Authorization: Role verification happens before operation execution via
AdminOperationtrait
Message Threading
Messages within a ticket follow these rules:
- Dual-author model: Each message has either
user_author_idORadmin_author_id(never both) - Edit tracking:
edited_attimestamp records when a message was last modified - Author metadata:
- User-facing API returns
FrontendTicketMessagewith enriched author data (name, avatar, email) joined from auth tables - Admin-facing API returns plain
TicketMessageobjects without enriched metadata
- User-facing API returns
- Sequential IDs: Messages use auto-incrementing integers for efficient database operations
Message Retrieval
Messages are returned with a simple limit-based approach:
- Default Limit: 100 messages per request
- Ordering: Messages are ordered by
sent_attimestamp in descending order (newest first) - No Pagination: Currently, there is no pagination support; all messages up to the limit are returned at once
Access Control
User Permissions
- Users can only view tickets they created (validated by
user_idmatch) - Users can only edit messages they authored
- Ticket ownership is checked on every operation (list, view, send message)
- Failed ownership checks return empty results or permission denied errors
Admin Permissions
- Admins can access all tickets through
SupportAdminService - Admin permissions are verified through the
managemodule’s RBAC system - Admins can perform operations like viewing all tickets, sending responses, and manually changing ticket status
- Admins can only edit or delete their own messages (ownership is checked)
Validation Layer
Input validation includes:
- Title validation: Non-empty, length limits (enforced at gRPC layer)
- Content validation: Non-empty, length limits for messages (enforced at gRPC layer)
- Ownership checks: Service-level validation verifies user owns the ticket/message before operations
Integration Points
Auth Module
- Ticket
user_idreferences users from auth module - User authentication context flows through
auth::rpc::middleware::UserIdfor user operations - Admin authentication flows through
manage::rpc::middleware::AdminIdfor admin operations
Database Schema
Lives in support PostgreSQL schema:
tickettable: Core ticket data with custom enums for priority and statusticket_messagetable: Messages with dual-author columns- Foreign keys to auth module’s user tables for referential integrity
Development Notes
- Ticket IDs are UUIDs for global uniqueness
- Message IDs are integers for simpler database management
- All service operations use the Processor pattern
- Status transition logic is implemented in
TicketStatusenum methods (on_user_message(),on_admin_reply()) - Status transitions happen automatically within the
CreateTicketMessagedatabase transaction - User-facing API gets enriched message data (
FrontendTicketMessage) with author metadata joined from user/admin tables - Admin operations use the
impl_recorded_admin_processor!macro for automatic audit logging - Admin message edit/delete operations enforce ownership validation at the service layer