# Tinker Tickets - Project Documentation for AI Assistants ## Project Status (January 2026) **Current Phase**: All 5 core features implemented and deployed. Ready for ANSI Art redesign. **Recent Completion**: - ✅ Activity Timeline (Feature 1) - ✅ Ticket Assignment (Feature 2) - ✅ Status Transitions with Workflows (Feature 3) - ✅ Ticket Templates (Feature 4) - ✅ Bulk Actions - Admin Only (Feature 5) **Next Priority**: 🎨 ANSI Art Redesign (major visual overhaul) ## Project Overview Tinker Tickets is a feature-rich, self-hosted ticket management system built for managing data center infrastructure issues. It features SSO integration with Authelia/LLDAP, workflow management, Discord notifications, and a comprehensive web interface. **Tech Stack:** - Backend: PHP 7.4+ with MySQLi - Frontend: Vanilla JavaScript, CSS3 - Database: MariaDB on separate LXC (10.10.10.50) - Web Server: Apache on production (10.10.10.45) - Authentication: Authelia SSO with LLDAP backend - External Libraries: marked.js (Markdown rendering) **Production Environment:** - **Primary URL**: http://t.lotusguild.org - **Web Server**: Apache at 10.10.10.45 (`/root/code/tinker_tickets`) - **Database**: MariaDB at 10.10.10.50 (`ticketing_system` database) - **Authentication**: Authelia provides SSO via headers ## Architecture ### MVC Pattern ``` Controllers → Models → Database ↓ Views ``` ### Project Structure (Updated) ``` /tinker_tickets/ ├── api/ # API endpoints │ ├── add_comment.php # POST: Add comment │ ├── assign_ticket.php # POST: Assign ticket to user (NEW) │ ├── bulk_operation.php # POST: Bulk operations - admin only (NEW) │ ├── get_template.php # GET: Fetch ticket template (NEW) │ ├── get_users.php # GET: Get user list (NEW) │ └── update_ticket.php # POST: Update ticket (workflow validation) ├── assets/ │ ├── css/ │ │ ├── dashboard.css # Shared + dashboard + bulk actions │ │ └── ticket.css # Ticket + timeline + dark mode fixes │ ├── js/ │ │ ├── dashboard.js # Dashboard + hamburger + bulk actions + templates │ │ └── ticket.js # Ticket + comments + status updates + assignment │ └── images/ │ └── favicon.png ├── config/ │ └── config.php # Config + .env loading ├── controllers/ # MVC Controllers │ ├── DashboardController.php # Dashboard with assigned_to column │ └── TicketController.php # Ticket CRUD + timeline + templates ├── models/ # Data models │ ├── AuditLogModel.php # Audit logging + timeline │ ├── BulkOperationsModel.php # Bulk operations tracking (NEW) │ ├── CommentModel.php # Comment data access │ ├── TemplateModel.php # Ticket templates (NEW) │ ├── TicketModel.php # Ticket CRUD + assignment │ ├── UserModel.php # User management (NEW) │ └── WorkflowModel.php # Status transition workflows (NEW) ├── views/ # PHP templates │ ├── CreateTicketView.php # Ticket creation with templates │ ├── DashboardView.php # Dashboard with bulk actions + assigned column │ └── TicketView.php # Ticket view with timeline + assignment ├── migrations/ # Database migrations │ ├── 001_initial_schema.sql │ ├── 007_add_ticket_assignment.sql # Ticket assignment │ ├── 008_add_status_workflows.sql # Workflow rules │ ├── 009_add_ticket_templates.sql # Ticket templates │ ├── 010_add_bulk_operations.sql # Bulk operations │ └── 011_remove_view_tracking.sql # Remove view audit logs ├── .env # Environment variables (GITIGNORED) ├── Claude.md # This file ├── README.md # User documentation ├── index.php # Dashboard entry point └── ticket.php # Ticket view/create router ``` ## Database Schema (Updated) **Database**: `ticketing_system` at 10.10.10.50 **User**: `tinkertickets` **Connection**: All APIs create their own connections via config.php ### Core Tables #### `tickets` Table (Updated) ```sql CREATE TABLE tickets ( ticket_id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL, description TEXT, status VARCHAR(50) DEFAULT 'Open', priority INT DEFAULT 4, category VARCHAR(50) DEFAULT 'General', type VARCHAR(50) DEFAULT 'Issue', created_by INT, -- User who created updated_by INT, -- User who last updated assigned_to INT, -- User assigned to (NEW) created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (created_by) REFERENCES users(user_id), FOREIGN KEY (updated_by) REFERENCES users(user_id), FOREIGN KEY (assigned_to) REFERENCES users(user_id) ON DELETE SET NULL, INDEX idx_status (status), INDEX idx_assigned_to (assigned_to) ) ENGINE=InnoDB; ``` #### `users` Table (SSO Integration) ```sql CREATE TABLE users ( user_id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(100) UNIQUE NOT NULL, display_name VARCHAR(255), email VARCHAR(255), is_admin BOOLEAN DEFAULT FALSE, last_login TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB; ``` #### `comments` Table ```sql CREATE TABLE comments ( comment_id INT AUTO_INCREMENT PRIMARY KEY, ticket_id INT NOT NULL, user_id INT, comment_text TEXT NOT NULL, markdown_enabled BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (ticket_id) REFERENCES tickets(ticket_id) ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES users(user_id), INDEX idx_ticket_id (ticket_id) ) ENGINE=InnoDB; ``` #### `audit_log` Table (Activity Timeline) ```sql CREATE TABLE audit_log ( log_id INT AUTO_INCREMENT PRIMARY KEY, user_id INT, action_type VARCHAR(50) NOT NULL, -- 'create', 'update', 'comment', 'assign', etc. entity_type VARCHAR(50) NOT NULL, -- 'ticket', 'comment' entity_id INT NOT NULL, -- ticket_id or comment_id details JSON, -- JSON details of what changed created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(user_id), INDEX idx_entity (entity_type, entity_id), INDEX idx_user (user_id), INDEX idx_action (action_type) ) ENGINE=InnoDB; ``` #### `status_transitions` Table (Workflow Rules) ```sql CREATE TABLE status_transitions ( transition_id INT AUTO_INCREMENT PRIMARY KEY, from_status VARCHAR(50) NOT NULL, to_status VARCHAR(50) NOT NULL, requires_comment BOOLEAN DEFAULT FALSE, -- Transition requires comment requires_admin BOOLEAN DEFAULT FALSE, -- Transition requires admin is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY unique_transition (from_status, to_status), INDEX idx_from_status (from_status) ) ENGINE=InnoDB; ``` Default transitions: ```sql -- Open → In Progress, Closed, Resolved -- In Progress → Open, Closed, Resolved -- Resolved → Closed, In Progress -- Closed → Open, In Progress (requires comment) ``` #### `ticket_templates` Table ```sql CREATE TABLE ticket_templates ( template_id INT AUTO_INCREMENT PRIMARY KEY, template_name VARCHAR(100) NOT NULL, title_template VARCHAR(255) NOT NULL, description_template TEXT NOT NULL, category VARCHAR(50), type VARCHAR(50), default_priority INT DEFAULT 4, created_by INT, is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (created_by) REFERENCES users(user_id), INDEX idx_template_name (template_name) ) ENGINE=InnoDB; ``` Default templates: Hardware Failure, Software Installation, Network Issue, Maintenance Request #### `bulk_operations` Table ```sql CREATE TABLE bulk_operations ( operation_id INT AUTO_INCREMENT PRIMARY KEY, operation_type VARCHAR(50) NOT NULL, -- 'bulk_close', 'bulk_assign', 'bulk_priority' ticket_ids TEXT NOT NULL, -- Comma-separated ticket IDs performed_by INT NOT NULL, parameters JSON, -- Operation parameters status VARCHAR(20) DEFAULT 'pending', total_tickets INT, processed_tickets INT DEFAULT 0, failed_tickets INT DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, completed_at TIMESTAMP NULL, FOREIGN KEY (performed_by) REFERENCES users(user_id), INDEX idx_performed_by (performed_by), INDEX idx_created_at (created_at) ) ENGINE=InnoDB; ``` ## API Endpoints (Updated) ### Authentication All API endpoints check: `$_SESSION['user']['user_id']` for authentication. Admin-only endpoints check: `$_SESSION['user']['is_admin']`. ### POST `/api/update_ticket.php` Updates ticket with workflow validation. **Request:** ```json { "ticket_id": 123, "status": "In Progress", // Validated against workflow rules "priority": 2, "title": "Updated title", "description": "...", "category": "Software", "type": "Task" } ``` **Response:** ```json { "success": true, "status": "In Progress", "priority": 2, "message": "Ticket updated successfully" } ``` **Features:** - Workflow validation via WorkflowModel - Partial updates (only send changed fields) - User tracking (updated_by) - Discord webhook notifications - Audit logging ### POST `/api/assign_ticket.php` (NEW) Assigns ticket to a user. **Request:** ```json { "ticket_id": 123, "assigned_to": 5 // user_id, or null to unassign } ``` **Response:** ```json { "success": true } ``` ### GET `/api/get_users.php` (NEW) Returns list of all users for assignment dropdowns. **Response:** ```json { "success": true, "users": [ { "user_id": 1, "username": "jared", "display_name": "Jared Vititoe", "is_admin": true } ] } ``` ### GET `/api/get_template.php?template_id=1` (NEW) Fetches a ticket template. **Response:** ```json { "success": true, "template": { "template_id": 1, "template_name": "Hardware Failure", "title_template": "Hardware Failure: [Device Name]", "description_template": "Device: \nIssue: \n...", "category": "Hardware", "type": "Problem", "default_priority": 2 } } ``` ### POST `/api/bulk_operation.php` (NEW - ADMIN ONLY) Performs bulk operations on tickets. **Request:** ```json { "operation_type": "bulk_close", // or 'bulk_assign', 'bulk_priority' "ticket_ids": [123, 456, 789], "parameters": { // For bulk_assign or bulk_priority "assigned_to": 5, // For bulk_assign "priority": 2 // For bulk_priority } } ``` **Response:** ```json { "success": true, "operation_id": 42, "processed": 3, "failed": 0, "message": "Bulk operation completed: 3 succeeded, 0 failed" } ``` ### POST `/api/add_comment.php` Adds comment to ticket. **Request:** ```json { "ticket_id": 123, "comment_text": "Comment content", "markdown_enabled": true } ``` **Response:** ```json { "success": true, "user_name": "Jared Vititoe", "created_at": "Jan 01, 2026 12:00" } ``` ## Key Features Implementation ### Feature 1: Activity Timeline **Location**: Ticket view → Activity tab **Implementation**: - `AuditLogModel->getTicketTimeline()` - Fetches all events for a ticket - Shows: creates, updates, comments, assignments, status changes - Displays: user, action, timestamp, details - CSS: timeline-content boxes with icons - Dark mode: Fully supported **Code**: `views/TicketView.php:258-282`, `models/AuditLogModel.php:getTicketTimeline()` ### Feature 2: Ticket Assignment **Location**: Ticket view → "Assigned to" dropdown, Dashboard → "Assigned To" column **Implementation**: - Database: `tickets.assigned_to` column - Models: `TicketModel->assignTicket()`, `TicketModel->unassignTicket()` - API: `api/assign_ticket.php` - Dashboard: Shows assigned user in table - Auto-saves on change - Audit logged **Code**: `views/TicketView.php:170-181`, `assets/js/ticket.js:handleAssignmentChange()` ### Feature 3: Status Transitions with Workflows **Location**: Ticket view → Status dropdown (header) **Implementation**: - Database: `status_transitions` table defines allowed transitions - Models: `WorkflowModel->isTransitionAllowed()`, `WorkflowModel->getAllowedTransitions()` - Dropdown shows only valid transitions for current status - Server-side validation prevents invalid changes - Can require comments or admin privileges - Removed from hamburger menu (was duplicate) **Code**: `models/WorkflowModel.php`, `api/update_ticket.php:130-144`, `views/TicketView.php:185-198` ### Feature 4: Ticket Templates **Location**: Create ticket page → Template selector **Implementation**: - Database: `ticket_templates` table - Models: `TemplateModel->getAllTemplates()`, `TemplateModel->getTemplateById()` - API: `api/get_template.php` - JavaScript: `loadTemplate()` in dashboard.js - Auto-fills: title, description, category, type, priority - 4 default templates included **Code**: `views/CreateTicketView.php:27-39`, `assets/js/dashboard.js:loadTemplate()` ### Feature 5: Bulk Actions (Admin Only) **Location**: Dashboard → Checkboxes + Toolbar (admins only) **Implementation**: - Database: `bulk_operations` table tracks operations - Models: `BulkOperationsModel->processBulkOperation()` - API: `api/bulk_operation.php` - UI: Toolbar appears when tickets selected - Operations: Bulk close, bulk assign, bulk priority - All operations audit logged - Server-side admin validation **Code**: `views/DashboardView.php:176-188`, `assets/js/dashboard.js:bulkClose()`, `models/BulkOperationsModel.php` ## Authentication & SSO Integration ### Authelia Integration User information passed via HTTP headers: - `Remote-User`: Username - `Remote-Name`: Display name - `Remote-Email`: Email - `Remote-Groups`: Comma-separated groups ### Session Management ```php $_SESSION['user'] = [ 'user_id' => 123, 'username' => 'jared', 'display_name' => 'Jared Vititoe', 'email' => 'jared@lotusguild.org', 'is_admin' => true // true if 'admins' in Remote-Groups ]; ``` ### Admin Privileges - Bulk operations (close, assign, priority) - Future: Admin-only transitions ## Frontend Components (Updated) ### Dashboard (`DashboardView.php` + `dashboard.js`) **Features**: - Sortable columns including new "Assigned To" column - Search (title, description, ticket_id, category, type) - Status filtering (default: Open + In Progress) - Pagination (configurable) - Dark mode toggle - **Bulk Actions Toolbar** (admin only): - Checkboxes on each ticket - "Select All" checkbox - Bulk close, assign, priority buttons - Shows count of selected tickets **Hamburger Menu**: - Category/Type filtering - Apply/Clear filters - No status field (removed) ### Ticket View (`TicketView.php` + `ticket.js`) **Features**: - **Tabbed Interface**: Description, Comments, Activity - **Activity Timeline**: Complete audit trail with icons - **Assignment Dropdown**: Assign to users - **Status Dropdown**: Workflow-validated status changes (header) - **Hamburger Menu**: Priority, Category, Type editing - **Edit Button**: Title and description editing - **Markdown Comments**: With live preview - **Dark Mode**: Comprehensive support **Visual Indicators**: - Priority colors (P1=Red, P2=Orange, P3=Blue, P4=Green, P5=Gray) - Status badges (Open=Green, In Progress=Yellow, Closed=Red, Resolved=Green) - Priority border colors on ticket container ### Create Ticket (`CreateTicketView.php`) **Features**: - **Template Selector**: Quick-fill from templates - Standard fields: title, description, status, priority, category, type - Form validation - Discord webhook on creation ## Dark Mode (Fixed) ### Comprehensive Dark Mode CSS **Files**: `assets/css/ticket.css`, `assets/css/dashboard.css` **Colors**: ```css body.dark-mode { --bg-primary: #1a202c; /* Main background */ --bg-secondary: #2d3748; /* Cards, inputs */ --bg-tertiary: #4a5568; /* Hover states */ --text-primary: #e2e8f0; /* Main text */ --text-secondary: #cbd5e0; /* Secondary text */ --text-muted: #a0aec0; /* Muted text */ --border-color: #4a5568; /* Borders */ } ``` **Fixed Elements**: - Timeline boxes (background + text) - Bulk actions toolbar - Tables and table rows - Input fields and textareas - Dropdowns and selects - Comment boxes - Modal dialogs - All text elements **Important**: Used `!important` flags to override any conflicting styles. ## Configuration ### Environment Variables (`.env`) ```ini DB_HOST=10.10.10.50 DB_USER=tinkertickets DB_PASS=password DB_NAME=ticketing_system DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/... ``` **CRITICAL**: `.env` is gitignored! Never commit this file. ### Apache Configuration **Virtual Host**: Apache serving from `/root/code/tinker_tickets` ```apache ServerName t.lotusguild.org DocumentRoot /root/code/tinker_tickets Options -Indexes +FollowSymLinks AllowOverride All Require all granted RewriteEngine On RewriteBase / RewriteRule ^ticket/([0-9]+)$ ticket.php?id=$1 [L,QSA] RewriteRule ^ticket/create$ ticket.php?action=create [L,QSA] ``` ## Deployment ### Git Auto-Deploy **Repository**: https://code.lotusguild.org/LotusGuild/tinker_tickets **Flow**: 1. Push to `main` branch 2. Auto-deploys to `/root/code/tinker_tickets` on 10.10.10.45 3. `.env` is preserved 4. Migrations must be run manually ### Running Migrations ```bash cd /root/code/tinker_tickets/migrations mysql -h 10.10.10.50 -u tinkertickets -p'pass' ticketing_system < 007_add_ticket_assignment.sql mysql -h 10.10.10.50 -u tinkertickets -p'pass' ticketing_system < 008_add_status_workflows.sql mysql -h 10.10.10.50 -u tinkertickets -p'pass' ticketing_system < 009_add_ticket_templates.sql mysql -h 10.10.10.50 -u tinkertickets -p'pass' ticketing_system < 010_add_bulk_operations.sql mysql -h 10.10.10.50 -u tinkertickets -p'pass' ticketing_system < 011_remove_view_tracking.sql ``` ## Development Guidelines ### Code Style - **PHP**: Tabs for indentation, prepared statements, `htmlspecialchars()` for output - **JavaScript**: Vanilla JS, `fetch()` for AJAX, clear function names - **CSS**: CSS variables for theming, mobile-responsive - **Security**: No SQL injection, XSS prevention, session validation ### Error Handling - APIs return JSON with `{success: bool, error: string}` - Debug logging to `/tmp/api_debug.log` (update_ticket.php) - User-friendly error messages ### Adding New Features 1. **Database**: Create migration in `migrations/` 2. **Model**: Add methods to relevant Model class 3. **API**: Create API endpoint in `api/` (with auth check) 4. **Controller**: Update controller to load data 5. **View**: Add UI elements 6. **JavaScript**: Add interactivity 7. **CSS**: Style for light + dark mode 8. **Test**: Test thoroughly before pushing ## ANSI Art Redesign (Next Priority) ### Goal Transform Tinker Tickets into a retro terminal aesthetic using ANSI art and ASCII characters. ### Design Concept - **Terminal-style borders**: Use box-drawing characters (┌─┐│└─┘) - **Monospace fonts**: Courier New, Consolas, Monaco - **ASCII art headers**: Stylized "TINKER TICKETS" banner - **Retro color palette**: Green terminal, amber terminal, or custom - **Template objects**: Reusable border/box components ### Implementation Approach 1. **CSS Variables**: Define ANSI color palette 2. **Border Components**: Create CSS classes for boxes with ASCII borders 3. **Typography**: Monospace fonts throughout 4. **Icons**: Replace emoji with ASCII art 5. **Dashboard**: Terminal-style table with borders 6. **Tickets**: Box-drawing characters for sections 7. **Forms**: Terminal-style input boxes ### Reference Colors (Classic Terminal) ```css :root { --ansi-black: #000000; --ansi-green: #00ff00; --ansi-amber: #ffb000; --ansi-blue: #0000ff; --ansi-cyan: #00ffff; --ansi-white: #ffffff; --ansi-bg: #000000; } ``` ### Example Box Template ``` ┌─────────────────────────────┐ │ TICKET #123 │ ├─────────────────────────────┤ │ Title: Hardware Failure │ │ Status: [OPEN] │ │ Priority: P1 (CRITICAL) │ └─────────────────────────────┘ ``` ## Debugging ### Common Issues ```bash # API debug logs tail -f /tmp/api_debug.log # Database connection mysql -h 10.10.10.50 -u tinkertickets -p ticketing_system # JavaScript console # Open browser DevTools (F12) → Console tab # Check dark mode # localStorage.getItem('theme') ``` ### Known Behaviors - Ticket viewing no longer tracked (011 migration removes view logs) - Status can only be changed via header dropdown (removed from hamburger) - Bulk actions only visible to admins - Templates are optional when creating tickets - Workflow validation prevents invalid status transitions ## Important Notes for AI Assistants 1. **All 5 features are complete and deployed** 2. **Dark mode is fixed** with comprehensive CSS 3. **Next priority is ANSI Art redesign** (major visual overhaul) 4. **Database at 10.10.10.50**, can't access directly from dev machine 5. **Auto-deploy is active**, test carefully before pushing 6. **Session format**: `$_SESSION['user']['user_id']` (not `$_SESSION['user_id']`) 7. **API auth**: Check `$_SESSION['user']['user_id']` exists 8. **Admin check**: `$_SESSION['user']['is_admin'] ?? false` 9. **Config path**: `config/config.php` (not `config/db.php`) 10. **Migrations**: Must be run manually on database server ## File Reference Quick Guide | File | Purpose | Key Functions | |------|---------|---------------| | `index.php` | Dashboard router | Database connection, routing | | `ticket.php` | Ticket router | View/create ticket routing | | `api/update_ticket.php` | Update API | Workflow validation, partial updates | | `api/assign_ticket.php` | Assignment API | Assign/unassign tickets | | `api/bulk_operation.php` | Bulk ops API | Admin bulk operations | | `api/get_template.php` | Template API | Fetch ticket templates | | `api/get_users.php` | Users API | Get user list | | `models/TicketModel.php` | Ticket data | CRUD, assignment, filtering | | `models/WorkflowModel.php` | Workflow rules | Status transition validation | | `models/AuditLogModel.php` | Audit logging | Timeline, activity tracking | | `models/TemplateModel.php` | Templates | Template CRUD | | `models/BulkOperationsModel.php` | Bulk ops | Process bulk operations | | `controllers/DashboardController.php` | Dashboard logic | Pagination, filters, assigned column | | `controllers/TicketController.php` | Ticket logic | CRUD, timeline, templates | | `assets/js/dashboard.js` | Dashboard UI | Filters, bulk actions, templates | | `assets/js/ticket.js` | Ticket UI | Status updates, assignment, comments | | `assets/css/dashboard.css` | Dashboard styles | Layout, table, bulk toolbar, dark mode | | `assets/css/ticket.css` | Ticket styles | Timeline, ticket view, dark mode | ## Repository & Contact - **Gitea**: https://code.lotusguild.org/LotusGuild/tinker_tickets - **Production**: http://t.lotusguild.org - **Infrastructure**: LotusGuild data center management