- Wrap all setter functions in useMemoEditorState with useCallback to ensure stable references
This prevents infinite loops when setters are used in useEffect dependencies (fixes "Maximum update depth exceeded" error)
- Extract MobX observable values in useMemoFilters and useMemoSorting before using them in useMemo dependencies
This prevents React from tracking MobX observables directly, improving reliability
- Add comprehensive documentation explaining the design decisions for future maintainability
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add MessageType filter to FindInbox to exclude legacy VERSION_UPDATE
notifications from inbox queries. This resolves the issue where users
saw notification counts but no items displayed, as VERSION_UPDATE
entries cannot be rendered in the new UserNotification API.
Changes:
- Add MessageType field to FindInbox struct for database-level filtering
- Implement JSON extraction filters in SQLite, MySQL, and PostgreSQL drivers
- Update ListUserNotifications to filter MEMO_COMMENT type at store level
This approach improves performance by filtering at the database rather
than in application code, reducing unnecessary data transfer for users
with many legacy inbox entries.
Fixes#5278🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major performance and standards compliance improvements to RSS feed generation:
Performance optimizations:
- Fix N+1 query problem by batch loading attachments (101 queries → 2-3)
- Add in-memory caching with 1-hour TTL and LRU eviction
- Implement ETag-based conditional requests (304 Not Modified)
- Add database-level pagination with LIMIT clause
- Clean up expired cache entries to prevent memory leaks
RSS 2.0 compliance:
- Add item titles extracted from memo content
- Include both description and content:encoded fields
- Add author information (name and email)
- Set proper Last-Modified headers
- Use specific application/rss+xml content type
Code quality:
- Fix potential index out of bounds panic in title generation
- Improve markdown heading stripping with regex (handles # to ######)
- Add proper HTTP caching headers (Cache-Control, ETag, Last-Modified)
- Thread-safe cache implementation with RWMutex
- Better error handling and edge case coverage
The RSS backend now follows industry best practices with optimal
performance, full standards compliance, and production-ready reliability.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements critical OAuth 2.0 security improvements to protect against authorization code interception attacks and improve provider compatibility:
- Add PKCE (RFC 7636) support with SHA-256 code challenge/verifier
- Fix access token extraction to use standard field instead of Extra()
- Add OAuth error parameter handling (access_denied, invalid_scope, etc.)
- Maintain backward compatibility for non-PKCE flows
This brings the OAuth implementation up to modern security standards as recommended by Auth0, Okta, and the OAuth 2.0 Security Best Current Practice (RFC 8252).
Backend changes:
- Add code_verifier parameter to ExchangeToken with PKCE support
- Use token.AccessToken for better provider compatibility
- Update proto definition with optional code_verifier field
Frontend changes:
- Generate cryptographically secure PKCE parameters
- Include code_challenge in authorization requests
- Handle and display OAuth provider errors gracefully
- Pass code_verifier during token exchange
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove enable_link_preview field from proto definitions
- Remove setting UI from MemoRelatedSettings component
- Remove translations from all 33 locale files
- Regenerate proto files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove disable_markdown_shortcuts field from proto definitions
- Remove setting UI from MemoRelatedSettings component
- Enable markdown shortcuts permanently in MemoEditor
- Remove translations from all 32 locale files
- Fix TypeScript error in useMemoSave hook by using typed translation function
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added MemoView component to display a single memo card with full functionality including creator info, memo content, attachments, reactions, and comments.
- Created MemoBody and MemoHeader subcomponents to separate concerns and improve maintainability.
- Introduced custom hooks for managing memo actions, keyboard shortcuts, NSFW content visibility, and image preview.
- Implemented reaction handling with new ReactionSelector and ReactionView components.
- Added TypeScript types for better type safety and clarity.
- Established constants for memo card styling and keyboard shortcuts.
- Removed legacy ReactionSelector and ReactionView components from the previous structure.
- Implemented LocationDialog component for selecting and entering location coordinates.
- Created useLocation hook to manage location state and updates.
- Added LocationState type for managing location data.
- Introduced useLinkMemo hook for linking memos with search functionality.
- Added VisibilitySelector component for selecting memo visibility.
- Refactored MemoEditor to integrate new hooks and components for improved functionality.
- Removed obsolete handlers and streamlined memo save logic with useMemoSave hook.
- Enhanced focus mode functionality with dedicated components for overlay and exit button.
Tags were missing CSS styles, appearing as plain text. Added text-primary
styling to Tag component and updated default theme primary color to match
other themes (blue hue 250, chroma 0.08) for consistency.
Fixes#5282🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Resolves issue where tag filtering in PostgreSQL databases failed with "operator does not exist: jsonb ~~ unknown" error. The hierarchical tag filtering feature introduced in commit 5e47f25b generated SQL with implicit type placeholders that PostgreSQL couldn't infer.
The fix explicitly casts the LIKE comparison placeholder to text (::text) in the PostgreSQL dialect, ensuring proper type resolution for the query parameter.
Fixes#5275🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The truncateAtWord function was slicing strings by byte position instead of
character position. When truncating text with multi-byte UTF-8 characters
(like CJK), this could cut in the middle of a character, creating invalid
UTF-8 and causing gRPC marshaling errors.
Fixed by converting to runes before truncation to ensure we always cut at
proper character boundaries. Added test cases for CJK characters.
Fixes#5276🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This fixes multiple issues with the tag sidebar and activity calendar:
1. Tag disappearing bug: When filtering by a tag, the sidebar now shows all tags instead of only the selected tag
2. Activity calendar filtering: Calendar now shows full activity history instead of filtered results
3. Auto-update on memo changes: Sidebar tags and calendar now update automatically when creating/editing memos without requiring manual page refresh
Technical changes:
- Modified useFilteredMemoStats to fetch unfiltered UserStats from backend API for Home/Profile pages
- Fixed key mismatch bug in userStore where stats were stored with inconsistent keys
- Added statsStateId update in fetchUserStats to trigger reactivity
- Updated MainLayout to pass appropriate userName based on page context
- Archived/Explore pages continue to compute from cached memos (correct behavior)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Pass i18n.language to time display components to ensure locale updates
when the user switches languages in UserMenu. Changes:
- MemoView: Pass i18n.language to toLocaleString() and <relative-time> lang attribute
- MonthNavigator: Wrap with observer to make component reactive to i18n.language changes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace custom character whitelist with Unicode standards-based validation:
- Use unicode.IsLetter/IsNumber/IsSymbol instead of hardcoded lists
- Remove manual UTF-8 byte checking for CJK punctuation
- Add proper rune-based length limiting (MAX_TAG_LENGTH = 100)
- Improve international character support (CJK, Arabic, Cyrillic, etc.)
- Add emoji support via unicode.IsSymbol
Benefits:
- Cleaner, more maintainable code (~50 lines removed)
- Standards-based approach following Unicode categories
- Better UTF-8 safety with utf8.DecodeRune
- Consistent validation between Go backend and TypeScript frontend
All existing tests pass with improved Unicode handling.
- Direct security reports to email only instead of public GitHub issues
- Set clear expectations: no CVEs during beta (v0.x) phase
- Add security best practices for self-hosted deployments
- Plan formal vulnerability disclosure program for v1.0+
Addresses #5255
The sidebar tag list wasn't updating when users created new memos with tags
or modified existing memo tags. This was because useFilteredMemoStats hook
only refetched when filter/state/orderBy changed.
Now the hook observes memoStore.state.stateId, which changes whenever memos
are created, updated, or deleted. This triggers automatic refetch and the
sidebar updates immediately with the latest tag counts.
Fixes tag refresh issue in sidebar
- Add MapCleanup component to properly remove Leaflet map instances on unmount
- Fix LocationMarker initialization with useRef to prevent re-initialization
- Remove problematic key prop in LocationDialog that caused unnecessary remounts
- Fix goimports formatting in tag parser
Fixes#5260
Fixes#5264
Chinese, Japanese, Korean, and other Unicode characters are now
properly recognized in hashtags, following the standard hashtag
parsing conventions used by Twitter, Instagram, and GitHub.
Changes:
- Updated tag parser to allow Unicode letters and digits
- Tags stop at whitespace and punctuation (both ASCII and CJK)
- Allow dash, underscore, forward slash in tags
- Added comprehensive tests for CJK characters and emoji
Examples:
- #测试 → recognized as tag '测试'
- #日本語 → recognized as tag '日本語'
- #한국어 → recognized as tag '한국어'
- #测试。→ recognized as tag '测试' (stops at punctuation)
- #work/测试/项目 → hierarchical tag with Unicode