Apply LotusGuild design system convergence (aesthetic_diff.md)

- §10: Filter sidebar labels color green→amber with glow-amber,
  matching unified amber-for-labels convention from base.css

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-14 21:40:43 -04:00
parent f59913910f
commit a34ca51223
2 changed files with 239 additions and 69 deletions

305
README.md
View File

@@ -3,6 +3,23 @@
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](https://wiki.lotusguild.org/en/Services/service-tinker-tickets)
**Design System**: [web_template](https://code.lotusguild.org/LotusGuild/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:
- [`web_template/README.md`](https://code.lotusguild.org/LotusGuild/web_template/src/branch/main/README.md) — full component reference, CSS variables, JS API
- [`web_template/base.css`](https://code.lotusguild.org/LotusGuild/web_template/src/branch/main/base.css) — unified CSS (`.lt-*` classes)
- [`web_template/base.js`](https://code.lotusguild.org/LotusGuild/web_template/src/branch/main/base.js) — `window.lt` utilities (toast, modal, CSRF, fetch helpers)
- [`web_template/aesthetic_diff.md`](https://code.lotusguild.org/LotusGuild/web_template/src/branch/main/aesthetic_diff.md) — cross-app divergence analysis and convergence guide
- [`web_template/php/layout.php`](https://code.lotusguild.org/LotusGuild/web_template/src/branch/main/php/layout.php) — PHP base layout template
**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
@@ -17,7 +34,7 @@ The following features are intentionally **not planned** for this system:
### 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
- **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)
- **Full-Text Search**: Search across tickets, descriptions, and metadata
- **Advanced Search**: Date ranges, priority ranges, user filters with saved filter support
@@ -30,7 +47,7 @@ The following features are intentionally **not planned** for this system:
### Ticket Visibility Levels
- **Public**: All authenticated users can view the ticket
- **Internal**: Only users in specified groups 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
@@ -102,7 +119,7 @@ Access all admin pages via the **Admin dropdown** in the dashboard header.
### 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
- **Dynamic URLs**: Ticket links adapt to the server hostname (set `APP_DOMAIN` in `.env`)
### Keyboard Shortcuts
| Shortcut | Action |
@@ -129,6 +146,7 @@ Access all admin pages via the **Admin dropdown** in the dashboard header.
- **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
@@ -138,6 +156,7 @@ Access all admin pages via the **Admin dropdown** in the dashboard header.
- **Mobile Responsive**: Touch-friendly controls, responsive layouts
### Database Tables
| Table | Purpose |
|-------|---------|
| `tickets` | Core ticket data with visibility |
@@ -153,9 +172,29 @@ Access all admin pages via the **Admin dropdown** in the dashboard header.
| `custom_field_definitions` | Custom field schemas |
| `custom_field_values` | Custom field data |
| `saved_filters` | Saved filter combinations |
| `api_keys` | API key storage |
| `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 |
|----------|--------|-------------|
| `/api/update_ticket.php` | POST | Update ticket with workflow validation |
@@ -169,75 +208,101 @@ Access all admin pages via the **Admin dropdown** in the dashboard header.
| `/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) |
## Setup & Configuration
### 1. Environment Configuration
Copy the example file and edit with your values:
```bash
cp .env.example .env
nano .env
```
Required environment variables:
```env
DB_HOST=10.10.10.50
DB_USER=tinkertickets
DB_PASS=your_password
DB_NAME=ticketing_system
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
APP_DOMAIN=t.lotusguild.org
TIMEZONE=America/New_York
```
**Note**: `APP_DOMAIN` is required for Discord webhook ticket links to work correctly. Without it, links will default to localhost.
### 2. Cron Jobs
Add to crontab for recurring tickets:
```bash
# Run every hour to create scheduled recurring tickets
0 * * * * php /var/www/html/tinkertickets/cron/create_recurring_tickets.php
```
### 3. File Uploads
Ensure the `uploads/` directory exists and is writable:
```bash
mkdir -p /var/www/html/tinkertickets/uploads
chown www-data:www-data /var/www/html/tinkertickets/uploads
chmod 755 /var/www/html/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.
| `/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) |
## Project Structure
```
tinker_tickets/
├── api/ # API endpoints
├── assets/ # Static assets (CSS, JS)
├── config/ # Configuration
├── controllers/ # MVC Controllers
├── cron/ # Scheduled task scripts
├── helpers/ # Utility classes
├── middleware/ # Request middleware
├── models/ # Data models
├── scripts/ # Maintenance scripts
├── uploads/ # File upload storage
├── views/ # View templates
── admin/ # Admin panel views
├── index.php # Main router
└── .env # Environment configuration
├── api/
├── add_comment.php # POST: Add comment
│ ├── assign_ticket.php # POST: Assign ticket to user
│ ├── bulk_operation.php # POST: Bulk operations (admin only)
├── check_duplicates.php # GET: Check for duplicate tickets
│ ├── 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
│ ├── manage_recurring.php # CRUD: Recurring tickets (admin)
│ ├── manage_templates.php # CRUD: Templates (admin)
│ ├── manage_workflows.php # CRUD: Workflow rules (admin)
│ ├── revoke_api_key.php # POST: Revoke API key (admin)
│ ├── 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
├── assets/
│ ├── css/
│ │ ├── dashboard.css # Dashboard + terminal styling
│ │ └── ticket.css # Ticket view styling
│ ├── js/
│ │ ├── advanced-search.js # Advanced search modal
│ │ ├── ascii-banner.js # ASCII art banner
│ │ ├── dashboard.js # Dashboard + bulk actions + kanban + sidebar
│ │ ├── keyboard-shortcuts.js # Keyboard shortcuts
│ │ ├── markdown.js # Markdown rendering + ticket linking (XSS-safe)
│ │ ├── settings.js # User preferences
│ │ ├── ticket.js # Ticket + comments + visibility
│ │ └── toast.js # Toast notifications
│ └── 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/
│ └── ResponseHelper.php # Standardized JSON responses
├── middleware/
│ ├── AuthMiddleware.php # Authelia SSO integration
│ ├── CsrfMiddleware.php # CSRF protection
│ ├── RateLimitMiddleware.php # Session + IP-based rate limiting
│ └── SecurityHeadersMiddleware.php # CSP with nonces, security headers
├── 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
│ ├── StatsModel.php # Dashboard statistics
│ ├── 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/
│ ├── cleanup_orphan_uploads.php # Clean orphaned uploads
│ └── create_dependencies_table.php # Create ticket_dependencies table
├── uploads/ # File attachment storage
├── 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
│ └── TicketView.php # Ticket view with visibility editing
├── .env # Environment variables (GITIGNORED)
├── README.md # This file
└── index.php # Main router
```
## Workflow States
@@ -252,6 +317,110 @@ 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:
```bash
cp .env.example .env
nano .env
```
Required environment variables:
```env
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.
### 2. Cron Jobs
Add to crontab for recurring tickets:
```bash
# Run every hour to create scheduled recurring tickets
0 * * * * php /path/to/tinkertickets/cron/create_recurring_tickets.php
```
### 3. File Uploads
Ensure the `uploads/` directory exists and is writable:
```bash
mkdir -p /path/to/tinkertickets/uploads
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.
## 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
7. **Cache busting**: Use `?v=YYYYMMDD` query params on JS/CSS files
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
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
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
## File Reference
| File | Purpose |
|------|---------|
| `index.php` | Main router for all routes |
| `config/config.php` | Config loader + .env parsing |
| `api/update_ticket.php` | Ticket updates with workflow + visibility validation |
| `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 |
| `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 |
| `assets/js/markdown.js` | Markdown parsing + ticket linking (XSS-safe) |
| `assets/css/dashboard.css` | Terminal styling, kanban, sidebar |
## 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`) |
| Session Security | Fixation prevention, secure cookies, session timeout |
| Rate Limiting | Session-based + IP-based (file storage) |
| File Security | Path traversal prevention, MIME type validation |
| Visibility | Enforced on ticket views, downloads, and bulk operations |
## License
Internal use only - LotusGuild Infrastructure