* feat(issues): add sub-issue support
- Backend: Add ListChildIssues SQL query, add parent_issue_id to UpdateIssue,
add GET /api/issues/{id}/children endpoint
- Frontend: Display parent issue breadcrumb and link in issue detail sidebar,
show child issues list with status icons, add "Create sub-issue" action in
dropdown menu and sidebar, pass parent_issue_id through create issue modal
- Update test mocks for new API method
* fix(issues): add parent validation, cycle detection, and improve child refresh
- CreateIssue: validate parent issue exists in the same workspace
- UpdateIssue: validate parent exists, prevent self-referencing, detect
circular parent chains (up to 10 levels deep)
- Frontend: derive child issues from store when available instead of
refetching on every global issue count change
- Migrate issue-detail.tsx: useQuery for issue data, useUpdateIssue/useDeleteIssue
- Migrate issues-page.tsx, my-issues-page.tsx, board-card.tsx: useQuery for list
- Migrate batch-action-toolbar.tsx, create-issue.tsx: mutation hooks
- Migrate edge consumers: mention-suggestion, mention-view, agents page, issue-mention-card
- Remove Zustand writes from WS sync (TQ cache is now sole source of truth)
- Remove useIssueStore.fetch() dependency from workspace store
- Gut useIssueStore to client-only: { activeIssueId, setActiveIssue }
- Update test wrappers with QueryClientProvider
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use google/uuid NewV7() for attachment ID and S3 file key instead of
random hex, so the S3 object name matches the attachment record ID
- Add LinkAttachmentsToIssue query to associate orphaned attachments
with a newly created issue
- Pass attachment_ids in CreateIssue request so uploads during issue
creation (before the issue exists) get linked after commit
- Collect and pass attachment IDs in comment-input and reply-input
so comment creation properly links uploaded files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace three divergent data paths (Marked HTML loading, regex post-processing
saving, separate paste parsing) with one symmetric path through @tiptap/markdown.
Key changes:
- Create features/editor/ module with ContentEditor (unified edit+readonly)
and TitleEditor, replacing components/common/ editor files
- Load content via contentType: 'markdown' instead of markdownToHtml() hack
- Save content via editor.getMarkdown() directly, no post-processing
- Merge RichTextEditor + ReadonlyEditor into single ContentEditor with
editable prop
- Extract extensions into separate modules (mention, file-upload,
markdown-paste, submit-shortcut, code-block-view)
- Extract shared preprocessMentionShortcodes to components/markdown/mentions.ts
- Add copyMarkdown utility for clipboard operations
- Upgrade all @tiptap packages from 3.20.5 to 3.22.1 (lexer isolation fix,
HTML entity roundtrip fix, table alignment support)
- Delete markdownToHtml.ts, readonly-editor.tsx, and 10 old component files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Paste/drop and attachment button previously used separate upload paths.
The button uploaded first then called insertFile (which replaced the
current selection), while paste inserted a blob preview first. This
caused the second image to overwrite the first when both were used.
Now both paths share the same flow via uploadAndInsertFile():
blob preview with uploading animation → background upload → replace URL.
- Extract shared uploadAndInsertFile() function
- Replace insertFile ref method with uploadFile (inserts at doc end)
- Simplify FileUploadButton to onSelect(file) — no more onUpload/onInsert
- Wire onUploadFile in comment edit mode (was missing, upload was no-op)
- Unify image border-radius CSS for both editing and readonly modes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When switching workspaces while on a detail page (e.g. /issues/[id]),
the store clears old data and the page tries to fetch the old resource
with the new workspace context, causing a 404 error. Navigate to the
issues list before switching to avoid referencing stale resources.
Add search functionality to quickly find issues by title:
- Backend: add search param (ILIKE) to ListIssues query
- Frontend: search modal using CommandDialog with skeleton loading
- Sidebar: ghost-style search button next to create issue button
- Handle CJK input method composition to avoid premature searches
- Responsive max-height for small screens
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace inline div placeholders (initials/Bot icon) with ActorAvatar
component so actual user and agent avatar images render in all assignee
picker dropdowns.
Replace the small one-line sonner toast with a richer card showing:
- Green checkmark with "Issue created" title
- Status icon + issue identifier + title on second line
- Clickable "View issue" link to navigate to the new issue
After creating an issue, a success toast appears showing the issue
identifier (e.g. MUL-72) with a "View issue" action button that
navigates to the issue detail page. Similar to Linear's behavior.
- New TitleEditor: minimal tiptap (Document+Paragraph+Text+Placeholder)
- Single-paragraph constraint prevents Enter from creating new lines
- contenteditable div enables visual word-wrap (no horizontal scroll)
- Enter→submit+blur, Shift+Enter blocked, Escape→blur
- Replace <Input> in create-issue modal and <input> in issue-detail
- Remove titleDraft state/titleFocusedRef/sync effect from issue-detail
- Fix duplicate React key: TitleEditor key={`title-${id}`}
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Status labels use colored pill badges (solid bg for active, muted for inactive)
- Board columns have tinted backgrounds matching their status color
- Priority badges use orange (--priority) design token for clear distinction from status
- Issue cards restructured: identifier, title, then assignee/priority/date row
- Agent avatar default color changed from blue to gray
- New Issue button in header changed to solid/primary style
- Reduced hover shadow on board cards
- Added inheritColor prop to StatusIcon and PriorityIcon for badge use
- Add zustand draft store with localStorage persistence
- Restore draft fields when reopening create-issue modal
- Clear draft only on successful submission
- Show brand-colored dot on sidebar new-issue button when draft exists
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add drag-to-resize sidebar with localStorage persistence
- Rewrite issue detail page with Tiptap rich text editor, due date picker, acceptance criteria
- Redesign create-issue modal with pill-based property toolbar and expand/collapse
- Consolidate @multica/sdk and @multica/types into apps/web/shared/
- Simplify auth: remove verification codes, PATs, email service (dev-only login)
- Add 401 unauthorized handler to redirect expired sessions to login
- Fix due date format to send full RFC3339 timestamps
- Increase description editor debounce to 1500ms
- Remove arbitrary Tailwind values in create-issue modal
- Renumber migrations (inbox_actor 012→009), remove unused migrations
- UI polish across agents, settings, inbox, knowledge-base pages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix global scrollbar overflow by removing h-svh from html element
- Add h-full overflow-hidden to html/body for proper app-like layout
- Fix default button variant: add shadow-sm and hover:bg-primary/90
- Update sidebar create-issue button to bg-background with shadow
- Add WorkspaceAvatar component and search/new-issue actions to sidebar header
- Improve theme provider with TooltipProvider wrapper
- Polish various page layouts, pickers, modals, and code block styling
- Clean up custom.css unused styles
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>