jared d443caf059 Fix bulk operation dropping tickets with leading-zero IDs, add query null-check
bulk_operation.php: ticket ID validation was converting IDs to int then back
to string, so '000123456' became '123456' which never matched the DB VARCHAR
key, silently rejecting ~11% of tickets from bulk operations. Now validates
with ctype_digit() to preserve leading zeros.

TicketModel::getTicketsByIds(): changed intval() to strval() and bind type
'i' to 's' so VARCHAR ticket_id columns are queried consistently as strings.

DashboardController::getCategoriesAndTypes(): added null check on query
result before calling fetch_assoc() to prevent TypeError if query fails.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 22:29:14 -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%