- Add helpers/NotificationHelper.php: shared Matrix webhook sender
that reads MATRIX_WEBHOOK_URL and MATRIX_NOTIFY_USERS from config
- Remove sendDiscordWebhook() from TicketController; call
NotificationHelper::sendTicketNotification() instead
- Replace 60-line Discord embed block in create_ticket_api.php
with a single NotificationHelper call
- config/config.php: DISCORD_WEBHOOK_URL → MATRIX_WEBHOOK_URL +
new MATRIX_NOTIFY_USERS key (comma-separated Matrix user IDs)
- .env.example: updated env var names and comments
Payload sent to hookshot includes notify_users array so the
JS transform can build proper @mention links for each user.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Security:
- Fix IDOR in delete/update comment (add ticket visibility check)
- XSS defense-in-depth in DashboardView active filters
- Replace innerHTML with DOM construction in toast.js
- Remove redundant real_escape_string in check_duplicates
- Add rate limiting to get_template, download_attachment, audit_log,
saved_filters, user_preferences endpoints
Bug fixes:
- Session timeout now reads from config instead of hardcoded 18000
- TicketController uses $GLOBALS['config'] instead of duplicate .env parsing
- Add DISCORD_WEBHOOK_URL to centralized config
- Cleanup script uses hashmap for O(1) ticket ID lookups
Dead code removal (~100 lines):
- Remove dead getTicketComments() from TicketModel (wrong bind_param type)
- Remove dead getCategories()/getTypes() from DashboardController
- Remove ~80 lines dead Discord webhook code from update_ticket API
Consolidation:
- Create api/bootstrap.php for shared API setup (auth, CSRF, rate limit)
- Convert 6 API endpoints to use bootstrap
- Extract escapeHtml/getTicketIdFromUrl into shared utils.js
- Batch save for user preferences (1 request instead of 7)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add APP_DOMAIN config for correct Discord webhook ticket links
- Add "Assign To" dropdown on create ticket form
- Update TicketModel.createTicket() to support assigned_to field
- Update documentation for APP_DOMAIN requirement
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Consolidate StatsModel queries from 12 to 3 using conditional aggregation
- Add input validation to DashboardController (sort columns, dates, priorities)
- Combine getCategories/getTypes into single query
- Add transaction support to BulkOperationsModel with atomic mode option
- Add depth limit (20) to dependency cycle detection to prevent DoS
- Add caching to UserModel.getAllGroups() with 5-minute TTL
- Improve ticket ID generation with 50 attempts, exponential backoff, and fallback
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Consolidate all 20 API files to use centralized Database helper
- Add optimistic locking to ticket updates to prevent concurrent conflicts
- Add caching to StatsModel (60s TTL) for dashboard performance
- Add health check endpoint (api/health.php) for monitoring
- Improve rate limit cleanup with cron script and efficient DirectoryIterator
- Enable rate limit response headers (X-RateLimit-*)
- Add audit logging for workflow transitions
- Log Discord webhook failures instead of silencing
- Fix visibility check on export_tickets.php
- Add database migration system with performance indexes
- Fix cron recurring tickets to use assignTicket method
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Standardized embed format across both ticket creation paths
- Added consistent priority colors (P1-P5) with distinct hex values
- Added priority labels (e.g., "P1 - Critical" instead of just "1")
- Added Source field showing hostname extracted from ticket title
- Added Status field to both webhook formats
- Added footer distinguishing "Automated Alert" vs "Manual Entry"
- Added timestamp to API endpoint webhooks
- Added error logging for failed webhook calls
- Added timeout (10s) to API endpoint curl calls
- Added null check for webhook URL in API endpoint
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bug fixes:
- Fix ticket ID extraction using URLSearchParams instead of split()
- Add error handling for query result in get_users.php
- Make Discord webhook URLs dynamic (use HTTP_HOST)
Code cleanup:
- Remove debug console.log statements from dashboard.js and ticket.js
- Add getTicketIdFromUrl() helper function to both JS files
Documentation:
- Update Claude.md: fix web server (nginx not Apache), add new notes
- Update README.md: add keyboard shortcuts, update setup instructions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add cache busting query params to JS/CSS files (v=20260123)
- Add visibility group selection UI for editing existing tickets
- Add toggleVisibilityGroupsEdit() and getSelectedVisibilityGroups() functions
- Fix visibility data being saved when editing tickets
- Pass $conn to views for UserModel access
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixed all reported issues:
1. **Dark Mode Improvements:**
- Fixed bulk-actions-info white on white text (now yellow on dark background)
- Fixed timeline-content boxes with explicit dark mode colors
- All text now properly visible in dark mode
2. **Dashboard Enhancement:**
- Added "Assigned To" column showing ticket assignments
- Updated TicketModel query to include assigned user information
- Shows "Unassigned" when no user assigned
3. **Removed Ticket View Tracking:**
- Removed logTicketView call from TicketController
- Created migration 011 to delete all view records from audit_log
- Viewing tickets no longer clutters activity timeline
4. **Removed Duplicate Status Dropdown:**
- Removed status field from hamburger menu
- Status can now only be changed via the workflow-validated dropdown in ticket header
- Prevents confusion and ensures all status changes follow workflow rules
All changes improve usability and reduce clutter.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add ticket template system for quick ticket creation:
- Created TemplateModel.php with full CRUD operations for templates
- Added get_template.php API endpoint to fetch template data
- Updated TicketController to load templates in create() method
- Modified CreateTicketView.php to include template selector dropdown
- Added loadTemplate() JavaScript function to populate form fields
- Templates include: title, description, category, type, and default priority
- Database already seeded with default templates (Hardware Failure, Software Installation, Network Issue, Maintenance Request)
Users can now select from predefined templates when creating tickets, speeding up common ticket creation workflows.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add comprehensive workflow management system for ticket status transitions:
- Created WorkflowModel.php for managing status transition rules
- Updated TicketController.php to load allowed transitions for each ticket
- Modified TicketView.php to display dynamic status dropdown with only allowed transitions
- Enhanced api/update_ticket.php with server-side workflow validation
- Added updateTicketStatus() JavaScript function for client-side status changes
- Included CSS styling for status select dropdown with color-coded states
- Transitions can require comments or admin privileges
- Status changes are validated against status_transitions table
This feature enforces proper ticket workflows and prevents invalid status changes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add assigned_to column support in TicketModel with assignTicket() and unassignTicket() methods
- Create assign_ticket.php API endpoint for assignment operations
- Update TicketController to load user list from UserModel
- Add assignment dropdown UI in TicketView
- Add JavaScript handler for assignment changes
- Integrate with audit log for assignment tracking
Users can now assign tickets to team members via dropdown selector.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>