Task #166: Trinity Console Issue Tracker (REQ-2026-04-14-issue-tracker)

- Migration 141: issues, issue_attachments, issue_comments
- src/routes/admin/issues.js: session-auth UI routes (list/new/detail/status/assign/comments/upload)
- src/routes/api.js: /api/internal/issues REST surface (Bearer token)
- src/services/issueNotifier.js: Discord webhook helper (DISCORD_ISSUE_WEBHOOK_URL)
- Views: index (list+filters), new (mobile-first form), detail (screenshots, comments, workflow)
- layout.ejs: sidebar nav link
- package.json: add multer ^1.4.5-lts.1
- CSRF token passed via query param on multipart forms (body unparsed when csurf runs)
- Screenshots stored in services/arbiter-3.0/uploads/issues/ (10MB limit, 6 files max)
This commit is contained in:
Claude Code
2026-04-15 01:53:18 -05:00
parent 263a7e3e47
commit b0b69fb172
11 changed files with 916 additions and 0 deletions

View File

@@ -1,123 +0,0 @@
# Code Bridge Request: Trinity Console Issue Tracker
**Date:** 2026-04-14
**From:** Chronicler #89
**Priority:** High
**Task:** #166
---
## What We Need
A full issue tracker module in Trinity Console. This is Holly's primary pain point — she infodumps bugs and requests in Discord DMs and Michael loses track. The issue tracker becomes the canonical location for all issues.
## The Critical UX Requirement
Holly plays Minecraft on her phone/PC. When something breaks, she screenshots it on her phone and needs to submit an issue **without tabbing out of the game**. This means:
- **Mobile-first responsive design** — must work perfectly on a phone browser
- **Screenshot upload from camera roll** — tap, select photo, done
- **Minimal form fields** — title, description, screenshot, priority, category. That's it for submission.
- **Fast** — she's in-game, she wants to fire and forget
## Database Schema
### `issues` table
```sql
CREATE TABLE issues (
id SERIAL PRIMARY KEY,
issue_number INTEGER UNIQUE,
title VARCHAR(255) NOT NULL,
description TEXT,
status VARCHAR(20) DEFAULT 'open', -- open, in-progress, blocked, resolved, closed
priority VARCHAR(20) DEFAULT 'medium', -- critical, high, medium, low
category VARCHAR(50) DEFAULT 'general', -- bug, feature, content, infrastructure, holly, general
submitted_by VARCHAR(100) NOT NULL, -- Discord username
assigned_to VARCHAR(100) DEFAULT 'unassigned',
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
resolved_at TIMESTAMPTZ,
resolved_by VARCHAR(100)
);
```
### `issue_attachments` table
```sql
CREATE TABLE issue_attachments (
id SERIAL PRIMARY KEY,
issue_id INTEGER REFERENCES issues(id) ON DELETE CASCADE,
filename VARCHAR(255) NOT NULL,
original_name VARCHAR(255),
mime_type VARCHAR(100),
file_size INTEGER,
uploaded_at TIMESTAMPTZ DEFAULT NOW()
);
```
### `issue_comments` table
```sql
CREATE TABLE issue_comments (
id SERIAL PRIMARY KEY,
issue_id INTEGER REFERENCES issues(id) ON DELETE CASCADE,
author VARCHAR(100) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
```
## API Routes
```
GET /api/internal/issues — list issues (with filters)
POST /api/internal/issues — create issue
GET /api/internal/issues/:id — get issue detail
PATCH /api/internal/issues/:id — update issue (status, assignment, etc.)
POST /api/internal/issues/:id/comments — add comment
POST /api/internal/issues/:id/upload — upload screenshot
GET /api/internal/issues/attachments/:filename — serve attachment
```
## UI Pages
### `/admin/issues` — Issue List
- Filter chips: status, priority, category, submitter
- Sort by: newest, priority, recently updated
- Each row: issue number, title, status badge, priority badge, submitter, age
- Click → detail view (slide-out panel like tasks module)
### `/admin/issues/new` — Submit Issue (Mobile-First)
- Title (required)
- Description (textarea, optional)
- Priority (dropdown, default medium)
- Category (dropdown, default general)
- Screenshot upload (file input accepting images, multiple allowed)
- Submit button
- Auto-fills submitted_by from Discord auth session
### Issue Detail (slide-out or dedicated page)
- Full description
- Screenshot thumbnails (click to enlarge)
- Status workflow buttons (open → in-progress → resolved → closed)
- Assignment dropdown
- Comments thread
- Activity log
## Discord Webhook
On issue create and status change, POST to a `#issue-tracker` Discord channel:
- New issue: "🐛 Issue #42 opened by Holly: [title] (priority: high)"
- Status change: "✅ Issue #42 resolved by Michael"
## Image Storage
Store uploaded images to disk at `/opt/arbiter-3.0/uploads/issues/` (or similar). Serve via Express static middleware. Keep it simple — no need for NextCloud/S3 for this.
## Reference
- Task module (existing) is a good starting point for the UI pattern — filter chips, slide-out panels, sort
- Discord auth session already provides the username for submitted_by
- Existing admin middleware handles auth
---
**Fire + Frost + Foundation = Where Love Builds Legacy** 💙🔥❄️