Nostr-native communal events module using NIP-52 Calendar Events.
Includes types (activity, ticket, category, NIP-52 parsers/builders),
services (ActivitiesNostrService, TicketApiService, PaymentProvider
abstraction with LNbits implementation), Pinia store with deduplication,
module plugin with DI registration, i18n (EN/FR/ES), and placeholder views.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prevents the dialog from shifting up/down as account search results
change the content height, which caused it to move behind the
virtual keyboard on mobile.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Users can now type to search accounts instead of manually navigating
the hierarchy. Uses existing FuzzySearch component with Fuse.js.
Search matches against account names and descriptions. The hierarchical
browser remains available when the search input is empty.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The simplified Home.vue lost the useQuickActions system, which meant
module quick actions (expenses, submit link) were no longer accessible.
Restore the expandable FAB that shows all registered module actions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create links module (link aggregator from atio branch) with SubmissionService,
LinkPreviewService, voting, ranking, and full submission UI
- Create tasks module with TaskService (own relay subscription for kinds
31922/31925), extracted from nostr-feed's ScheduledEventService
- Promote ProfileService and ReactionService to base module as shared services
- Replace Home.vue feed with SubmissionList from links module
- Disable nostr-feed module (kept in codebase for future re-enablement)
- Add links and tasks to app.config, app.ts, navigation, and DI container
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The processIncomingMessage function was also being called for outgoing
messages from loadRecentMessagesForPeer, but was using the wrong pubkey
for decryption. NIP-04 requires YOUR private key + the OTHER party's
public key.
For outgoing messages, event.pubkey is the user's own pubkey, but it
should use the recipient's pubkey from the p-tag for decryption.
This fix:
- Detects if message is outgoing (event.pubkey === userPubkey)
- For outgoing: gets recipient pubkey from p-tag
- For incoming: uses event.pubkey (sender)
- Sets sent flag correctly based on direction
- Associates message with the correct peer
Fixes "aes/pcks5: wrong padding" console errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add "Powered by ⚡LNbits" link to both desktop and mobile sidebars
- Links to lnbits.com in new tab
- Includes separator divider above attribution
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Increase dropdown width from w-56 to w-64
- Prevents EverQuest-style coin display from being cut off
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Comment out Settings link in both desktop and mobile sidebars
- Comment out Relay Hub Status in user menu dropdown
- Add TODO comments to review implementing these in the future
- Comment out unused imports to fix TypeScript errors
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create ChatMessageContent component to detect and render order messages
- Display order details in a clean card format instead of raw JSON
- Show item count, shipping zone with truck icon, and short order ID
- Falls back to plain text for non-order messages
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add query parameter support (?tab=orders) to Market Dashboard
- Update CheckoutPage to navigate with tab=orders query param
- Dashboard validates tab param against allowed values
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Combine shipping and contact info into single step
- Remove BTC Onchain and Cashu payment options (Lightning only for now)
- Add collapsible section for optional contact info (email, npub, address)
- Keep shipping address visible when required for physical delivery
- Keep message to merchant visible by default
- Add TODO comment for future payment method expansion
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Changed updateStall from PATCH to PUT (LNbits API requirement)
- Updated to send full stall object instead of partial update
- Merges form values with existing stall data before sending
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Changed Home.vue sticky header from z-40 to z-30
- Changed SubmissionDetail.vue sticky header from z-40 to z-30
- AppTopBar remains at z-40, ensuring it stays above page content
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add new sidebar-based layout components:
- AppLayout.vue: Main layout wrapper with sidebar + topbar
- AppSidebar.vue: Desktop sidebar with navigation, theme, language
- AppTopBar.vue: Top bar with notifications, cart, profile
- MobileDrawer.vue: Slide-out drawer for mobile navigation
- Add Shadcn Sheet component for mobile drawer
- Update App.vue to use new AppLayout (except login page)
- Rename old Navbar.vue to Navbar.old.vue for reference
Layout structure:
- Desktop: Fixed 288px sidebar + offset content area
- Mobile: Hidden sidebar with drawer triggered from top bar
- Cart only shown when market module is enabled
- Combined notifications (chat unread count)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add spacing between header border and sort tabs for better visual
separation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Constrain feed content to max-w-4xl (896px) and center it, matching
the layout style of sites like programming.dev.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change SubmissionWithMeta from interface to type intersection
- Fix UseSubmissionsReturn types to use proper Ref/ComputedRef
- Remove unused imports across components and services
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The link aggregator is now the main feed, replacing the old NostrFeed
component. FAB button navigates to /submit for creating posts.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add watchers to fetch profiles when submissions and comments load,
ensuring display names are shown instead of pubkeys.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove test page with mock data and test relay connection UI.
The link aggregator is now ready for production use.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace native HTML select with themed Select component for proper
dark mode support.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace hardcoded Tailwind colors with semantic chart-* colors that
adapt to light/dark theme.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add inline reply form that appears below the comment being replied to
- Pass replyingToId and isSubmittingReply props through comment tree
- Add cancel-reply and submit-reply events for inline form handling
- Top composer now only shows for new top-level comments
- Better UX: no need to scroll to top to reply to nested comments
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change border-* to bg-* classes so threading lines actually display
- Tighten spacing to match Lemmy-style threading (ml-0.5, pl-2, py-1)
- Rename borderColor to depthColor for accuracy
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Implement downvote() for submissions using dislikeEvent
- Add refreshAllSubmissionVotes() to update all votes after EOSE
- Refresh submission votes after loading reactions in both subscribe methods
- Fixes vote state not displaying correctly on page load
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add fetchCommentReactions() to load reactions for all comments after EOSE
- Add updateCommentVotes() to refresh comment votes from ReactionService
- Add dislikeEvent() and undislikeEvent() to ReactionService for downvotes
- Update downvoteComment() to use ReactionService for persistence
- Fix vote button styling in SubmissionComment to properly show active state
- Wire up comment vote handlers in SubmissionDetail
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add subscribeToSubmission() to fetch submission + comments by ID
- Fix isComment check order - check before parseSubmission (which fails for comments)
- Update comment count on submission when comments are added
- Add duplicate comment detection to prevent double-display
- Update useSubmission composable to auto-subscribe on mount
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add createComment() method to SubmissionService for posting comments
- Add getSortedComments() with sort options: best, new, old, controversial
- Wire up comment submission in SubmissionDetail.vue
- Add comment sort dropdown in detail view
- Support replying to specific comments or root submission
- Display comment submission errors
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create SubmitComposer.vue with post type selector (text/link/media)
- Add debounced link preview fetching on URL input
- Wire up submission publishing via SubmissionService.createSubmission()
- Add /submit route with SubmitPage.vue wrapper
- Support community query param for pre-selection
- Include NSFW toggle and form validation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add SubmissionDetail.vue for full post view with content display
- Add SubmissionComment.vue for recursive threaded comments
- Add SubmissionDetailPage.vue route wrapper
- Add /submission/:id route to module
- Update SubmissionList share URL to use correct route
- Update test page to navigate to detail view on click
- Update plan document with Phase 4 completion
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add LinkAggregatorTest.vue with mock data and live submission views
- Include direct relay connection for testing kind 1111 events
- Add submission composer with self/link post types
- Add route at /link-aggregator-test
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement minimal, information-dense submission feed UI inspired by
old Reddit and Lemmy designs.
New components:
- VoteControls.vue: Compact vertical upvote/downvote arrows with score
- SubmissionThumbnail.vue: Small square thumbnail with fallback icons
- SubmissionRow.vue: Single submission row with title, metadata, actions
- SortTabs.vue: Sort tabs (hot, new, top, controversial) with time range
- SubmissionList.vue: Main container composing all components
UI features:
- Dense layout showing many items at once
- Hover-reveal secondary actions (share, save, hide, report)
- Domain display for link posts
- NSFW blur/badge support
- Rank numbers (optional)
- Time-ago formatting
- Score formatting (e.g., 1.2k)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement Reddit-style link aggregator foundation using NIP-72 (Moderated
Communities) and NIP-22 (Comments) specifications.
New files:
- types/submission.ts: Complete type definitions for submissions, voting,
communities, link previews, and ranking algorithms
- services/SubmissionService.ts: Core service for kind 1111 submission
events with parsing, creation, voting, and comment threading
- services/LinkPreviewService.ts: Open Graph metadata fetching with
caching, CORS proxy support, and oEmbed fallbacks
- composables/useSubmissions.ts: Vue composable for reactive submission
state management
- LINK_AGGREGATOR_PLAN.md: Implementation roadmap
Features:
- Three post types: link, media, self (text)
- NIP-22 compliant community-scoped posts
- NIP-92 media attachments with imeta tags
- Hot/Top/New/Controversial ranking algorithms
- Threaded comment support
- Upvote/downvote via NIP-25 reactions
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added full CRUD for shipping zones in MarketSettings.vue
- Added updateZone and deleteZone API methods to nostrmarketAPI.ts
- Zone form supports name, cost, and countries/regions
- Edit and delete zones with confirmation dialog
- Loading states and proper error handling with toast notifications
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rewrote MarketSettings.vue to use real Stall model fields
- Added updateStall API method to nostrmarketAPI.ts
- Editable fields: name, description, imageUrl
- Read-only fields: currency, shipping zones (set at creation)
- Form validation with Zod schema
- Loading states and proper error handling
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The CreateStoreDialog already shows a success toast with helpful message.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Call /api/v1/currencies endpoint on LNbits core (not nostrmarket extension)
- Ensure 'sat' is always first in the currency list and used as default
- Add loading state for currency dropdown
- Add key prop to Select component for proper reactivity
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove duplicate Add Product button from store header (keep the one in Products tab)
- Grey out Satisfaction card with "Coming Soon" badge (feature not yet implemented)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove Customer Actions and Merchant Actions cards from Overview
- Simplify My Store to single-store management (remove multi-store grid)
- Auto-select user's store when available
- Remove "Back to Stores" navigation (no longer needed)
- Clean up unused imports and functions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
**Problem:**
Task status changes (claim/start/complete/unclaim/delete) would update the
local UI state even when the Nostr event failed to publish to ANY relays.
This caused users to see "completed" tasks that were never actually published,
leading to confusion when the UI reverted after page refresh.
**Root Cause:**
ScheduledEventService optimistically updated local state after calling
publishEvent(), without checking if any relays accepted the event. If all
relay publishes failed (result.success = 0), the UI still updated.
**Solution:**
Modified RelayHub.publishEvent() to throw an error when no relays accept the
event (success = 0). This ensures:
- Existing try-catch blocks handle the error properly
- Error toast shown to user: "Failed to publish event - none of X relay(s) accepted it"
- Local state NOT updated (UI remains accurate)
- Consistent behavior across all services using publishEvent()
**Changes:**
- relay-hub.ts: Add check after publish - throw error if successful === 0
- ScheduledEventService.ts: Update comments to reflect new behavior
**Benefits:**
- Single source of truth for publish failure handling
- No code duplication (no need to check result.success everywhere)
- Better UX: Users immediately see error instead of false success
- UI state always matches server state after operations
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added ability for task authors to delete their own tasks from the expanded
view in the task feed.
**Features:**
- Delete button visible only to task author in expanded task view
- Confirmation dialog with destructive styling
- Publishes NIP-09 deletion event (kind 5) with 'a' tag referencing the
task's event address (kind:pubkey:d-tag format)
- Real-time deletion handling via FeedService routing
- Optimistic local state update for immediate UI feedback
**Implementation:**
- Added deleteTask() method to ScheduledEventService
- Added handleTaskDeletion() for processing incoming deletion events
- Updated FeedService to route kind 31922 deletions to ScheduledEventService
- Added delete button and dialog flow to ScheduledEventCard component
- Integrated with existing confirmation dialog pattern
**Permissions:**
- Only task authors can delete tasks (enforced by isAuthor check)
- NIP-09 validation: relays only accept deletion from event author
- Pubkey verification in handleTaskDeletion()
**Testing:**
- Created tasks and verified delete button appears for author only
- Confirmed deletion removes task from UI immediately
- Verified deletion persists after refresh
- Tested with multiple users - others cannot delete
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Require users to confirm they've communicated with the team before unclaiming a task to prevent coordination issues.
Changes:
- Add hasConfirmedCommunication checkbox state
- Show checkbox in unclaim confirmation dialog
- Disable "Unclaim Task" button until checkbox is checked
- Reset checkbox state when dialog is closed/cancelled
- Update dialog description to prompt communication
UX Flow:
1. User clicks "Unclaim" button
2. Dialog appears with message about removing claim
3. Checkbox: "I have communicated this to the team"
4. "Unclaim Task" button disabled until checkbox checked
5. Forces user acknowledgment before unclaiming
This prevents situations where:
- Someone unclaims without notifying others working on related tasks
- Team members are left confused about task status
- Work gets duplicated or blocked due to lack of communication
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Refine unclaim button visibility to prevent confusing UX where users could "unclaim" status updates they didn't claim.
Changes:
- Only show "Unclaim" button when task is in "claimed" state
- Remove "Unclaim" button from in-progress and completed states
- Maintain check that current user must be the claimer
Rationale:
- Prevents confusion where user marks task in-progress but sees "Unclaim"
- "Unclaim" makes sense only for the original claim action
- Users can still update status (mark in-progress/complete) on any task
- But only the claimer can unclaim the original claim
Example scenarios:
- Alice claims task → Alice sees "Unclaim" button
- Bob marks Alice's task as in-progress → Bob does NOT see "Unclaim"
- Only Alice can unclaim, reverting task to unclaimed state
This simple rule prevents UX confusion until we implement full per-user status tracking.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>