jared c442e2d47f Fix AttachmentModel ticket_id binding to preserve leading zeros
All ticket_id parameters were bound as integer ("i"), which stripped
leading zeros before insertion into ticket_attachments.ticket_id
(VARCHAR 9). This caused a mismatch: upload_attachment.php creates
the directory using the full string (e.g. /uploads/000123456/) but
the DB stored the integer form ("123456"), so download and delete
would look in the wrong path.

Changed getAttachments, addAttachment, getTotalSizeForTicket, and
getAttachmentCount to use string binding ("s") so the canonical
zero-padded ticket ID is stored and read back consistently.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 13:40:15 -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: Matrix (hookshot webhook) is the chosen external notification method
  • 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 (drag-and-drop status changes)
  • Right Drawer Preview: Click any ticket title to open a quick-preview panel without navigating away
  • Stats Widgets: Clickable cards for quick filtering (Open, Critical, Unassigned, Today's tickets) with live trend indicators
  • Charts: Priority distribution donut, status breakdown donut, and category bar chart (Chart.js, CDN)
  • Team Workload: Collapsible panel showing open ticket count per assignee with progress bars
  • Full-Text Search: Search across tickets, descriptions, and metadata
  • Advanced Search: Date ranges (Flatpickr), priority ranges, user filters
  • Saved Filters: Save and recall filter presets; quick-switch pills above the table
  • Column Visibility: Toggle which dashboard table columns are shown; persisted in localStorage
  • Ticket Assignment: Assign tickets to specific users with typeahead search
  • Priority Tracking: P1 (Critical) to P5 (Minimal Impact) with color-coded indicators and status dots
  • Custom Categories: Hardware, Software, Network, Security, General
  • Ticket Types: Maintenance, Install, Task, Upgrade, Issue, Problem
  • Skeleton Loaders: Loading placeholders during filter changes and data refresh
  • Export: Export filtered 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)
  • Comment Requirements: Transitions that require a comment open an inline modal before committing the change
  • 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

Collaboration Features

  • Markdown Comments: Full Markdown support with live preview, toolbar, and table rendering
  • @Mentions: Tag users in comments with @ autocomplete (typeahead); triggers Matrix notification to mentioned user
  • 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; image attachments display as thumbnails with lightbox zoom
  • Ticket Cloning: Duplicate any ticket with a single click; auto-links as relates_to
  • Ticket Dependencies: Link tickets as blocks / blocked-by / relates-to / duplicates
  • Duplicate Detection: Similarity check on ticket title surfaces potential duplicates with one-click linking
  • Activity Timeline: Full lt-timeline audit trail — color-coded by event type (status, comment, assign, attach)
  • Watcher Avatars: Avatar group shows who is watching a ticket; tooltip lists all names
  • SLA Timer: P1/P2 tickets display a live elapsed-time banner with progress bar (P1 = 8 h, P2 = 24 h, P3 = 72 h)
  • Priority Alert Banner: P1 shows a sticky error banner; P2 shows a warning banner — dismissible per session

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 Avatars: JPEG avatars fetched from lldap via LDAP; cached locally (/api/user_avatar.php)
  • 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 (typeahead search)
  • 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

In-App Notifications

  • Notification Bell: Header bell icon with unread count badge; polls every 60 s
  • Notification Sources: Ticket assigned to you, comment on your ticket, status change on watched ticket, @mention
  • Mark All Read: Click the bell or "Mark all read" to clear the badge
  • Powered by audit_log: No extra table — notifications are derived from existing audit trail

Matrix Notifications (hookshot)

  • Ticket Created: Fires when any ticket is created (manual or via API)
  • Status Changed: Fires on every status transition
  • @Mentions: Mentioned users receive a direct Matrix notification
  • Assignment: Optional — set MATRIX_NOTIFY_ASSIGNMENTS=1 to enable
  • Comments: Optional — set MATRIX_NOTIFY_COMMENTS=1 to enable
  • Watcher Alerts: Watchers receive Matrix notifications on status changes (resolved via Synapse Admin API)
  • Rich Payloads: JSON payloads sent to hookshot generic webhook; format ticket links using APP_DOMAIN

Command Palette (Ctrl+K)

  • Global Access: Available on every page via Ctrl+K or ⌘K button in header
  • Quick Navigation: Dashboard, New Ticket, My Tickets, admin pages
  • Recent Tickets: Last 5 viewed tickets (stored in localStorage)
  • Filter Shortcuts: Apply common filters directly from palette

Keyboard Shortcuts

Shortcut Action
Ctrl/Cmd + K Open command palette (global)
Ctrl/Cmd + E Toggle edit mode (ticket page)
Ctrl/Cmd + S Save changes (ticket page)
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; token rotated after each write
  • 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

Automated Ticket Creation (hwmonDaemon)

hwmonDaemon runs on all servers and creates tickets automatically for hardware/health issues. It calls the standalone API endpoint at the document root:

POST /create_ticket_api.php
Authorization: Bearer <api_key>
Content-Type: application/json

{
  "title":       "[hostname][auto][production][hardware][single-node] SMART issues on /dev/sda",
  "description": "...",
  "priority":    "2",
  "category":    "Hardware",
  "type":        "Issue"
}

Key behaviours:

  • Authenticated via Authorization: Bearer header — API key stored in /etc/hwmonDaemon/.env
  • Deduplication: Generates a SHA-256 hash from the issue category, hostname, and device; rejects duplicate tickets within 24 hours
  • Cluster-wide issues (Ceph health, etc.) deduplicate across all nodes (hostname excluded from hash)
  • Matrix notification sent automatically after ticket creation
  • API key must be generated at /admin/api-keys; the key goes in hwmonDaemon's /etc/hwmonDaemon/.env as TICKET_API_KEY

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
  • Chart.js: CDN-loaded on dashboard only — priority/status/category charts
  • Flatpickr: CDN-loaded on dashboard only — date range filter pickers

Database Tables

Table Purpose
tickets Core ticket data with visibility
ticket_comments Markdown-supported comments
ticket_attachments File attachment metadata
ticket_dependencies Ticket relationships
ticket_watchers Per-user ticket subscriptions
users User accounts with groups
user_preferences User settings (rows per page, notification opts, notif_last_seen)
audit_log Complete audit trail (also powers in-app notifications)
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
/create_ticket_api.php POST Create ticket via API key (hwmonDaemon, external tools)
/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/clone_ticket.php POST Clone an existing 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)
/api/custom_fields.php CRUD Custom field definitions/values (admin)
/api/saved_filters.php CRUD Saved filter combinations
/api/user_preferences.php GET/POST User preferences
/api/notifications.php GET/POST In-app notifications (bell)
/api/user_avatar.php GET User avatar from lldap (cached JPEG)
/api/audit_log.php GET Audit log entries (admin)
/api/watch_ticket.php POST Watch/unwatch a ticket
/api/health.php GET Health check

Project Structure

tinker_tickets/
├── api/
│   ├── add_comment.php                   # POST: Add comment
│   ├── assign_ticket.php                 # POST: Assign ticket to user
│   ├── audit_log.php                     # GET: Audit log entries (admin)
│   ├── bootstrap.php                     # Shared auth/setup include (not a public endpoint)
│   ├── bulk_operation.php                # POST: Bulk operations (admin only)
│   ├── check_duplicates.php              # GET: Check for duplicate tickets
│   ├── clone_ticket.php                  # POST: Clone an existing ticket
│   ├── custom_fields.php                 # CRUD: Custom field definitions/values (admin)
│   ├── 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
│   ├── health.php                        # GET: Health check endpoint
│   ├── manage_recurring.php              # CRUD: Recurring tickets (admin)
│   ├── manage_templates.php              # CRUD: Templates (admin)
│   ├── manage_workflows.php              # CRUD: Workflow rules (admin)
│   ├── notifications.php                 # GET/POST: In-app notification bell
│   ├── revoke_api_key.php                # POST: Revoke API key (admin)
│   ├── saved_filters.php                 # CRUD: Saved filter combinations
│   ├── 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
│   ├── user_avatar.php                   # GET: LDAP avatar proxy with disk cache
│   ├── user_preferences.php              # GET/POST: User preferences
│   └── watch_ticket.php                  # POST: Watch/unwatch a ticket
├── assets/
│   ├── css/
│   │   ├── base.css                      # LotusGuild Terminal Design System (copied 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 (copied from web_template)
│   │   ├── dashboard.js                  # Dashboard + bulk actions + kanban + sidebar + charts
│   │   ├── 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 + @mention
│   │   ├── 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/
│   ├── CacheHelper.php                   # File-based cache (stats, avatars)
│   ├── Database.php                      # Centralized mysqli connection
│   ├── NotificationHelper.php            # Matrix hookshot webhook events
│   ├── SynapseHelper.php                 # Resolves usernames → Matrix IDs via Synapse admin API
│   └── UrlHelper.php                     # Canonical ticket URLs using APP_DOMAIN
├── middleware/
│   ├── ApiKeyAuth.php                    # Bearer token auth for external API (hwmonDaemon)
│   ├── AuthMiddleware.php                # Authelia SSO integration
│   ├── CsrfMiddleware.php                # CSRF protection
│   ├── RateLimitMiddleware.php           # Session + IP-based rate limiting
│   └── SecurityHeadersMiddleware.php     # CSP headers with per-request nonce generation
├── 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
│   ├── SavedFiltersModel.php             # Saved filter combinations
│   ├── StatsModel.php                    # Dashboard statistics (cached)
│   ├── 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/
│   ├── add_closed_at_column.php          # Migration: add closed_at column to tickets
│   ├── add_comment_updated_at.php        # Migration: add updated_at column to ticket_comments
│   ├── cleanup_orphan_uploads.php        # Clean orphaned uploads (run manually or via cron)
│   └── create_dependencies_table.php     # Create ticket_dependencies table
├── uploads/                              # File attachment storage
│   └── avatars/                          # lldap avatar disk cache
├── 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 + charts
│   ├── layout_footer.php                 # Shared footer (notification polling, boot sequence)
│   ├── layout_header.php                 # Shared header (nav, command palette, theme toggle)
│   └── TicketView.php                    # Ticket view with timeline, SLA, watcher avatars
├── .env                                  # Environment variables (GITIGNORED)
├── create_ticket_api.php                 # External API endpoint (hwmonDaemon, API-key auth)
├── 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
APP_DOMAIN=your.domain.example
TIMEZONE=America/New_York

Matrix notification variables (all optional):

# hookshot generic webhook URL — send events to Matrix room
MATRIX_WEBHOOK_URL=https://matrix.lotusguild.org/_hookshot/webhook/...

# Comma-separated Matrix user IDs to @mention on new tickets / status changes
MATRIX_NOTIFY_USERS=@jared:matrix.lotusguild.org,@ops:matrix.lotusguild.org

# Matrix homeserver domain (used to build Matrix user IDs from LLDAP usernames)
MATRIX_DOMAIN=matrix.lotusguild.org

# Synapse internal URL and admin token (used to resolve usernames → Matrix IDs for watcher DMs)
SYNAPSE_ADMIN_URL=http://10.10.10.29:8008
SYNAPSE_ADMIN_TOKEN=your_synapse_admin_token

# Optional: send Matrix notification on comments and/or assignments
MATRIX_NOTIFY_COMMENTS=0
MATRIX_NOTIFY_ASSIGNMENTS=1

LDAP/avatar variables (optional):

LDAP_ENABLED=true
LDAP_HOST=10.10.10.39
LDAP_PORT=3890
LDAP_BIND_DN=uid=tinker-tickets,ou=people,dc=example,dc=com
LDAP_BIND_PW=your_bind_password
LDAP_BASE_DN=dc=example,dc=com
LDAP_USER_BASE=ou=people,dc=example,dc=com
AVATAR_CACHE_TTL=3600

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

2. Cron Jobs

Add to crontab for recurring tickets and optional cleanup:

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

# Optional: clean up orphaned uploads weekly
0 3 * * 0 php /path/to/tinkertickets/scripts/cleanup_orphan_uploads.php

3. File Uploads

Ensure the uploads/ directory exists and is writable:

mkdir -p /path/to/tinkertickets/uploads/avatars
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.

5. hwmonDaemon API Key

  1. Go to /admin/api-keys and generate a new key named e.g. "hwmonDaemon"
  2. Copy the displayed key (shown only once)
  3. On each monitored server, create /etc/hwmonDaemon/.env:
    TICKET_API_KEY=your_generated_key
    TICKET_API_URL=http://10.10.10.45/create_ticket_api.php
    

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; bootstrap.php rotates token and returns it in csrf_token field of all apiRespond() responses
  7. Cache busting: ASSET_VERSION is auto-computed from asset file mtimes; override with ASSET_VERSION= in .env
  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 — guard subsequent session_start() calls with if (session_status() === PHP_SESSION_NONE)
  12. Database collation: Use utf8mb4_general_ci (not unicode_ci) for new tables
  13. Matrix URLs: Set APP_DOMAIN in .env for correct ticket URLs in Matrix 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 60 s; 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. Stats cache: StatsModel caches stats for 60 s. Any API that modifies ticket state must call (new StatsModel($conn))->invalidateCache() after changes (bulk_operation, assign_ticket, update_ticket, clone_ticket all do this).
  25. External API (create_ticket_api.php): Uses ApiKeyAuth (Bearer token), not session auth. Served directly by the web server from the document root — not through the index.php router. Includes deduplication logic to prevent duplicate hw-alert tickets within 24 h.

File Reference

File Purpose
index.php Main router for all routes
create_ticket_api.php External API (hwmonDaemon) — Bearer token auth, deduplication
config/config.php Config loader + .env parsing
api/update_ticket.php Ticket updates with workflow + visibility validation
api/notifications.php In-app notification bell — reads from audit_log
api/user_avatar.php LDAP avatar proxy with disk cache
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
models/StatsModel.php Dashboard statistics (60 s cache; invalidated on ticket changes)
middleware/ApiKeyAuth.php Bearer token authentication for external API
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
helpers/NotificationHelper.php Matrix hookshot webhook events
helpers/SynapseHelper.php Username → Matrix ID resolution via Synapse admin API
assets/js/dashboard.js Dashboard UI, kanban, sidebar, bulk actions, charts, command palette
assets/js/ticket.js Ticket UI, @mention autocomplete, lightbox, visibility editing
assets/js/markdown.js Markdown parsing + ticket linking (XSS-safe)
assets/css/dashboard.css Terminal styling, kanban, sidebar, charts, workload panel
assets/css/ticket.css Ticket view: SLA progress, attachment thumbnails, timeline

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); rotated on each write
Session Security Fixation prevention, secure cookies, session timeout
Rate Limiting Session-based + IP-based (file storage)
File Security Path traversal prevention, MIME type validation, uploads .htaccess blocks execution
Visibility Enforced on ticket views, downloads, and bulk operations
API Key Auth SHA-256 hashed keys stored in DB; Bearer token auth for external API

License

Internal use only - LotusGuild Infrastructure

S
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 10 MiB
Languages
PHP 57.6%
JavaScript 25%
CSS 17.4%