issues-api
Issues API
- User Base Path:
/api/v1/issues - Admin Base Path:
/api/admin/issues - Auth: required for every endpoint (user token for
/api/v1, admin token for/api/admin)
Issue Model
- _id: string (ObjectId)
- description: string (user-provided text, required)
- category: string (user-provided tag, required)
- attachments: string[] (zero-or-more HTTPS URLs that the reporter has already uploaded elsewhere)
- user: string (ObjectId) — reporter id; populated with
emailfor admin reads - status:
'open' | 'in_progress' | 'closed'(defaults toopenwhen the issue is created) - statusHistory:
[\{ status, comment?, updatedAt, updatedBy? \}](admin-only; newest first when returned from admin endpoints) - createdAt / updatedAt: string (ISO timestamp)
User-facing endpoints (/api/v1/issues)
List Issues
- GET
/api/v1/issues - Query params:
category(optional string) — exact match filtermine(optional boolean) —trueto fetch only the authenticated user's issues
- Returns:
Issue[]sorted with newest first - Notes: user tokens see only their own issues unless
mine=falseAND the token belongs to an admin user (our auth middleware still enforces standard visibility rules).
Create Issue
- POST
/api/v1/issues - Body:
{
"description": "Latitude won’t load leaderboard",
"category": "app_bug",
"attachments": ["https://cdn.example.com/issue-screens/123.png"]
} - Returns: the created
Issue(status fixed toopenat this stage). - Validation:
description/categorymust be non-empty strings.attachments, if present, must be an array of valid URLs.
Get Issue By Id
- GET
/api/v1/issues/:id - Returns: the matching
Issueor404.
Update Issue
- PATCH
/api/v1/issues/:id - Body: any subset of
\{ description, category, attachments \}(all optional, but at least one must be present). - Returns: updated
Issue. - Notes: reporters cannot change
statusor status history from the public API.
Delete Issue
- DELETE
/api/v1/issues/:id - Returns:
204on success.
Admin endpoints (/api/admin/issues)
List Issues
- GET
/api/admin/issues - Query params:
category(optional string) - Returns:
Issue[]with reporteruserpopulated to\{ _id, email \}andstatusHistorysorted newest-first.
Get Issue
- GET
/api/admin/issues/:id - Same response shape as list item (includes
statusHistory).
Update Issue
- PATCH
/api/admin/issues/:id - Body: any combination of
description,category,attachments,status, plus optionalstatusCommentwhenstatusis provided.{
"status": "in_progress",
"statusComment": "Reached out to the player for extra logs.",
"category": "support"
} - Behaviour:
- When
statuschanges, the server requiresstatusCommentto be non-empty. - A history entry is appended with the new status, comment, timestamp, and the admin's user id.
- When
- Returns: updated issue (with fresh history ordering and reporter email).
Delete Issue
- DELETE
/api/admin/issues/:id - Returns:
\{ ok: true \}when the issue was removed.
Frontend Guidance
- Default new issues to
status = 'open'; only admins should surface UI to transition statuses. - When calling the admin PATCH endpoint with a status change, always supply a comment string — the backend rejects empty comments.
- Render status history in reverse chronological order (already pre-sorted from the API). Each entry may include the admin email when available; fall back to displaying the raw id if
updatedBywas just an ObjectId. - For reporter details, the admin responses include a
user.email— use it for quick Gmail compose links:https://mail.google.com/mail/?view=cm&fs=1&to=<email>. - Attachment URLs are plain strings; frontend should open them in a new tab and handle cases where the array is empty.