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. 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) **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 ## Design Decisions
@@ -17,7 +34,7 @@ The following features are intentionally **not planned** for this system:
### Dashboard & Ticket Management ### Dashboard & Ticket Management
- **View Modes**: Toggle between Table view and Kanban card view - **View Modes**: Toggle between Table view and Kanban card view
- **Collapsible Sidebar**: Click the arrow to collapse/expand the filter sidebar - **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) - **Stats Widgets**: Clickable cards for quick filtering (Open, Critical, Unassigned, Today's tickets)
- **Full-Text Search**: Search across tickets, descriptions, and metadata - **Full-Text Search**: Search across tickets, descriptions, and metadata
- **Advanced Search**: Date ranges, priority ranges, user filters with saved filter support - **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 ### Ticket Visibility Levels
- **Public**: All authenticated users can view the ticket - **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 - **Confidential**: Only the creator, assignee, and admins can view the ticket
### Workflow Management ### Workflow Management
@@ -102,7 +119,7 @@ Access all admin pages via the **Admin dropdown** in the dashboard header.
### Notifications ### Notifications
- **Discord Integration**: Webhook notifications for ticket creation and updates - **Discord Integration**: Webhook notifications for ticket creation and updates
- **Rich Embeds**: Color-coded priority indicators and ticket links - **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 ### Keyboard Shortcuts
| Shortcut | Action | | Shortcut | Action |
@@ -129,6 +146,7 @@ Access all admin pages via the **Admin dropdown** in the dashboard header.
- **Language**: PHP 7.4+ - **Language**: PHP 7.4+
- **Database**: MariaDB/MySQL - **Database**: MariaDB/MySQL
- **Architecture**: MVC pattern with models, views, controllers - **Architecture**: MVC pattern with models, views, controllers
- **Authentication**: Authelia SSO with LLDAP backend
### Frontend ### Frontend
- **HTML5/CSS3**: Semantic markup with retro terminal styling - **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 - **Mobile Responsive**: Touch-friendly controls, responsive layouts
### Database Tables ### Database Tables
| Table | Purpose | | Table | Purpose |
|-------|---------| |-------|---------|
| `tickets` | Core ticket data with visibility | | `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_definitions` | Custom field schemas |
| `custom_field_values` | Custom field data | | `custom_field_values` | Custom field data |
| `saved_filters` | Saved filter combinations | | `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 ### API Endpoints
| Endpoint | Method | Description | | Endpoint | Method | Description |
|----------|--------|-------------| |----------|--------|-------------|
| `/api/update_ticket.php` | POST | Update ticket with workflow validation | | `/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/export_tickets.php` | GET | Export tickets to CSV/JSON |
| `/api/generate_api_key.php` | POST | Generate API key (admin) | | `/api/generate_api_key.php` | POST | Generate API key (admin) |
| `/api/revoke_api_key.php` | POST | Revoke API key (admin) | | `/api/revoke_api_key.php` | POST | Revoke API key (admin) |
| `/api/delete_comment.php` | POST | Delete comment (owner/admin) |
## Setup & Configuration | `/api/update_comment.php` | POST | Update comment (owner/admin) |
| `/api/delete_attachment.php` | POST/DELETE | Delete attachment |
### 1. Environment Configuration | `/api/download_attachment.php` | GET | Download attachment (visibility checked) |
| `/api/check_duplicates.php` | GET | Check for duplicate tickets |
Copy the example file and edit with your values: | `/api/manage_recurring.php` | CRUD | Recurring tickets (admin) |
```bash | `/api/manage_templates.php` | CRUD | Templates (admin) |
cp .env.example .env | `/api/manage_workflows.php` | CRUD | Workflow rules (admin) |
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.
## Project Structure ## Project Structure
``` ```
tinker_tickets/ tinker_tickets/
├── api/ # API endpoints ├── api/
├── assets/ # Static assets (CSS, JS) ├── add_comment.php # POST: Add comment
├── config/ # Configuration │ ├── assign_ticket.php # POST: Assign ticket to user
├── controllers/ # MVC Controllers │ ├── bulk_operation.php # POST: Bulk operations (admin only)
├── cron/ # Scheduled task scripts ├── check_duplicates.php # GET: Check for duplicate tickets
├── helpers/ # Utility classes │ ├── delete_attachment.php # POST/DELETE: Delete attachment
├── middleware/ # Request middleware │ ├── delete_comment.php # POST: Delete comment (owner/admin)
├── models/ # Data models │ ├── download_attachment.php # GET: Download with visibility check
├── scripts/ # Maintenance scripts │ ├── export_tickets.php # GET: Export tickets to CSV/JSON
├── uploads/ # File upload storage │ ├── generate_api_key.php # POST: Generate API key (admin)
├── views/ # View templates │ ├── get_template.php # GET: Fetch ticket template
── admin/ # Admin panel views ── get_users.php # GET: Get user list
├── index.php # Main router │ ├── manage_recurring.php # CRUD: Recurring tickets (admin)
└── .env # Environment configuration │ ├── 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 ## Workflow States
@@ -252,6 +317,110 @@ Open → Pending → In Progress → Closed
All states can transition to Closed (with comment). All states can transition to Closed (with comment).
Closed tickets can be reopened to Open or In Progress. 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 ## License
Internal use only - LotusGuild Infrastructure Internal use only - LotusGuild Infrastructure

View File

@@ -2566,7 +2566,8 @@ input[type="checkbox"]:checked {
.filter-group label { .filter-group label {
display: block; display: block;
margin: 0.4rem 0; margin: 0.4rem 0;
color: var(--terminal-green); color: var(--terminal-amber);
text-shadow: var(--glow-amber);
cursor: pointer; cursor: pointer;
font-size: 0.85rem; font-size: 0.85rem;
font-family: var(--font-mono); font-family: var(--font-mono);