Jared Vititoe ce95e555d5 CSS class migrations: admin views and boot overlay fade-out
- Replace style.display with .is-hidden classList in ApiKeysView, CustomFieldsView, RecurringTicketsView
- Convert boot overlay fade-out from style.opacity to .boot-overlay--fade-out CSS class
- Add .boot-overlay--fade-out rule to dashboard.css

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 21:20:55 -04:00
2026-01-01 15:40:32 -05:00

Tinker Tickets

A feature-rich PHP-based ticketing system designed for tracking and managing data center infrastructure issues with enterprise-grade workflow management and a retro terminal aesthetic.

Documentation: Wiki Design System: web_template — shared CSS, JS, and layout patterns for all LotusGuild apps

Styling & Layout

Tinker Tickets uses the LotusGuild Terminal Design System. For all styling, component, and layout documentation see:

Key conventions:

  • All .lt-* CSS classes come from base.css — do not duplicate them in assets/css/
  • All lt.* JS utilities come from base.js — use lt.toast, lt.modal, lt.api, etc.
  • CSP nonces: every <script> tag needs nonce="<?php echo $nonce; ?>"
  • CSRF: inject window.CSRF_TOKEN via the nonce-protected inline script block; lt.api.* adds the header automatically

Design Decisions

The following features are intentionally not planned for this system:

  • Email Integration: Discord webhooks are the chosen notification method
  • SLA Management: Not required for internal infrastructure use
  • Time Tracking: Out of scope for current requirements
  • OAuth2/External Identity Providers: Authelia is the only approved SSO method

Core Features

Dashboard & Ticket Management

  • View Modes: Toggle between Table view and Kanban card view
  • Collapsible Sidebar: Click the arrow to collapse/expand the filter sidebar
  • Inline Ticket Preview: Hover over ticket IDs for a quick preview popup (300ms delay)
  • Stats Widgets: Clickable cards for quick filtering (Open, Critical, Unassigned, Today's tickets)
  • Full-Text Search: Search across tickets, descriptions, and metadata
  • Advanced Search: Date ranges, priority ranges, user filters with saved filter support
  • Ticket Assignment: Assign tickets to specific users with quick-assign from dashboard
  • Priority Tracking: P1 (Critical) to P5 (Minimal Impact) with color-coded indicators
  • Custom Categories: Hardware, Software, Network, Security, General
  • Ticket Types: Maintenance, Install, Task, Upgrade, Issue, Problem
  • Export: Export selected tickets to CSV or JSON format
  • Ticket Linking: Reference other tickets in comments using #123456789 format

Ticket Visibility Levels

  • Public: All authenticated users can view the ticket
  • Internal: Only users in specified groups can view the ticket (at least one group required)
  • Confidential: Only the creator, assignee, and admins can view the ticket

Workflow Management

  • Status Transitions: Enforced workflow rules (Open → Pending → In Progress → Closed)
  • Workflow Designer: Visual admin UI at /admin/workflow to configure transitions
  • Workflow Validation: Server-side validation prevents invalid status changes
  • Admin Controls: Certain transitions can require admin privileges
  • Comment Requirements: Optional comment requirements for specific transitions

Collaboration Features

  • Markdown Comments: Full Markdown support with live preview, toolbar, and table rendering
  • @Mentions: Tag users in comments with autocomplete
  • Comment Edit/Delete: Comment owners and admins can edit or delete comments
  • Auto-linking: URLs in comments are automatically converted to clickable links
  • File Attachments: Upload files to tickets with drag-and-drop support
  • Ticket Dependencies: Link tickets as blocks/blocked-by/relates-to/duplicates
  • Activity Timeline: Complete audit trail of all ticket changes

Ticket Templates

  • Template Management: Admin UI at /admin/templates to create/edit templates
  • Quick Creation: Pre-configured templates for common issues
  • Auto-fill: Templates populate title, description, category, type, and priority

Recurring Tickets

  • Scheduled Tickets: Automatically create tickets on a schedule
  • Admin UI: Manage at /admin/recurring-tickets
  • Flexible Scheduling: Daily, weekly, or monthly recurrence
  • Cron Integration: Run cron/create_recurring_tickets.php to process

Custom Fields

  • Per-Category Fields: Define custom fields for specific ticket categories
  • Admin UI: Manage at /admin/custom-fields
  • Field Types: Text, textarea, select, checkbox, date, number
  • Required Fields: Mark fields as required for validation

API Key Management

  • Admin UI: Generate and manage API keys at /admin/api-keys
  • Bearer Token Auth: Use API keys with Authorization: Bearer YOUR_KEY header
  • Expiration: Optional expiration dates for keys
  • Revocation: Revoke compromised keys instantly

User Management & Authentication

  • SSO Integration: Authelia authentication with LLDAP backend
  • Role-Based Access: Admin and standard user roles
  • User Groups: Groups displayed in settings modal, used for visibility
  • User Activity: View per-user stats at /admin/user-activity
  • Session Management: Secure PHP session handling with timeout

Bulk Actions (Admin Only)

  • Bulk Close: Close multiple tickets at once
  • Bulk Assign: Assign multiple tickets to a user
  • Bulk Priority: Change priority for multiple tickets
  • Bulk Status: Change status for multiple tickets
  • Checkbox Click Area: Click anywhere in the checkbox cell to toggle

Admin Pages

Access all admin pages via the Admin dropdown in the dashboard header.

Route Description
/admin/templates Create and edit ticket templates
/admin/workflow Visual workflow transition designer
/admin/recurring-tickets Manage recurring ticket schedules
/admin/custom-fields Define custom fields per category
/admin/user-activity View per-user activity statistics
/admin/audit-log Browse all audit log entries
/admin/api-keys Generate and manage API keys

Notifications

  • Discord Integration: Webhook notifications for ticket creation and updates
  • Rich Embeds: Color-coded priority indicators and ticket links
  • Dynamic URLs: Ticket links adapt to the server hostname (set APP_DOMAIN in .env)

Keyboard Shortcuts

Shortcut Action
Ctrl/Cmd + E Toggle edit mode (ticket page)
Ctrl/Cmd + S Save changes (ticket page)
Ctrl/Cmd + K Focus search box (dashboard)
N New ticket (dashboard)
J / K Next / previous row (dashboard table)
Enter Open selected ticket (dashboard)
G then D Go to dashboard
14 Quick status change (ticket page)
ESC Cancel edit / close modal
? Show keyboard shortcuts help

Security Features

  • CSRF Protection: Token-based protection with constant-time comparison
  • Rate Limiting: Session-based AND IP-based rate limiting to prevent abuse
  • Security Headers: CSP with nonces (no unsafe-inline), X-Frame-Options, X-Content-Type-Options
  • SQL Injection Prevention: All queries use prepared statements with parameter binding
  • XSS Protection: HTML escaped in markdown parser, CSP headers block inline scripts
  • Audit Logging: Complete audit trail of all actions
  • Visibility Enforcement: Access checks on ticket views, downloads, and bulk operations
  • Collision-Safe IDs: Ticket IDs verified unique before creation

Technical Architecture

Backend

  • Language: PHP 7.4+
  • Database: MariaDB/MySQL
  • Architecture: MVC pattern with models, views, controllers
  • Authentication: Authelia SSO with LLDAP backend

Frontend

  • HTML5/CSS3: Semantic markup with retro terminal styling
  • JavaScript: Vanilla JS with Fetch API for AJAX
  • Markdown: Custom markdown parser with toolbar
  • Terminal UI: Box-drawing characters, monospace fonts, CRT effects
  • Mobile Responsive: Touch-friendly controls, responsive layouts

Database Tables

Table Purpose
tickets Core ticket data with visibility
ticket_comments Markdown-supported comments
ticket_attachments File attachment metadata
ticket_dependencies Ticket relationships
users User accounts with groups
user_preferences User settings
audit_log Complete audit trail
status_transitions Workflow configuration
ticket_templates Reusable templates
recurring_tickets Scheduled tickets
custom_field_definitions Custom field schemas
custom_field_values Custom field data
saved_filters Saved filter combinations
bulk_operations Bulk operation tracking
api_keys API key storage with hashed keys

tickets Table Key Columns

Column Type Description
ticket_id varchar(9) Unique 9-digit identifier
visibility enum public, internal, confidential
visibility_groups varchar(500) Comma-separated group names (for internal)
created_by int Foreign key to users
assigned_to int Foreign key to users (nullable)
updated_by int Foreign key to users
priority int 15 (1=Critical, 5=Minimal)
status varchar(20) Open, Pending, In Progress, Closed

Indexed Columns (performance)

  • tickets: ticket_id (unique), status, priority, created_at, created_by, assigned_to, visibility
  • audit_log: user_id, action_type, entity_type, created_at

API Endpoints

Endpoint Method Description
/api/update_ticket.php POST Update ticket with workflow validation
/api/assign_ticket.php POST Assign ticket to user
/api/add_comment.php POST Add comment to ticket
/api/get_template.php GET Fetch ticket template
/api/get_users.php GET Get user list for assignments
/api/bulk_operation.php POST Perform bulk operations
/api/ticket_dependencies.php GET/POST/DELETE Manage dependencies
/api/upload_attachment.php GET/POST List or upload attachments
/api/export_tickets.php GET Export tickets to CSV/JSON
/api/generate_api_key.php POST Generate API key (admin)
/api/revoke_api_key.php POST Revoke API key (admin)
/api/delete_comment.php POST Delete comment (owner/admin)
/api/update_comment.php POST Update comment (owner/admin)
/api/delete_attachment.php POST/DELETE Delete attachment
/api/download_attachment.php GET Download attachment (visibility checked)
/api/check_duplicates.php GET Check for duplicate tickets
/api/manage_recurring.php CRUD Recurring tickets (admin)
/api/manage_templates.php CRUD Templates (admin)
/api/manage_workflows.php CRUD Workflow rules (admin)

Project Structure

tinker_tickets/
├── api/
│   ├── add_comment.php                   # POST: Add comment
│   ├── assign_ticket.php                 # POST: Assign ticket to user
│   ├── bulk_operation.php                # POST: Bulk operations (admin only)
│   ├── check_duplicates.php              # GET: Check for duplicate tickets
│   ├── delete_attachment.php             # POST/DELETE: Delete attachment
│   ├── delete_comment.php                # POST: Delete comment (owner/admin)
│   ├── download_attachment.php           # GET: Download with visibility check
│   ├── export_tickets.php                # GET: Export tickets to CSV/JSON
│   ├── generate_api_key.php              # POST: Generate API key (admin)
│   ├── get_template.php                  # GET: Fetch ticket template
│   ├── get_users.php                     # GET: Get user list
│   ├── manage_recurring.php              # CRUD: Recurring tickets (admin)
│   ├── manage_templates.php              # CRUD: Templates (admin)
│   ├── manage_workflows.php              # CRUD: Workflow rules (admin)
│   ├── revoke_api_key.php                # POST: Revoke API key (admin)
│   ├── ticket_dependencies.php           # GET/POST/DELETE: Ticket dependencies
│   ├── update_comment.php                # POST: Update comment (owner/admin)
│   ├── update_ticket.php                 # POST: Update ticket (workflow validation)
│   └── upload_attachment.php             # GET/POST: List or upload attachments
├── assets/
│   ├── css/
│   │   ├── base.css                      # LotusGuild Terminal Design System (symlinked from web_template)
│   │   ├── dashboard.css                 # Dashboard + terminal styling
│   │   └── ticket.css                    # Ticket view styling
│   ├── js/
│   │   ├── advanced-search.js            # Advanced search modal
│   │   ├── ascii-banner.js               # ASCII art banner (rendered in boot overlay on first visit)
│   │   ├── base.js                       # LotusGuild JS utilities — window.lt (symlinked from web_template)
│   │   ├── dashboard.js                  # Dashboard + bulk actions + kanban + sidebar
│   │   ├── keyboard-shortcuts.js         # Keyboard shortcuts (uses lt.keys)
│   │   ├── markdown.js                   # Markdown rendering + ticket linking (XSS-safe)
│   │   ├── settings.js                   # User preferences
│   │   ├── ticket.js                     # Ticket + comments + visibility
│   │   ├── toast.js                      # Deprecated shim (no longer loaded — all callers use lt.toast directly)
│   │   └── utils.js                      # escapeHtml (→ lt.escHtml), getTicketIdFromUrl, showConfirmModal
│   └── images/
│       └── favicon.png
├── config/
│   └── config.php                        # Config + .env loading
├── controllers/
│   ├── DashboardController.php           # Dashboard with stats + filters
│   └── TicketController.php              # Ticket CRUD + timeline + visibility
├── cron/
│   └── create_recurring_tickets.php      # Process recurring ticket schedules
├── helpers/
│   └── ResponseHelper.php                # Standardized JSON responses
├── middleware/
│   ├── AuthMiddleware.php                # Authelia SSO integration
│   ├── CsrfMiddleware.php                # CSRF protection
│   ├── RateLimitMiddleware.php           # Session + IP-based rate limiting
│   └── SecurityHeadersMiddleware.php     # CSP with nonces, security headers
├── models/
│   ├── ApiKeyModel.php                   # API key generation/validation
│   ├── AuditLogModel.php                 # Audit logging + timeline
│   ├── BulkOperationsModel.php           # Bulk operations tracking
│   ├── CommentModel.php                  # Comment data access
│   ├── CustomFieldModel.php              # Custom field definitions/values
│   ├── DependencyModel.php               # Ticket dependencies
│   ├── RecurringTicketModel.php          # Recurring ticket schedules
│   ├── StatsModel.php                    # Dashboard statistics
│   ├── TemplateModel.php                 # Ticket templates
│   ├── TicketModel.php                   # Ticket CRUD + visibility + collision-safe IDs
│   ├── UserModel.php                     # User management + groups
│   ├── UserPreferencesModel.php          # User preferences
│   └── WorkflowModel.php                 # Status transition workflows
├── scripts/
│   ├── cleanup_orphan_uploads.php        # Clean orphaned uploads
│   └── create_dependencies_table.php     # Create ticket_dependencies table
├── uploads/                              # File attachment storage
├── views/
│   ├── admin/
│   │   ├── ApiKeysView.php               # API key management
│   │   ├── AuditLogView.php              # Audit log browser
│   │   ├── CustomFieldsView.php          # Custom field management
│   │   ├── RecurringTicketsView.php      # Recurring ticket management
│   │   ├── TemplatesView.php             # Template management
│   │   ├── UserActivityView.php          # User activity report
│   │   └── WorkflowDesignerView.php      # Workflow transition designer
│   ├── CreateTicketView.php              # Ticket creation with visibility
│   ├── DashboardView.php                 # Dashboard with kanban + sidebar
│   └── TicketView.php                    # Ticket view with visibility editing
├── .env                                  # Environment variables (GITIGNORED)
├── README.md                             # This file
└── index.php                             # Main router

Workflow States

Default Workflow

Open → Pending → In Progress → Closed
         ↑           ↑
         └───────────┘

All states can transition to Closed (with comment). Closed tickets can be reopened to Open or In Progress.

Setup & Configuration

1. Environment Configuration

Copy the example file and edit with your values:

cp .env.example .env
nano .env

Required environment variables:

DB_HOST=your_db_host
DB_USER=your_db_user
DB_PASS=your_password
DB_NAME=ticketing_system
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
APP_DOMAIN=your.domain.example
TIMEZONE=America/New_York

Note: APP_DOMAIN is required for Discord webhook ticket links to work correctly. Without it, links will default to localhost.

2. Cron Jobs

Add to crontab for recurring tickets:

# Run every hour to create scheduled recurring tickets
0 * * * * php /path/to/tinkertickets/cron/create_recurring_tickets.php

3. File Uploads

Ensure the uploads/ directory exists and is writable:

mkdir -p /path/to/tinkertickets/uploads
chown www-data:www-data /path/to/tinkertickets/uploads
chmod 755 /path/to/tinkertickets/uploads

4. Authelia Integration

Tinker Tickets uses Authelia for SSO. User information is passed via headers:

  • Remote-User: Username
  • Remote-Name: Display name
  • Remote-Email: Email address
  • Remote-Groups: User groups (comma-separated)

Admin users must be in the admin group in LLDAP.

Developer Notes

Key conventions and gotchas for working with this codebase:

  1. Session format: $_SESSION['user']['user_id'] (not $_SESSION['user_id'])
  2. API auth check: Verify $_SESSION['user']['user_id'] exists
  3. Admin check: $_SESSION['user']['is_admin'] ?? false
  4. Config path: config/config.php (not config/db.php)
  5. Comments table: ticket_comments (not comments)
  6. CSRF: Required for all POST/DELETE requests via X-CSRF-Token header
  7. Cache busting: Use ?v=YYYYMMDD query params on JS/CSS files
  8. Ticket linking: Use #123456789 in markdown-enabled comments
  9. User groups: Stored in users.groups as comma-separated values
  10. API routing: All API endpoints must be registered in index.php router
  11. Session in APIs: RateLimitMiddleware starts the session — do not call session_start() again
  12. Database collation: Use utf8mb4_general_ci (not unicode_ci) for new tables
  13. Discord URLs: Set APP_DOMAIN in .env for correct ticket URLs in Discord notifications
  14. Ticket ID extraction: Use getTicketIdFromUrl() helper in JS files
  15. CSP nonces: All inline <script> tags require nonce="<?php echo $nonce; ?>"
  16. Visibility validation: Internal visibility requires at least one group — validated server-side
  17. Rate limiting: Both session-based AND IP-based limits are enforced
  18. Relative timestamps: Dashboard dates use lt.time.ago() and refresh every 60s; full date is always in the title attribute for hover
  19. Boot sequence: Shows ASCII banner then boot messages on first page visit per session (sessionStorage.getItem('booted')); removed on subsequent loads
  20. No raw fetch(): All AJAX calls use lt.api.get/post/put/delete() — never use raw fetch(). The wrapper auto-adds Content-Type: application/json and X-CSRF-Token, auto-parses JSON, and throws on non-2xx.
  21. Confirm dialogs: Never use browser confirm(). Use showConfirmModal(title, message, type, onConfirm) (defined in utils.js, available on all pages). Types: 'warning' | 'error' | 'info'.
  22. utils.js on all pages: utils.js is loaded by all views (including admin). It provides escapeHtml(), getTicketIdFromUrl(), and showConfirmModal().
  23. No toast.js: toast.js is deprecated and no longer loaded by any view. Use lt.toast.success/error/warning/info() directly from base.js.
  24. CSS utility classes (dashboard.css): Use .text-green, .text-amber, .text-cyan, .text-danger, .text-open, .text-closed, .text-muted, .text-muted-green, .text-sm, .text-center, .nowrap, .mono, .fw-bold, .mb-1 for typography. Use .admin-container (1200px) or .admin-container-wide (1400px) for admin page max-widths. Use .admin-header-row for title+button header rows. Use .admin-form-row, .admin-form-field, .admin-label, .admin-input for filter forms. Use .admin-form-actions for filter form button groups. Use .table-wrapper + td.empty-state for tables. Use .setting-grid-2 and .setting-grid-3 for modal form grids. Use .lt-modal-sm or .lt-modal-lg for modal sizing.
  25. CSS utility classes (ticket.css): Use .form-hint (green helper text), .form-hint-warning (amber helper text), .visibility-groups-list (checkbox row), .group-checkbox-label (checkbox label) for ticket forms.

File Reference

File Purpose
index.php Main router for all routes
config/config.php Config loader + .env parsing
api/update_ticket.php Ticket updates with workflow + visibility validation
api/download_attachment.php File downloads with visibility check
api/bulk_operation.php Bulk operations with visibility filtering
models/TicketModel.php Ticket CRUD, visibility filtering, collision-safe ID generation
models/ApiKeyModel.php API key generation and validation
middleware/AuthMiddleware.php Authelia header parsing + session setup
middleware/CsrfMiddleware.php CSRF token generation and validation
middleware/SecurityHeadersMiddleware.php CSP headers with per-request nonce generation
middleware/RateLimitMiddleware.php Session + IP-based rate limiting
assets/js/dashboard.js Dashboard UI, kanban, sidebar, bulk actions
assets/js/ticket.js Ticket UI, visibility editing
assets/js/markdown.js Markdown parsing + ticket linking (XSS-safe)
assets/css/dashboard.css Terminal styling, kanban, sidebar

Security Implementations

Feature Implementation
SQL Injection All queries use prepared statements with parameter binding
XSS Prevention HTML escaped in markdown parser; CSP with per-request nonces
CSRF Protection Token-based with constant-time comparison (hash_equals)
Session Security Fixation prevention, secure cookies, session timeout
Rate Limiting Session-based + IP-based (file storage)
File Security Path traversal prevention, MIME type validation
Visibility Enforced on ticket views, downloads, and bulk operations

License

Internal use only - LotusGuild Infrastructure

Description
A PHP-based ticketing system with a clean web interface for managing and tracking hardware, software, and network issues in Lotus Guild Cluster
Readme 6.1 MiB
Languages
PHP 57.2%
CSS 23.8%
JavaScript 18.8%
Shell 0.2%