Files
tinker_tickets/Claude.md
2026-01-01 15:40:32 -05:00

19 KiB

Tinker Tickets - Project Documentation for AI Assistants

Project Overview

Tinker Tickets is a lightweight, self-hosted ticket management system built for managing data center infrastructure issues. It features automatic ticket creation via hardware monitoring integration, Discord notifications, and a clean web interface.

Tech Stack:

  • Backend: PHP 8+ with MySQLi
  • Frontend: Vanilla JavaScript, CSS3
  • Database: MariaDB (on separate LXC: 10.10.10.???)
  • Web Server: Nginx on production (10.10.10.45)
  • External Libraries: marked.js (Markdown rendering)

Production Environment:

Architecture

Project Structure

/tinker_tickets/
├── api/                          # API endpoints (standalone PHP files)
│   ├── add_comment.php          # POST: Add comment to ticket
│   └── update_ticket.php        # POST: Update ticket fields (partial updates)
├── assets/                       # Static assets
│   ├── css/
│   │   ├── dashboard.css        # Shared + dashboard styles
│   │   └── ticket.css           # Ticket page styles
│   ├── js/
│   │   ├── dashboard.js         # Dashboard + hamburger menu
│   │   └── ticket.js            # Ticket interactions
│   └── images/
│       └── favicon.png
├── config/
│   └── config.php               # Config + .env loading
├── controllers/                  # MVC Controllers
│   ├── CommentController.php    # Comment operations
│   ├── DashboardController.php  # Dashboard/listing
│   └── TicketController.php     # Ticket CRUD + webhooks
├── models/                       # Data models
│   ├── CommentModel.php         # Comment data access
│   └── TicketModel.php          # Ticket data access
├── views/                        # PHP templates
│   ├── CreateTicketView.php     # Ticket creation form
│   ├── DashboardView.php        # Main listing page
│   └── TicketView.php           # Single ticket view
├── .env                          # Environment variables (GITIGNORED)
├── .gitignore
├── create_ticket_api.php         # External API for hwmonDaemon
├── deploy.sh                     # Legacy manual deploy (not used)
├── index.php                     # Main entry point + router
└── README.md

Routing System (index.php)

Simple switch-based router:

  • / → Dashboard
  • /ticket/{id} → View ticket
  • /ticket/create → Create ticket form
  • /api/update_ticket.php → Update ticket (AJAX)
  • /api/add_comment.php → Add comment (AJAX)

Important Notes:

  • API routes handle their own database connections
  • Page routes receive connection from index.php
  • Legacy routes redirect to new URLs

Database Schema

Database Name: ticketing_system (NOT tinkertickets)

tickets Table

CREATE TABLE tickets (
  ticket_id VARCHAR(9) PRIMARY KEY,        -- 9-digit format with leading zeros
  title VARCHAR(255) NOT NULL,
  description TEXT,
  status VARCHAR(50) DEFAULT 'Open',       -- 'Open', 'Closed', 'In Progress', 'Pending'
  priority INT DEFAULT 4,                   -- 1=Critical, 2=High, 3=Medium, 4=Low, 5=Lowest
  category VARCHAR(50) DEFAULT 'General',   -- Hardware, Software, Network, Security, General
  type VARCHAR(50) DEFAULT 'Issue',         -- Maintenance, Install, Task, Upgrade, Issue
  hash VARCHAR(64),                         -- For duplicate detection (hwmonDaemon)
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB;

ticket_comments Table

CREATE TABLE ticket_comments (
  comment_id INT AUTO_INCREMENT PRIMARY KEY,
  ticket_id VARCHAR(10),
  user_name VARCHAR(50),
  comment_text TEXT,
  markdown_enabled TINYINT(1) DEFAULT 0,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (ticket_id) REFERENCES tickets(ticket_id)
) ENGINE=InnoDB;

Key Points:

  • Ticket IDs are VARCHAR (9-digit format with leading zeros)
  • Status ENUM-like validation in application layer
  • Hash field used for duplicate detection by hwmonDaemon
  • Comments support optional Markdown rendering

API Endpoints

POST /api/update_ticket.php

Updates ticket fields (supports partial updates).

Request:

{
  "ticket_id": 123456789,
  "status": "In Progress",      // Optional
  "priority": 2,                 // Optional (1-5)
  "title": "Updated title",      // Optional
  "description": "...",          // Optional
  "category": "Software",        // Optional
  "type": "Task"                 // Optional
}

Response:

{
  "success": true,
  "status": "In Progress",
  "priority": 2,
  "message": "Ticket updated successfully"
}

Features:

  • Merges updates with existing ticket data (partial updates)
  • Validates status against allowed values
  • Validates priority range (1-5)
  • Sends Discord webhook on changes
  • Debug logging to /tmp/api_debug.log

Discord Webhook:

  • Triggered on ticket updates
  • Shows field changes (old → new)
  • Color-coded by priority
  • Links to ticket URL
  • Only sends if changes detected

POST /api/add_comment.php

Adds a comment to a ticket.

Request:

{
  "ticket_id": "123456789",
  "comment_text": "Comment content",
  "markdown_enabled": true,      // Optional, default false
  "user_name": "User"            // Optional, default "User"
}

Response:

{
  "success": true,
  "user_name": "User",
  "created_at": "Jan 01, 2026 12:00",
  "markdown_enabled": 1,
  "comment_text": "Comment content"
}

POST /create_ticket_api.php

EXTERNAL API used by hwmonDaemon for automated ticket creation.

Request:

{
  "title": "[hostname][auto][hardware]Issue[single-node][production][maintenance]",
  "description": "Detailed hardware issue...",
  "priority": "2",
  "category": "Hardware",
  "type": "Problem"
}

Response:

{
  "success": true,
  "ticket_id": "123456789",
  "message": "Ticket created successfully"
}

OR (if duplicate):

{
  "success": false,
  "error": "Duplicate ticket",
  "existing_ticket_id": "987654321"
}

Special Features:

  • Duplicate detection via SHA-256 hashing
  • Hash based on: hostname, SMART attributes, environment tags, device
  • 24-hour duplicate window
  • Sends Discord webhook notification
  • Auto-creates tickets table if not exists

Frontend Components

Dashboard (views/DashboardView.php + assets/js/dashboard.js)

Features:

  • Pagination (default 15, configurable via settings)
  • Search (title, description, ticket_id, category, type)
  • Status filtering (Open, In Progress, Closed)
  • Category/Type filtering via hamburger menu
  • Column sorting (click headers)
  • Theme toggle (light/dark, persisted to localStorage)
  • Settings modal (rows per page)

Default Behavior:

  • Shows Open + In Progress tickets (Closed hidden)
  • Use ?show_all=1 to see all tickets
  • Use ?status=Open,Closed for specific statuses

Hamburger Menu:

  • Left sidebar with filters
  • Multi-select checkboxes
  • Apply/Clear filter buttons

Ticket View (views/TicketView.php + assets/js/ticket.js)

Features:

  • Tabbed interface (Description, Comments)
  • Inline editing via Edit button
  • Real-time status/priority indicators
  • Markdown support for comments
  • Live markdown preview toggle

Hamburger Menu (Ticket Page):

  • Quick edit: Status, Priority, Category, Type
  • Click value → dropdown → save/cancel
  • Updates main page elements dynamically
  • Changes ticket border color based on priority

Visual Indicators:

Priority Colors:

  • P1 (Critical): Red #ff4d4d
  • P2 (High): Orange #ffa726
  • P3 (Medium): Blue #42a5f5
  • P4 (Low): Green #66bb6a
  • P5 (Lowest): Gray #9e9e9e

Status Colors:

  • Open: Green #28a745
  • In Progress: Yellow #ffc107
  • Closed: Red #dc3545

Create Ticket (views/CreateTicketView.php)

Form Fields:

  • Title (required)
  • Description (required, textarea)
  • Status (dropdown, default: Open)
  • Priority (dropdown, default: P4)
  • Category (dropdown, default: General)
  • Type (dropdown, default: Issue)

On Submit:

  • Server-side validation
  • Discord webhook notification
  • Redirect to new ticket

Configuration

Environment Variables (.env)

DB_HOST=<mariadb-ip>
DB_USER=<username>
DB_PASS=<password>
DB_NAME=ticketing_system
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...

CRITICAL: .env is gitignored! Never commit this file.

Config (config/config.php)

$GLOBALS['config'] = [
    'DB_HOST' => $envVars['DB_HOST'],
    'DB_USER' => $envVars['DB_USER'],
    'DB_PASS' => $envVars['DB_PASS'],
    'DB_NAME' => $envVars['DB_NAME'],
    'BASE_URL' => '',              // Empty (serving from root)
    'ASSETS_URL' => '/assets',
    'API_URL' => '/api'
];

Deployment System

Auto-Deploy Pipeline

Gitea → Webhook → Production Server

  1. Push to main branch on Gitea (code.lotusguild.org)
  2. Gitea sends webhook to http://10.10.10.45:9000/hooks/tinker-deploy
  3. Webhook service validates signature and triggers deploy script
  4. Deploy script pulls code, preserves .env, sets permissions

Webhook Configuration

Service: /etc/systemd/system/webhook.service

[Unit]
Description=Webhook Listener for Auto Deploy
After=network.target

[Service]
ExecStart=/usr/bin/webhook -hooks /etc/webhook/hooks.json -port 9000
Restart=always
User=root

Hooks: /etc/webhook/hooks.json

{
  "id": "tinker-deploy",
  "execute-command": "/usr/local/bin/tinker_deploy.sh",
  "command-working-directory": "/var/www/html/tinkertickets",
  "response-message": "Deploying tinker_tickets...",
  "trigger-rule": {
    "match": {
      "type": "payload-hash-sha256",
      "secret": "...",
      "parameter": {
        "source": "header",
        "name": "X-Gitea-Signature"
      }
    }
  }
}

Deploy Script: /usr/local/bin/tinker_deploy.sh

#!/bin/bash
set -e
WEBROOT="/var/www/html/tinkertickets"

# Backup .env
if [ -f "$WEBROOT/.env" ]; then
    cp "$WEBROOT/.env" /tmp/.env.backup
fi

# Pull latest code
if [ ! -d "$WEBROOT/.git" ]; then
    rm -rf "$WEBROOT"
    git clone https://code.lotusguild.org/LotusGuild/tinker_tickets.git "$WEBROOT"
else
    cd "$WEBROOT"
    git fetch --all
    git reset --hard origin/main
fi

# Restore .env
if [ -f /tmp/.env.backup ]; then
    mv /tmp/.env.backup "$WEBROOT/.env"
fi

# Set permissions
chown -R www-data:www-data "$WEBROOT"

IMPORTANT NOTES:

  • Test thoroughly before pushing to main!
  • Low traffic (single user), so testing in production is acceptable
  • But avoid breaking changes
  • .env is preserved across deployments
  • Database changes require manual migration

Nginx Configuration

Site Config: /etc/nginx/sites-enabled/tinker_prod

server {
    listen 80;
    server_name t.lotusguild.org;
    root /var/www/html/tinkertickets;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php-fpm.sock;
    }

    location ~ /\.env {
        deny all;
    }
}

Key Points:

  • Clean URLs via try_files
  • PHP-FPM via Unix socket
  • .env explicitly denied

Hardware Monitoring Integration

hwmonDaemon Overview

The hwmonDaemon runs on all Proxmox VE servers as a systemd timer (hourly). It monitors:

  • SMART drive health
  • Disk usage
  • Memory (including ECC errors)
  • CPU usage
  • Network connectivity (Management + Ceph networks)
  • System logs for drive errors

When issues are detected, it automatically creates tickets via /create_ticket_api.php.

Daemon Configuration

Service: /etc/systemd/system/hwmon.service

  • Executes Python script from Gitea URL (self-updating)
  • Runs as root for hardware access
  • Auto-restarts on failure

Timer: /etc/systemd/system/hwmon.timer

  • Runs hourly
  • 5-minute randomized delay

API Endpoint:

TICKET_API_URL = 'http://10.10.10.45/create_ticket_api.php'

Ticket Title Format

hwmonDaemon creates tickets with structured titles:

[hostname][auto][hardware]Issue Description[single-node][production][maintenance]

Components:

  • [hostname]: Server name
  • [auto]: Automated creation
  • [hardware]: Issue category
  • Issue Description: e.g., "Drive /dev/sda has SMART issues: Reallocated_Sector_Ct"
  • [single-node]: Scope
  • [production]: Environment
  • [maintenance]: Ticket type

Duplicate Detection

Tickets are hashed based on:

  • Hostname
  • SMART attribute types (not values)
  • Environment tags
  • Device path (for drive issues)

Hash Window: 24 hours

This prevents duplicate tickets for the same issue on the same host.

Development Guidelines

Code Style

  • Tabs for indentation in PHP
  • Parameterized queries (prepared statements)
  • Output escaping with htmlspecialchars()
  • Error logging to /tmp/api_debug.log

Security Practices

  • SQL Injection: All queries use prepared statements
  • XSS: HTML output escaped
  • CSRF: Not implemented (single-user system)
  • Environment Variables: .env gitignored
  • File Permissions: www-data:www-data ownership

Error Handling

  • API endpoints use output buffering
  • Errors returned as JSON with success: false
  • Debug logging in /tmp/api_debug.log
  • Display errors disabled in production

JavaScript Patterns

  • Vanilla JavaScript (no framework)
  • DOMContentLoaded for initialization
  • fetch() for AJAX
  • window.ticketData for ticket pages
  • CSS class toggling for state changes

Common Tasks

Adding a New Ticket Field

  1. Database: Add column to tickets table on MariaDB server
  2. Model: Update TicketModel.php:
    • getTicketById()
    • updateTicket()
    • createTicket()
  3. API: Update update_ticket.php:
    • Add to validation
    • Add to merge logic (line 73-81)
  4. Views:
    • Add field to TicketView.php
    • Add field to CreateTicketView.php
  5. JavaScript: Add to hamburger menu in dashboard.js (if editable)
  6. CSS: Add styling if needed

Modifying Status/Priority Values

  1. API: Update validation in update_ticket.php:172
    • Status: Line 102-108
    • Priority: Line 93-98
  2. Views: Update dropdowns:
    • TicketView.php:410-414 (status)
    • TicketView.php:426-432 (priority)
    • CreateTicketView.php
  3. JavaScript: Update hamburger options in dashboard.js
  4. CSS: Add color classes to dashboard.css and ticket.css

Changing Discord Notifications

Edit update_ticket.phpsendDiscordWebhook() (lines 135-219):

  • Change embed structure
  • Modify color mapping
  • Add/remove fields
  • Update ticket URL

Also check TicketController.phpsendDiscordWebhook() (lines 128-207) for ticket creation webhooks.

Updating Pagination Defaults

  1. Controller: DashboardController.php:16 (default: 15)
  2. JavaScript: dashboard.js:128-133 (settings modal options)
  3. Cookie: Stored as ticketsPerPage

Known Behaviors & Quirks

Ticket ID Generation

  • Format: 9-digit random number with leading zeros
  • Generation: sprintf('%09d', mt_rand(1, 999999999))
  • Stored as VARCHAR
  • Collision possible (no uniqueness check beyond DB constraint)

Status Filtering

  • Default: Shows Open + In Progress (hides Closed)
  • ?show_all=1 → All statuses
  • ?status=Open,Closed → Specific statuses
  • No status param → Default behavior

Markdown Rendering

  • Client-side only (marked.js from CDN)
  • Toggle must be enabled before preview works
  • XSS Risk: Consider adding DOMPurify

CSS Class Naming

  • Status: status-Open, status-In-Progress, status-Closed
  • Spaces replaced with hyphens
  • Priority: priority-1 through priority-5

Theme Persistence

  • Stored: localStorage['theme']light or dark
  • Applied via data-theme attribute on <html>
  • CSS variables change based on theme

Debugging

API Issues

tail -f /tmp/api_debug.log

JavaScript Issues

  • Browser console (F12)
  • Check Network tab for API responses
  • Look for console.log() statements

Database Issues

# Connect to MariaDB server
ssh root@<mariadb-ip>
mysql ticketing_system

Deployment Issues

# On production server (10.10.10.45)
journalctl -u webhook.service -f
systemctl status webhook.service

# Manual deploy
cd /var/www/html/tinkertickets
git pull
chown -R www-data:www-data .

hwmonDaemon Issues

# On Proxmox server
journalctl -u hwmon.service -f
systemctl status hwmon.timer

# Manual test
python3 /path/to/hwmonDaemon.py --dry-run

Important Notes for AI Assistants

  1. Always read existing code before suggesting changes
  2. Test carefully - auto-deploy to production is enabled
  3. Database changes require manual migration (no auto-rollback)
  4. Preserve security (prepared statements, escaping, .env protection)
  5. Consider auto-deploy when making changes
  6. Single-user system - authentication/authorization not implemented
  7. hwmonDaemon integration - test with create_ticket_api.php
  8. Duplicate detection - understand hashing for automated tickets
  9. Discord webhooks - changes trigger notifications
  10. MariaDB on separate server - can't access directly from this machine

Future Considerations

Potential Improvements

  • User authentication/authorization
  • CSRF protection
  • File attachments
  • Email notifications
  • Advanced search/filters
  • Ticket assignment
  • Activity/audit log
  • API rate limiting
  • Database migrations system
  • Unit tests
  • DOMPurify for Markdown XSS protection

Performance Optimizations

  • Database indexes
  • Query caching
  • Lazy load comments
  • Minify/bundle assets

React Beta Site

  • URL: https://beta.t.lotusguild.org
  • Branch: react_test
  • Status: Early development (brother's project)
  • Deploy: Separate webhook + script (tinker_react_deploy.sh)
  • Location: /var/www/html/tinkertickets-react

File Reference Quick Guide

File Purpose Key Functions
index.php Router URL routing, DB connection
create_ticket_api.php hwmonDaemon API Duplicate detection, auto-tickets
api/update_ticket.php Update API Partial updates, Discord webhooks
api/add_comment.php Comment API Markdown-enabled comments
models/TicketModel.php Ticket data layer CRUD, filtering, sorting
models/CommentModel.php Comment data layer Get/add comments
controllers/DashboardController.php Dashboard logic Pagination, filters
controllers/TicketController.php Ticket logic CRUD, webhooks
assets/js/dashboard.js Dashboard UI Filters, sorting, hamburger
assets/js/ticket.js Ticket UI Edit mode, comments, markdown
assets/css/dashboard.css Shared styles Layout, table, theme
assets/css/ticket.css Ticket styles Ticket-specific components

Contact & Repository

This is a personal project for infrastructure management. For issues, use the Gitea repository.