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

689 lines
19 KiB
Markdown

# 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:**
- **Primary URL**: https://t.lotusguild.org
- **Beta URL**: https://beta.t.lotusguild.org (React port - in development)
- **Web Server**: Nginx at 10.10.10.45 (`/var/www/html/tinkertickets`)
- **Database**: MariaDB on separate LXC (`ticketing_system` database)
## 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
```sql
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
```sql
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:**
```json
{
"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:**
```json
{
"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:**
```json
{
"ticket_id": "123456789",
"comment_text": "Comment content",
"markdown_enabled": true, // Optional, default false
"user_name": "User" // Optional, default "User"
}
```
**Response:**
```json
{
"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:**
```json
{
"title": "[hostname][auto][hardware]Issue[single-node][production][maintenance]",
"description": "Detailed hardware issue...",
"priority": "2",
"category": "Hardware",
"type": "Problem"
}
```
**Response:**
```json
{
"success": true,
"ticket_id": "123456789",
"message": "Ticket created successfully"
}
```
**OR** (if duplicate):
```json
{
"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`)
```ini
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`)
```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`
```ini
[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`
```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`
```bash
#!/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`
```nginx
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:**
```python
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.php``sendDiscordWebhook()` (lines 135-219):
- Change embed structure
- Modify color mapping
- Add/remove fields
- Update ticket URL
Also check `TicketController.php``sendDiscordWebhook()` (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
```bash
tail -f /tmp/api_debug.log
```
### JavaScript Issues
- Browser console (F12)
- Check Network tab for API responses
- Look for `console.log()` statements
### Database Issues
```bash
# Connect to MariaDB server
ssh root@<mariadb-ip>
mysql ticketing_system
```
### Deployment Issues
```bash
# 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
```bash
# 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
## Related Systems
### 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
- **Gitea:** https://code.lotusguild.org/LotusGuild/tinker_tickets
- **Production:** https://t.lotusguild.org
- **Beta:** https://beta.t.lotusguild.org
This is a personal project for infrastructure management. For issues, use the Gitea repository.