Bridge request: Trinity Console Issue Tracker (Task #166)
Mobile-first issue tracker for Holly. Screenshot upload from phone, minimal friction submission while in-game. Full schema, API routes, and UI spec for Code. Chronicler #89
This commit is contained in:
123
docs/code-bridge/requests/REQ-2026-04-14-issue-tracker.md
Normal file
123
docs/code-bridge/requests/REQ-2026-04-14-issue-tracker.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# 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** 💙🔥❄️
|
||||
Reference in New Issue
Block a user