Instead of regex-parsing markdown content to find attachment URLs
(fragile), the frontend now tracks uploaded attachment IDs and sends
them with the comment creation request. The backend links them by ID.
Frontend: upload returns attachment ID, comment/reply inputs collect
IDs during editing session, pass as attachment_ids on submit.
Backend: CreateComment accepts attachment_ids, links by ID+issue scope.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Delete/DeleteKeys/KeyFromURL methods to S3Storage
- DeleteAttachment handler now removes the S3 object after DB delete
- DeleteComment collects attachment URLs before CASCADE, then cleans S3
- DeleteIssue collects all attachment URLs (issue + comment level) before CASCADE, then cleans S3
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add CloudFrontSigner.SignedURL() for generating per-resource signed URLs
- Attachment responses include download_url (5-min signed URL for CLI)
- Eager load attachments on comments and timeline (same pattern as reactions)
- Add ListAttachmentsByCommentIDs query for batch loading
- Update Comment and TimelineEntry types with attachments field
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add attachment table with workspace/issue/comment associations
- Upload handler creates attachment record when workspace context exists
- Add GET /api/issues/{id}/attachments and DELETE /api/attachments/{id}
- Frontend passes issueId context during uploads for tracking
- Add Attachment type, listAttachments, deleteAttachment to API client
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>