Move Link extension before Markdown in the TipTap extensions array
to ensure URL detection happens before markdown processing. Also
explicitly enable linkOnPaste for paste detection.
Fixes#376
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Use `||` instead of `??` so empty strings also fall back to email.
The nullish coalescing operator (`??`) only catches null/undefined,
so users with an empty name string would appear nameless in emails.
* feat(db): add webhook schema, migration, and repository
Add the database foundation for workspace webhooks:
- Add workspace_webhooks table with migration (webhook_event enum,
URL, secret, event subscriptions, active flag)
- Add webhook repository with CRUD operations
- Add webhooks schema definition with relations
- Extend card and list repos to return board/list names for
webhook payload context
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(db): remove unused webhook_event enum and fix migration timestamp
- Remove dead webhook_event pgEnum from schema (events column uses text)
- Remove CREATE TYPE statement from migration SQL
- Fix migration journal timestamp to be chronologically after the
notifications migration (idx 25)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(db): return boardPublicId from card and list repo queries
Add board publicId to getWorkspaceAndCardIdByCardPublicId and
getWorkspaceAndListIdByListPublicId return values, needed for
correct boardId in webhook payloads.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(db): add workspaceId index and document secret exposure
- Add index on workspaceId for efficient webhook lookups per workspace
- Add JSDoc comment on getActiveByWorkspaceId explaining that it
returns secrets for server-side HMAC signing only and must never
be exposed via client-facing endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(db): extract parseEvents helper in webhook repo
DRY up 6 repeated JSON.parse-and-cast calls into a single helper
function, addressing reviewer feedback on PR #391.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The board.byId query was generating presigned S3 URLs for workspace
member avatars but not for card member avatars. This caused card avatars
to silently fall back to initials since the frontend helper returns ""
for raw S3 keys.
Closes#387
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add notifications schema
* chore: gen migration
* feat: add mention email template
* feat: add sendMentionEmail func
* feat: add repo funcs
* feat: update card router to send emails on mention
* fix: update the editor suggestion to show all members
* feat: skip pending members in sendMentionEmails
* feat: update comments to use tiptap editor
- Use /boards/{id} for private board links so copied link works; keep pretty URL for public boards
- Show matching path in board header (pretty path for public, boards/id for private)
- Copy link button copies URL to clipboard instead of opening in new tab (opening a new tab seems redundant since we're already on it)
- Edit workspace URL button links to /settings/workspace instead of account settings
* refactor: replace presigned URL uploads with backend upload endpoints
* feat: update avatar upload to use new endpoint
* refactor: use createS3Client in auth hooks
* feat: generate presigned URLs for avatars
* fix: show avatar image in user menu
* fix: hide tooltip if content is empty
* fix: support external avatar URLs in generateAvatarUrl
* fix: remove content type restriction on attachments
* fix: prevent workspace.byId validation errors when publicId is empty
* fix: add keys to shortcut elements
* fix: prevent card.byId validation errors when cardPublicId is empty
* chore: remove invalid config option from next.config.js