Fix session_start guards, add missing API routes, rewrite README
- Added session_status() === PHP_SESSION_NONE guard to six API files (custom_fields, revoke_api_key, manage_templates, generate_api_key, get_template, manage_recurring) that called bare session_start() after RateLimitMiddleware had already started the session - Registered /api/notifications.php and /api/user_avatar.php in index.php router (were missing, served only by direct file access) - Complete README rewrite: remove all Discord references (Matrix/hookshot is the only external notification method), add hwmonDaemon API docs, document all TDS v1.2 features (kanban, charts, SLA, command palette, notification bell, watcher avatars, @mention, etc.), fix keyboard shortcuts table, add Matrix/LDAP env vars to setup section Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -23,25 +23,28 @@ Tinker Tickets uses the **LotusGuild Terminal Design System**. For all styling,
|
||||
## Design Decisions
|
||||
|
||||
The following features are intentionally **not planned** for this system:
|
||||
- **Email Integration**: Discord webhooks are the chosen notification method
|
||||
- **SLA Management**: Not required for internal infrastructure use
|
||||
- **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
|
||||
- **Collapsible Sidebar**: Click the arrow to collapse/expand the filter sidebar
|
||||
- **Inline Ticket Preview**: Hover over ticket IDs for a quick preview popup (300ms delay)
|
||||
- **Stats Widgets**: Clickable cards for quick filtering (Open, Critical, Unassigned, Today's tickets)
|
||||
- **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, priority ranges, user filters with saved filter support
|
||||
- **Ticket Assignment**: Assign tickets to specific users with quick-assign from dashboard
|
||||
- **Priority Tracking**: P1 (Critical) to P5 (Minimal Impact) with color-coded indicators
|
||||
- **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
|
||||
- **Export**: Export selected tickets to CSV or JSON format
|
||||
- **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
|
||||
@@ -51,19 +54,24 @@ The following features are intentionally **not planned** for this system:
|
||||
|
||||
### 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
|
||||
- **Comment Requirements**: Optional comment requirements for specific transitions
|
||||
|
||||
### Collaboration Features
|
||||
- **Markdown Comments**: Full Markdown support with live preview, toolbar, and table rendering
|
||||
- **@Mentions**: Tag users in comments with autocomplete
|
||||
- **@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 support
|
||||
- **Ticket Dependencies**: Link tickets as blocks/blocked-by/relates-to/duplicates
|
||||
- **Activity Timeline**: Complete audit trail of all ticket changes
|
||||
- **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
|
||||
@@ -92,40 +100,44 @@ The following features are intentionally **not planned** for this system:
|
||||
- **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
|
||||
- **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
|
||||
|
||||
### Admin Pages
|
||||
Access all admin pages via the **Admin dropdown** in the dashboard header.
|
||||
### 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
|
||||
|
||||
| Route | Description |
|
||||
|-------|-------------|
|
||||
| `/admin/templates` | Create and edit ticket templates |
|
||||
| `/admin/workflow` | Visual workflow transition designer |
|
||||
| `/admin/recurring-tickets` | Manage recurring ticket schedules |
|
||||
| `/admin/custom-fields` | Define custom fields per category |
|
||||
| `/admin/user-activity` | View per-user activity statistics |
|
||||
| `/admin/audit-log` | Browse all audit log entries |
|
||||
| `/admin/api-keys` | Generate and manage API keys |
|
||||
### 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`
|
||||
|
||||
### Notifications
|
||||
- **Discord Integration**: Webhook notifications for ticket creation and updates
|
||||
- **Rich Embeds**: Color-coded priority indicators and ticket links
|
||||
- **Dynamic URLs**: Ticket links adapt to the server hostname (set `APP_DOMAIN` in `.env`)
|
||||
### 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) |
|
||||
| `Ctrl/Cmd + K` | Focus search box (dashboard) |
|
||||
| `N` | New ticket (dashboard) |
|
||||
| `J` / `K` | Next / previous row (dashboard table) |
|
||||
| `Enter` | Open selected ticket (dashboard) |
|
||||
@@ -135,7 +147,7 @@ Access all admin pages via the **Admin dropdown** in the dashboard header.
|
||||
| `?` | Show keyboard shortcuts help |
|
||||
|
||||
### Security Features
|
||||
- **CSRF Protection**: Token-based protection with constant-time comparison
|
||||
- **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
|
||||
@@ -144,6 +156,31 @@ Access all admin pages via the **Admin dropdown** in the dashboard header.
|
||||
- **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](https://code.lotusguild.org/LotusGuild/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
|
||||
@@ -158,6 +195,8 @@ Access all admin pages via the **Admin dropdown** in the dashboard header.
|
||||
- **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
|
||||
|
||||
@@ -167,9 +206,10 @@ Access all admin pages via the **Admin dropdown** in the dashboard header.
|
||||
| `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 |
|
||||
| `audit_log` | Complete audit trail |
|
||||
| `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 |
|
||||
@@ -201,6 +241,7 @@ Access all admin pages via the **Admin dropdown** in the dashboard header.
|
||||
|
||||
| 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 |
|
||||
@@ -224,7 +265,10 @@ Access all admin pages via the **Admin dropdown** in the dashboard header.
|
||||
| `/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
|
||||
@@ -251,13 +295,16 @@ tinker_tickets/
|
||||
│ ├── 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_preferences.php # GET/POST: User preferences
|
||||
│ ├── 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)
|
||||
@@ -267,11 +314,11 @@ tinker_tickets/
|
||||
│ │ ├── 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
|
||||
│ │ ├── 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
|
||||
│ │ ├── 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/
|
||||
@@ -284,12 +331,17 @@ tinker_tickets/
|
||||
├── cron/
|
||||
│ └── create_recurring_tickets.php # Process recurring ticket schedules
|
||||
├── helpers/
|
||||
│ └── ResponseHelper.php # Standardized JSON responses
|
||||
│ ├── 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 with nonces, security headers
|
||||
│ └── SecurityHeadersMiddleware.php # CSP headers with per-request nonce generation
|
||||
├── models/
|
||||
│ ├── ApiKeyModel.php # API key generation/validation
|
||||
│ ├── AuditLogModel.php # Audit logging + timeline
|
||||
@@ -298,7 +350,8 @@ tinker_tickets/
|
||||
│ ├── CustomFieldModel.php # Custom field definitions/values
|
||||
│ ├── DependencyModel.php # Ticket dependencies
|
||||
│ ├── RecurringTicketModel.php # Recurring ticket schedules
|
||||
│ ├── StatsModel.php # Dashboard statistics
|
||||
│ ├── 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
|
||||
@@ -307,9 +360,10 @@ tinker_tickets/
|
||||
├── 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
|
||||
│ ├── 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
|
||||
@@ -320,9 +374,12 @@ tinker_tickets/
|
||||
│ │ ├── UserActivityView.php # User activity report
|
||||
│ │ └── WorkflowDesignerView.php # Workflow transition designer
|
||||
│ ├── CreateTicketView.php # Ticket creation with visibility
|
||||
│ ├── DashboardView.php # Dashboard with kanban + sidebar
|
||||
│ └── TicketView.php # Ticket view with visibility editing
|
||||
│ ├── 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
|
||||
```
|
||||
@@ -355,26 +412,60 @@ DB_HOST=your_db_host
|
||||
DB_USER=your_db_user
|
||||
DB_PASS=your_password
|
||||
DB_NAME=ticketing_system
|
||||
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
|
||||
APP_DOMAIN=your.domain.example
|
||||
TIMEZONE=America/New_York
|
||||
```
|
||||
|
||||
**Note**: `APP_DOMAIN` is required for Discord webhook ticket links to work correctly. Without it, links will default to localhost.
|
||||
Matrix notification variables (all optional):
|
||||
```env
|
||||
# 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):
|
||||
```env
|
||||
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:
|
||||
Add to crontab for recurring tickets and optional cleanup:
|
||||
```bash
|
||||
# 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:
|
||||
```bash
|
||||
mkdir -p /path/to/tinkertickets/uploads
|
||||
mkdir -p /path/to/tinkertickets/uploads/avatars
|
||||
chown www-data:www-data /path/to/tinkertickets/uploads
|
||||
chmod 755 /path/to/tinkertickets/uploads
|
||||
```
|
||||
@@ -389,6 +480,16 @@ Tinker Tickets uses Authelia for SSO. User information is passed via headers:
|
||||
|
||||
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`:
|
||||
```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:
|
||||
@@ -398,46 +499,54 @@ Key conventions and gotchas for working with this codebase:
|
||||
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
|
||||
7. **Cache busting**: Use `?v=YYYYMMDD` query params on JS/CSS files
|
||||
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 — do not call `session_start()` again
|
||||
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. **Discord URLs**: Set `APP_DOMAIN` in `.env` for correct ticket URLs in Discord notifications
|
||||
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 60s; full date is always in the `title` attribute for hover
|
||||
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. **CSS utility classes** (dashboard.css): Use `.text-green`, `.text-amber`, `.text-cyan`, `.text-danger`, `.text-open`, `.text-closed`, `.text-muted`, `.text-muted-green`, `.text-sm`, `.text-center`, `.nowrap`, `.mono`, `.fw-bold`, `.mb-1` for typography. Use `.admin-container` (1200px) or `.admin-container-wide` (1400px) for admin page max-widths. Use `.admin-header-row` for title+button header rows. Use `.admin-form-row`, `.admin-form-field`, `.admin-label`, `.admin-input` for filter forms. Use `.admin-form-actions` for filter form button groups. Use `.table-wrapper` + `td.empty-state` for tables. Use `.setting-grid-2` and `.setting-grid-3` for modal form grids. Use `.lt-modal-sm` or `.lt-modal-lg` for modal sizing.
|
||||
25. **CSS utility classes** (ticket.css): Use `.form-hint` (green helper text), `.form-hint-warning` (amber helper text), `.visibility-groups-list` (checkbox row), `.group-checkbox-label` (checkbox label) for ticket forms.
|
||||
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 |
|
||||
| `assets/js/dashboard.js` | Dashboard UI, kanban, sidebar, bulk actions |
|
||||
| `assets/js/ticket.js` | Ticket UI, visibility editing |
|
||||
| `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 |
|
||||
| `assets/css/dashboard.css` | Terminal styling, kanban, sidebar, charts, workload panel |
|
||||
| `assets/css/ticket.css` | Ticket view: SLA progress, attachment thumbnails, timeline |
|
||||
|
||||
## Security Implementations
|
||||
|
||||
@@ -445,11 +554,12 @@ Key conventions and gotchas for working with this codebase:
|
||||
|---------|---------------|
|
||||
| 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`) |
|
||||
| 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 |
|
||||
| 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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user