- Reorganize all markdown documentation into structured docs/ folder - Create 7 main documentation categories (00-overview through 06-deployment) - Add comprehensive index files for each category with cross-linking - Implement Obsidian-compatible [[link]] syntax throughout - Move legacy/deprecated documentation to archive folder - Establish documentation standards and maintenance guidelines - Provide complete coverage of modular architecture, services, and deployment - Enable better navigation and discoverability for developers and contributors 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1117 lines
32 KiB
Markdown
1117 lines
32 KiB
Markdown
# Ario Web App Architecture
|
|
|
|
> **⚠️ DEPRECATED DOCUMENT**
|
|
> **Date**: September 6, 2025
|
|
> **Status**: This document describes the legacy singleton-based architecture which has been replaced by a **modular service-based architecture** with dependency injection.
|
|
>
|
|
> **Current Architecture**: See `CLAUDE.md` and `docs/modular-architecture-analysis.md` for up-to-date information.
|
|
|
|
## Overview
|
|
|
|
~~The Ario web app uses a **singleton-based architecture** to manage shared state and resources across components. This document explains how the core singletons work and how different components (chat, market, feed) plug into the system.~~
|
|
|
|
**Updated**: The Ario web app now uses a modular plugin architecture with dependency injection through the BaseService pattern and SERVICE_TOKENS.
|
|
|
|
## Core Singleton Architecture
|
|
|
|
### 1. Authentication Singleton (`useAuth`)
|
|
|
|
**Location**: `src/composables/useAuth.ts`
|
|
|
|
**Purpose**: Manages user authentication state using LNBits integration.
|
|
|
|
**Singleton Pattern**:
|
|
```typescript
|
|
export function useAuth() {
|
|
// ... implementation
|
|
}
|
|
|
|
// Export singleton instance for global state
|
|
export const auth = useAuth()
|
|
```
|
|
|
|
**Usage**: Imported throughout the app for authentication state:
|
|
```typescript
|
|
import { auth } from '@/composables/useAuth'
|
|
|
|
// All components see the same authentication state
|
|
console.log(auth.isAuthenticated.value)
|
|
```
|
|
|
|
### 2. Relay Hub Singleton (`relayHub`)
|
|
|
|
**Location**: `src/lib/nostr/relayHub.ts`
|
|
|
|
**Purpose**: Centralized management of Nostr relay connections, providing a single WebSocket connection pool for the entire application.
|
|
|
|
**Singleton Pattern**:
|
|
```typescript
|
|
export class RelayHub extends EventEmitter {
|
|
// ... implementation
|
|
}
|
|
|
|
// Export singleton instance
|
|
export const relayHub = new RelayHub()
|
|
```
|
|
|
|
**Key Features**:
|
|
- Single WebSocket connection pool
|
|
- Automatic reconnection and health checks
|
|
- Event broadcasting for connection state changes
|
|
- Mobile visibility handling for WebSocket management
|
|
|
|
### 3. Relay Hub Composable Singleton (`useRelayHub`)
|
|
|
|
**Location**: `src/composables/useRelayHub.ts`
|
|
|
|
**Purpose**: Vue-reactive wrapper around the core `relayHub` instance, providing reactive state and Vue-specific functionality.
|
|
|
|
**Singleton Pattern**:
|
|
```typescript
|
|
export function useRelayHub() {
|
|
// Uses the same relayHub instance
|
|
const initialize = async () => {
|
|
await relayHub.initialize(relayUrls)
|
|
}
|
|
|
|
return { initialize, connect, disconnect, ... }
|
|
}
|
|
|
|
// Export singleton instance
|
|
export const relayHubComposable = useRelayHub()
|
|
```
|
|
|
|
**Relationship**: This composable wraps the core `relayHub` instance, making it Vue-reactive while maintaining the singleton connection pool.
|
|
|
|
### 4. Chat Singleton (`useNostrChat`)
|
|
|
|
**Location**: `src/composables/useNostrChat.ts`
|
|
|
|
**Purpose**: Manages Nostr chat functionality including message encryption/decryption, peer management, and real-time messaging.
|
|
|
|
**Singleton Pattern**:
|
|
```typescript
|
|
export function useNostrChat() {
|
|
// ... implementation
|
|
}
|
|
|
|
// Export singleton instance for global state
|
|
export const nostrChat = useNostrChat()
|
|
```
|
|
|
|
**Relay Hub Integration**: Uses `useRelayHub()` to connect to relays and manage subscriptions.
|
|
|
|
### 5. Market Singleton (`useMarket`)
|
|
|
|
**Location**: `src/composables/useMarket.ts`
|
|
|
|
**Purpose**: Manages market functionality including stalls, products, and market data.
|
|
|
|
**Singleton Pattern**:
|
|
```typescript
|
|
export function useMarket() {
|
|
// ... implementation
|
|
}
|
|
|
|
// Export singleton instance
|
|
export const market = useMarket()
|
|
```
|
|
|
|
**Relay Hub Integration**: Uses `useRelayHub()` to fetch market data from Nostr relays.
|
|
|
|
### 6. Nostr Store Singleton (`useNostrStore`)
|
|
|
|
**Location**: `src/stores/nostr.ts`
|
|
|
|
**Purpose**: Pinia store for Nostr-related state including push notifications and relay connection status.
|
|
|
|
**Singleton Pattern**:
|
|
```typescript
|
|
export const useNostrStore = defineStore('nostr', () => {
|
|
// ... implementation
|
|
})
|
|
```
|
|
|
|
**Relay Hub Integration**: Imports the `relayHub` singleton directly for connection management.
|
|
|
|
## Component Integration Architecture
|
|
|
|
### How Components Plug Into the System
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Component Layer │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ ChatComponent │ NostrFeed │ Market.vue │ Navbar.vue │
|
|
│ ↓ │ ↓ │ ↓ │ ↓ │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Composable Layer │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ useNostrChat │ useRelayHub │ useMarket │ useAuth │
|
|
│ ↓ │ ↓ │ ↓ │ ↓ │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Singleton Instance Layer │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ nostrChat │ relayHub │ market │ auth │
|
|
│ ↓ │ ↓ │ ↓ │ ↓ │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Core Implementation Layer │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ RelayHub │ LNBits API │ Market API │ Chat API │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 1. Chat Component Integration
|
|
|
|
**Component**: `src/components/nostr/ChatComponent.vue`
|
|
|
|
**Integration Path**:
|
|
```typescript
|
|
// 1. Component imports the chat singleton
|
|
import { nostrChat } from '@/composables/useNostrChat'
|
|
|
|
// 2. Chat singleton uses relay hub composable
|
|
import { useRelayHub } from './useRelayHub'
|
|
|
|
// 3. Relay hub composable uses core relay hub singleton
|
|
import { relayHub } from '../lib/nostr/relayHub'
|
|
```
|
|
|
|
**Data Flow**:
|
|
```
|
|
ChatComponent → nostrChat → useRelayHub → relayHub → Nostr Relays
|
|
↓ ↓ ↓ ↓
|
|
UI Updates Chat State Vue State WebSocket
|
|
```
|
|
|
|
**Key Benefits**:
|
|
- Single chat state across all components
|
|
- Shared relay connections
|
|
- Centralized message encryption/decryption
|
|
- Unified peer management
|
|
|
|
### 2. Feed Component Integration
|
|
|
|
**Component**: `src/components/nostr/NostrFeed.vue`
|
|
|
|
**Integration Path**:
|
|
```typescript
|
|
// 1. Component imports relay hub composable
|
|
import { useRelayHub } from '@/composables/useRelayHub'
|
|
|
|
// 2. Relay hub composable uses core relay hub singleton
|
|
import { relayHub } from '../lib/nostr/relayHub'
|
|
```
|
|
|
|
**Data Flow**:
|
|
```
|
|
NostrFeed → useRelayHub → relayHub → Nostr Relays
|
|
↓ ↓ ↓
|
|
Feed UI Vue State WebSocket
|
|
```
|
|
|
|
**Key Benefits**:
|
|
- Real-time feed updates
|
|
- Shared relay connections
|
|
- Centralized admin filtering
|
|
- Efficient event subscription management
|
|
|
|
### 3. Market Component Integration
|
|
|
|
**Component**: `src/pages/Market.vue`
|
|
|
|
**Integration Path**:
|
|
```typescript
|
|
// 1. Component uses market composable
|
|
import { useMarket } from '@/composables/useMarket'
|
|
|
|
// 2. Market composable uses relay hub composable
|
|
import { useRelayHub } from './useRelayHub'
|
|
|
|
// 3. Relay hub composable uses core relay hub singleton
|
|
import { relayHub } from '../lib/nostr/relayHub'
|
|
```
|
|
|
|
**Data Flow**:
|
|
```
|
|
Market.vue → useMarket → useRelayHub → relayHub → Nostr Relays
|
|
↓ ↓ ↓ ↓
|
|
Market UI Market Vue State WebSocket
|
|
State
|
|
```
|
|
|
|
**Key Benefits**:
|
|
- Centralized market data
|
|
- Shared relay connections
|
|
- Efficient product/stall fetching
|
|
- Real-time market updates
|
|
|
|
## Singleton Benefits in Practice
|
|
|
|
### 1. **Shared Connection State**
|
|
```typescript
|
|
// Component A
|
|
const { isConnected } = useRelayHub()
|
|
console.log(isConnected.value) // true
|
|
|
|
// Component B (different part of app)
|
|
const { isConnected } = useRelayHub()
|
|
console.log(isConnected.value) // true (same state!)
|
|
```
|
|
|
|
### 2. **Centralized Resource Management**
|
|
```typescript
|
|
// All components share the same WebSocket connections
|
|
relayHub.connectedRelayCount // Same value everywhere
|
|
relayHub.totalSubscriptionCount // Same value everywhere
|
|
```
|
|
|
|
### 3. **Event Broadcasting**
|
|
```typescript
|
|
// Component A listens to connection events
|
|
relayHub.on('connected', () => console.log('Connected!'))
|
|
|
|
// Component B triggers connection
|
|
await relayHub.connect() // Component A gets notified!
|
|
```
|
|
|
|
### 4. **Efficient Resource Usage**
|
|
- **Before**: Each component creates its own relay connections
|
|
- **After**: Single connection pool shared across all components
|
|
- **Result**: Reduced memory usage, better performance, consistent state
|
|
|
|
## Configuration and Environment Variables
|
|
|
|
### Required Environment Variables
|
|
```bash
|
|
# Nostr relay configuration
|
|
VITE_NOSTR_RELAYS=["wss://relay1.example.com", "wss://relay2.example.com"]
|
|
|
|
# Admin pubkeys for feed filtering
|
|
VITE_ADMIN_PUBKEYS=["npub1admin1...", "npub1admin2..."]
|
|
|
|
# LNBits API configuration
|
|
VITE_LNBITS_BASE_URL=https://your-lnbits-instance.com
|
|
VITE_API_KEY=your-api-key
|
|
```
|
|
|
|
### Configuration Structure
|
|
```typescript
|
|
// src/lib/config/index.ts
|
|
export const config: AppConfig = {
|
|
nostr: {
|
|
relays: parseJsonEnv(import.meta.env.VITE_NOSTR_RELAYS, []),
|
|
adminPubkeys: parseJsonEnv(import.meta.env.VITE_ADMIN_PUBKEYS, [])
|
|
},
|
|
api: {
|
|
baseUrl: import.meta.env.VITE_LNBITS_BASE_URL || '',
|
|
key: import.meta.env.VITE_API_KEY || ''
|
|
}
|
|
}
|
|
```
|
|
|
|
## Testing and Development
|
|
|
|
### Mocking Singletons for Testing
|
|
```typescript
|
|
// In test files, you can mock the singleton instances
|
|
import { auth } from '@/composables/useAuth'
|
|
import { nostrChat } from '@/composables/useNostrChat'
|
|
|
|
// Mock the singletons
|
|
vi.mock('@/composables/useAuth', () => ({
|
|
auth: {
|
|
isAuthenticated: ref(false),
|
|
currentUser: ref(null)
|
|
}
|
|
}))
|
|
```
|
|
|
|
### Development Benefits
|
|
- **Hot Reload**: Singleton state persists across component reloads
|
|
- **Debugging**: Single point of inspection for shared state
|
|
- **Performance**: No unnecessary re-initialization of expensive resources
|
|
|
|
## Best Practices
|
|
|
|
### 1. **Always Use the Singleton Instance**
|
|
```typescript
|
|
// ✅ Good: Use the exported singleton
|
|
import { auth } from '@/composables/useAuth'
|
|
import { nostrChat } from '@/composables/useNostrChat'
|
|
|
|
// ❌ Bad: Don't create new instances
|
|
const { currentUser } = useAuth() // This creates a new instance!
|
|
```
|
|
|
|
### 2. **Access State Through Composables**
|
|
```typescript
|
|
// ✅ Good: Use the composable wrapper for reactive state
|
|
const { isConnected, connectionStatus } = useRelayHub()
|
|
|
|
// ❌ Bad: Don't access relayHub directly in components
|
|
import { relayHub } from '@/lib/nostr/relayHub'
|
|
console.log(relayHub.isConnected) // Not reactive!
|
|
```
|
|
|
|
### 3. **Listen to Events for State Changes**
|
|
```typescript
|
|
// ✅ Good: Listen to relay hub events
|
|
relayHub.on('connected', () => {
|
|
console.log('Relay connected!')
|
|
})
|
|
|
|
// ❌ Bad: Don't poll for state changes
|
|
setInterval(() => {
|
|
console.log(relayHub.isConnected) // Inefficient!
|
|
}, 1000)
|
|
```
|
|
|
|
## Conclusion
|
|
|
|
The singleton architecture in Ario provides:
|
|
|
|
1. **Efficient Resource Management**: Single connection pools and shared state
|
|
2. **Consistent User Experience**: All components see the same data
|
|
3. **Simplified Development**: Clear patterns for state management
|
|
4. **Better Performance**: No duplicate connections or state
|
|
5. **Easier Testing**: Centralized mocking of shared resources
|
|
|
|
This architecture makes the app more maintainable, performant, and user-friendly while providing a solid foundation for future features.
|
|
|
|
## Shared Nostr Function Execution
|
|
|
|
### Event Building and Publishing Pattern
|
|
|
|
All components that need to create and publish Nostr events follow a consistent pattern through the relay hub singleton:
|
|
|
|
#### 1. Event Creation Utilities
|
|
|
|
**Direct Event Template Creation** (used in `useNostrChat`):
|
|
```typescript
|
|
import { nip04, finalizeEvent, type EventTemplate } from 'nostr-tools'
|
|
|
|
// Create event template
|
|
const eventTemplate: EventTemplate = {
|
|
kind: 4, // Encrypted DM
|
|
created_at: Math.floor(Date.now() / 1000),
|
|
tags: [['p', peerPubkey]]
|
|
content: encryptedContent
|
|
}
|
|
|
|
// Finalize and sign the event
|
|
const event = finalizeEvent(eventTemplate, hexToBytes(privateKey))
|
|
```
|
|
|
|
**Market Event Creation** (used in `useMarket`):
|
|
```typescript
|
|
// Market events use specific kinds and tags
|
|
const MARKET_EVENT_KINDS = {
|
|
STALL: 30017,
|
|
PRODUCT: 30018,
|
|
MARKET: 30019
|
|
}
|
|
|
|
// Extract data from event tags
|
|
const stallId = event.tags.find((tag: any) => tag[0] === 'd')?.[1]
|
|
const productId = event.tags.find((tag: any) => tag[0] === 'd')?.[1]
|
|
```
|
|
|
|
#### 2. Centralized Publishing Through Relay Hub
|
|
|
|
**All components publish through the same singleton**:
|
|
```typescript
|
|
// In useNostrChat.ts
|
|
await relayHub.publishEvent(event)
|
|
|
|
// In useMarket.ts (if publishing)
|
|
await relayHub.publishEvent(event)
|
|
|
|
// In any other component
|
|
await relayHub.publishEvent(event)
|
|
```
|
|
|
|
**Relay Hub Publishing Logic**:
|
|
```typescript
|
|
async publishEvent(event: Event): Promise<{ success: number; total: number }> {
|
|
if (!this._isConnected) {
|
|
throw new Error('Not connected to any relays')
|
|
}
|
|
|
|
const relayUrls = Array.from(this.connectedRelays.keys())
|
|
const results = await Promise.allSettled(
|
|
relayUrls.map(relay => this.pool.publish([relay], event))
|
|
)
|
|
|
|
const successful = results.filter(result => result.status === 'fulfilled').length
|
|
const total = results.length
|
|
|
|
this.emit('eventPublished', { eventId: event.id, success: successful, total })
|
|
return { success: successful, total }
|
|
}
|
|
```
|
|
|
|
#### 3. Event Querying and Subscription
|
|
|
|
**Consistent Query Interface**:
|
|
```typescript
|
|
// One-time event queries
|
|
const events = await relayHub.queryEvents(filters)
|
|
|
|
// Real-time subscriptions
|
|
const unsubscribe = relayHub.subscribe({
|
|
id: 'subscription-id',
|
|
filters: [{ kinds: [1], limit: 50 }],
|
|
onEvent: (event) => {
|
|
// Handle incoming event
|
|
}
|
|
})
|
|
```
|
|
|
|
### Shared Dependencies
|
|
|
|
**nostr-tools Package**:
|
|
- `finalizeEvent` - Event signing and finalization
|
|
- `nip04` - Encrypted message handling
|
|
- `SimplePool` - Relay connection management
|
|
- `EventTemplate` - Event structure typing
|
|
|
|
**Common Event Patterns**:
|
|
- **Text Notes** (kind 1): Community posts and announcements
|
|
- **Encrypted DMs** (kind 4): Private chat messages
|
|
- **Market Events** (kinds 30017-30019): Stall, product, and market data
|
|
- **Reactions** (kind 7): Emoji reactions to posts
|
|
|
|
## Configuration Management
|
|
|
|
### Environment Variables and Configuration
|
|
|
|
**Centralized Config** (`src/lib/config/index.ts`):
|
|
```typescript
|
|
interface NostrConfig {
|
|
relays: string[]
|
|
adminPubkeys: string[]
|
|
}
|
|
|
|
interface MarketConfig {
|
|
defaultNaddr: string
|
|
supportedRelays: string[]
|
|
lightningEnabled: boolean
|
|
defaultCurrency: string
|
|
}
|
|
|
|
// Environment variables
|
|
VITE_NOSTR_RELAYS: JSON array of relay URLs
|
|
VITE_ADMIN_PUBKEYS: JSON array of admin public keys
|
|
VITE_MARKET_RELAYS: JSON array of market-specific relays
|
|
VITE_LIGHTNING_ENABLED: Boolean for Lightning integration
|
|
```
|
|
|
|
**Default Relay Configuration**:
|
|
```typescript
|
|
// Fallback relay configuration
|
|
supportedRelays: [
|
|
'ws://127.0.0.1:7777',
|
|
'wss://relay.damus.io',
|
|
'wss://relay.snort.social',
|
|
'wss://nostr-pub.wellorder.net',
|
|
'wss://nostr.zebedee.cloud',
|
|
'wss://nostr.walletofsatoshi.com'
|
|
]
|
|
```
|
|
|
|
### Configuration Utilities
|
|
|
|
**Admin Pubkey Validation**:
|
|
```typescript
|
|
export const configUtils = {
|
|
isAdminPubkey(pubkey: string): boolean {
|
|
return config.nostr.adminPubkeys.includes(pubkey)
|
|
}
|
|
}
|
|
```
|
|
|
|
## Error Handling and Resilience
|
|
|
|
### Connection Management
|
|
|
|
**Automatic Reconnection**:
|
|
```typescript
|
|
// Relay hub automatically handles reconnection
|
|
private scheduleReconnect(): void {
|
|
if (this.reconnectInterval) {
|
|
clearTimeout(this.reconnectInterval)
|
|
}
|
|
|
|
this.reconnectInterval = setTimeout(async () => {
|
|
await this.connect()
|
|
}, this.reconnectDelay)
|
|
}
|
|
```
|
|
|
|
**Health Monitoring**:
|
|
```typescript
|
|
// Continuous health checks
|
|
private startHealthCheck(): void {
|
|
this.healthCheckInterval = setInterval(() => {
|
|
this.performHealthCheck()
|
|
}, this.healthCheckIntervalMs)
|
|
}
|
|
```
|
|
|
|
### Error Handling Patterns
|
|
|
|
**Graceful Degradation**:
|
|
```typescript
|
|
// Components handle connection failures gracefully
|
|
async function loadNotes() {
|
|
try {
|
|
if (!relayHub.isConnected.value) {
|
|
await relayHub.connect()
|
|
}
|
|
// ... load notes
|
|
} catch (err) {
|
|
error.value = err instanceof Error ? err : new Error('Failed to load notes')
|
|
console.error('Failed to load notes:', err)
|
|
}
|
|
}
|
|
```
|
|
|
|
**Retry Logic**:
|
|
```typescript
|
|
// Market app retry pattern
|
|
async def wait_for_nostr_events(nostr_client: NostrClient):
|
|
while True:
|
|
try:
|
|
await subscribe_to_all_merchants()
|
|
# ... process events
|
|
except Exception as e:
|
|
logger.warning(f"Subscription failed. Will retry in one minute: {e}")
|
|
await asyncio.sleep(10)
|
|
```
|
|
|
|
## Event Processing and Filtering
|
|
|
|
### Filter Management
|
|
|
|
**Dynamic Filter Creation**:
|
|
```typescript
|
|
// Feed component creates filters based on type
|
|
const filters: any[] = [{
|
|
kinds: [1], // TEXT_NOTE
|
|
limit: 50
|
|
}]
|
|
|
|
// Filter by authors for announcements
|
|
if (props.feedType === 'announcements' && hasAdminPubkeys.value) {
|
|
filters[0].authors = adminPubkeys
|
|
}
|
|
```
|
|
|
|
**Market Event Filtering**:
|
|
```typescript
|
|
// Market-specific filters
|
|
const _filters_for_stall_events = (public_keys: List[str], since: int) -> List:
|
|
stall_filter = {"kinds": [30017], "authors": public_keys}
|
|
if since and since != 0:
|
|
stall_filter["since"] = since
|
|
return [stall_filter]
|
|
```
|
|
|
|
### Event Processing Pipeline
|
|
|
|
**Event Processing Flow**:
|
|
```typescript
|
|
// 1. Receive event from relay
|
|
onEvent: (event) => {
|
|
// 2. Process and transform
|
|
const newNote = {
|
|
id: event.id,
|
|
pubkey: event.pubkey,
|
|
content: event.content,
|
|
created_at: event.created_at,
|
|
tags: event.tags || [],
|
|
mentions: event.tags?.filter(tag => tag[0] === 'p').map(tag => tag[1]) || [],
|
|
isReply: event.tags?.some(tag => tag[0] === 'e' && tag[3] === 'reply'),
|
|
replyTo: event.tags?.find(tag => tag[0] === 'e' && tag[3] === 'reply')?.[1]
|
|
}
|
|
|
|
// 3. Apply business logic filters
|
|
let shouldInclude = true
|
|
if (props.feedType === 'announcements' && !isAdminPost(event.pubkey)) {
|
|
shouldInclude = false
|
|
}
|
|
|
|
// 4. Add to state if approved
|
|
if (shouldInclude) {
|
|
notes.value.unshift(newNote)
|
|
// 5. Limit array size for memory management
|
|
if (notes.value.length > 100) {
|
|
notes.value = notes.value.slice(0, 100)
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Performance Optimizations
|
|
|
|
### Memory Management
|
|
|
|
**Array Size Limits**:
|
|
```typescript
|
|
// Prevent memory issues with large feeds
|
|
if (notes.value.length > 100) {
|
|
notes.value = notes.value.slice(0, 100)
|
|
}
|
|
```
|
|
|
|
**Subscription Cleanup**:
|
|
```typescript
|
|
// Proper cleanup prevents memory leaks
|
|
onUnmounted(() => {
|
|
if (unsubscribe) {
|
|
unsubscribe()
|
|
unsubscribe = null
|
|
}
|
|
})
|
|
```
|
|
|
|
### Connection Pooling
|
|
|
|
**Shared WebSocket Connections**:
|
|
```typescript
|
|
// Single pool shared across all components
|
|
private pool: SimplePool
|
|
|
|
// Components don't create individual connections
|
|
// They all use the centralized relay hub
|
|
```
|
|
|
|
**Efficient Relay Usage**:
|
|
```typescript
|
|
// Query multiple relays simultaneously
|
|
const events = await this.pool.querySync(availableRelays, filter)
|
|
|
|
// Publish to all relays in parallel
|
|
const results = await Promise.allSettled(
|
|
relayUrls.map(relay => this.pool.publish([relay], event))
|
|
)
|
|
```
|
|
|
|
## Security Considerations
|
|
|
|
### Encryption and Privacy
|
|
|
|
**End-to-End Encryption**:
|
|
```typescript
|
|
// All chat messages are encrypted using nip04
|
|
const encryptedContent = await nip04.encrypt(
|
|
privateKey,
|
|
publicKey,
|
|
content
|
|
)
|
|
```
|
|
|
|
**Private Key Management**:
|
|
```typescript
|
|
// Keys never leave the browser
|
|
// Validation of key format and length
|
|
if (privateKey.length !== 64) {
|
|
throw new Error(`Invalid private key length: ${privateKey.length} (expected 64)`)
|
|
}
|
|
|
|
// Hex format validation
|
|
const hexRegex = /^[0-9a-fA-F]+$/
|
|
if (!hexRegex.test(privateKey)) {
|
|
throw new Error(`Invalid private key format: contains non-hex characters`)
|
|
}
|
|
```
|
|
|
|
### Access Control
|
|
|
|
**Admin Pubkey Validation**:
|
|
```typescript
|
|
// Only admin pubkeys can post announcements
|
|
function isAdminPost(pubkey: string): boolean {
|
|
return configUtils.isAdminPubkey(pubkey)
|
|
}
|
|
|
|
// Filter content based on user permissions
|
|
if (props.feedType === 'announcements' && !isAdminPost(event.pubkey)) {
|
|
shouldInclude = false
|
|
}
|
|
```
|
|
|
|
## Benefits of This Architecture
|
|
|
|
### 1. **Consistent Event Handling**
|
|
- All components use the same event creation and publishing patterns
|
|
- Centralized relay management ensures consistent behavior
|
|
- Shared error handling and retry logic
|
|
|
|
### 2. **Efficient Resource Usage**
|
|
- Single WebSocket connection pool shared across all components
|
|
- No duplicate relay connections
|
|
- Centralized connection health monitoring
|
|
|
|
### 3. **Simplified Component Logic**
|
|
- Components focus on business logic, not relay management
|
|
- Consistent API for all Nostr operations
|
|
- Easy to add new event types and functionality
|
|
|
|
### 4. **Maintainable Codebase**
|
|
- Single source of truth for relay connections
|
|
- Centralized event publishing logic
|
|
- Easy to debug and monitor Nostr operations
|
|
|
|
### 5. **Robust Error Handling**
|
|
- Automatic reconnection and health monitoring
|
|
- Graceful degradation when relays are unavailable
|
|
- Comprehensive error logging and user feedback
|
|
|
|
### 6. **Performance Optimized**
|
|
- Memory management with array size limits
|
|
- Efficient connection pooling
|
|
- Parallel relay operations
|
|
|
|
## Future Extensibility
|
|
|
|
This architecture makes it easy to add new Nostr functionality:
|
|
|
|
1. **New Event Types**: Add new event creation utilities following the existing pattern
|
|
2. **Additional Relays**: Configure new relays in the centralized relay hub
|
|
3. **New Components**: Import the existing singletons and use the established patterns
|
|
4. **Enhanced Features**: Extend the relay hub with new capabilities (e.g., event caching, filtering)
|
|
5. **Advanced Filtering**: Implement more sophisticated event filtering and processing
|
|
6. **Caching Layer**: Add event caching for improved performance
|
|
7. **Rate Limiting**: Implement rate limiting for relay operations
|
|
8. **Metrics and Monitoring**: Add comprehensive metrics for relay performance
|
|
|
|
This architecture makes the app more maintainable, performant, and user-friendly while providing a solid foundation for future features.
|
|
|
|
## Market Integration Roadmap
|
|
|
|
### Overview
|
|
This document outlines the roadmap for integrating the nostr-market-app purchasing functionality into the web-app, creating a seamless e-commerce experience while maintaining the decentralized, Nostr-based architecture.
|
|
|
|
### Analysis of nostr-market-app Purchasing Flow
|
|
|
|
The nostr-market-app has a sophisticated purchasing system with the following key components:
|
|
|
|
#### 1. Shopping Cart System
|
|
- **Cart Management**: Products are added to stall-specific carts
|
|
- **Cart State**: Each stall has its own cart with products and quantities
|
|
- **Cart Persistence**: Cart data is stored locally and synced across sessions
|
|
|
|
#### 2. Checkout Process
|
|
- **Order Confirmation**: Users provide contact information (address, email, message)
|
|
- **Shipping Selection**: Multiple shipping zones with different costs
|
|
- **Payment Options**: Lightning Network, BTC Onchain, and Cashu support
|
|
|
|
#### 3. Order Placement
|
|
- **Encrypted Communication**: Orders are encrypted using NIP-04 and sent as direct messages
|
|
- **Order Structure**: Includes product details, quantities, shipping, and contact info
|
|
- **Payment Integration**: Lightning invoice generation and QR code display
|
|
|
|
#### 4. Key Components
|
|
- `ShoppingCartCheckout.vue` - Main checkout interface
|
|
- `useShoppingCart.js` - Cart management logic
|
|
- `useOrders.js` - Order placement and management
|
|
- `marketStore.js` - Central state management
|
|
|
|
### Implementation Roadmap
|
|
|
|
#### Phase 1: Enhanced Shopping Cart System (High Priority)
|
|
|
|
**1.1 Extend Market Store**
|
|
- Add cart management with stall-specific carts
|
|
- Implement cart persistence and synchronization
|
|
- Add shipping zone support
|
|
- Extend existing `useMarketStore` with cart functionality
|
|
|
|
**1.2 Create Cart Components**
|
|
- `ShoppingCart.vue` - Cart overview and management
|
|
- `CartItem.vue` - Individual cart item with quantity controls
|
|
- `CartSummary.vue` - Cart totals and checkout button
|
|
- Integrate cart icon in header with item count
|
|
|
|
**1.3 Cart State Management**
|
|
- Implement stall-specific cart structure
|
|
- Add cart persistence to local storage
|
|
- Sync cart state across components
|
|
- Handle cart updates and real-time synchronization
|
|
|
|
#### Phase 2: Checkout System (High Priority)
|
|
|
|
**2.1 Checkout Flow**
|
|
- `CheckoutPage.vue` - Main checkout interface
|
|
- Contact information form (address, email, message)
|
|
- Shipping zone selection with cost calculation
|
|
- Order summary and confirmation
|
|
|
|
**2.2 Payment Integration**
|
|
- Lightning Network invoice generation
|
|
- QR code display for payments
|
|
- Payment status tracking
|
|
- Integration with existing payment infrastructure
|
|
|
|
**2.3 Checkout State Management**
|
|
- Form validation and error handling
|
|
- Multi-step checkout process
|
|
- Order confirmation and review
|
|
|
|
#### Phase 3: Order Management (Medium Priority)
|
|
|
|
**3.1 Order Processing**
|
|
- Encrypted order creation using NIP-04
|
|
- Direct message sending to merchants
|
|
- Order status tracking and updates
|
|
- Integration with existing Nostr messaging system
|
|
|
|
**3.2 Order History**
|
|
- `OrdersPage.vue` - User's order history
|
|
- Order status updates and notifications
|
|
- Communication with merchants
|
|
- Order filtering and search
|
|
|
|
**3.3 Order Communication**
|
|
- Encrypted messaging between buyers and sellers
|
|
- Order status notifications
|
|
- Shipping updates and tracking
|
|
|
|
#### Phase 4: Enhanced User Experience (Medium Priority)
|
|
|
|
**4.1 Streamlined Navigation**
|
|
- Integrated cart icon in header
|
|
- Quick checkout from product cards
|
|
- Seamless flow between browsing and purchasing
|
|
- Breadcrumb navigation for checkout process
|
|
|
|
**4.2 Real-time Updates**
|
|
- Live inventory updates
|
|
- Order status notifications
|
|
- Chat integration with merchants
|
|
- WebSocket connections for live updates
|
|
|
|
#### Phase 5: Advanced Features (Low Priority)
|
|
|
|
**5.1 Multiple Payment Methods**
|
|
- BTC Onchain payments
|
|
- Cashu integration
|
|
- Payment method selection
|
|
- Payment preference storage
|
|
|
|
**5.2 Advanced Filtering and Search**
|
|
- Enhanced product search
|
|
- Advanced filtering options
|
|
- Saved search preferences
|
|
- Product recommendations
|
|
|
|
**5.3 Merchant Tools**
|
|
- Merchant dashboard
|
|
- Inventory management
|
|
- Order fulfillment tools
|
|
- Analytics and reporting
|
|
|
|
### Technical Implementation Details
|
|
|
|
#### State Management Architecture
|
|
|
|
**Extended Market Store Structure**
|
|
```typescript
|
|
interface CartItem {
|
|
product: Product
|
|
quantity: number
|
|
stallId: string
|
|
}
|
|
|
|
interface StallCart {
|
|
id: string
|
|
merchant: string
|
|
products: CartItem[]
|
|
subtotal: number
|
|
shippingZone?: ShippingZone
|
|
}
|
|
|
|
interface Order {
|
|
id: string
|
|
cartId: string
|
|
status: OrderStatus
|
|
contactInfo: ContactInfo
|
|
shippingZone: ShippingZone
|
|
paymentRequest?: string
|
|
createdAt: number
|
|
updatedAt: number
|
|
}
|
|
```
|
|
|
|
#### Component Architecture
|
|
|
|
**New Components to Create**
|
|
1. `ShoppingCart.vue` - Main cart interface
|
|
2. `CartItem.vue` - Individual cart item
|
|
3. `CartSummary.vue` - Cart totals and checkout
|
|
4. `CheckoutPage.vue` - Complete checkout flow
|
|
5. `OrderSummary.vue` - Order review and confirmation
|
|
6. `PaymentModal.vue` - Payment processing interface
|
|
7. `OrdersPage.vue` - Order history and management
|
|
|
|
**Enhanced Existing Components**
|
|
1. `ProductCard.vue` - Add quick add to cart
|
|
2. `Market.vue` - Integrate cart functionality
|
|
3. Header navigation - Add cart icon and count
|
|
|
|
#### Data Flow
|
|
|
|
**Cart Management Flow**
|
|
1. User adds product to cart
|
|
2. Cart state updated in store
|
|
3. Cart persisted to local storage
|
|
4. Cart UI components updated
|
|
5. Real-time sync across components
|
|
|
|
**Checkout Flow**
|
|
1. User initiates checkout from cart
|
|
2. Contact information collected
|
|
3. Shipping zone selected
|
|
4. Order summary displayed
|
|
5. Payment method selected
|
|
6. Order encrypted and sent
|
|
7. Payment processed
|
|
8. Order confirmed
|
|
|
|
#### Integration Points
|
|
|
|
**Existing Systems**
|
|
1. **Authentication**: Integrate with existing auth system
|
|
2. **Nostr Store**: Extend existing Nostr functionality
|
|
3. **Relay Hub**: Use existing relay connections
|
|
4. **Notifications**: Leverage existing notification system
|
|
5. **Storage**: Extend existing storage mechanisms
|
|
|
|
**New Systems**
|
|
1. **Payment Gateway**: Lightning Network integration
|
|
2. **Order Management**: Encrypted order processing
|
|
3. **Cart Persistence**: Local storage with sync
|
|
4. **Real-time Updates**: WebSocket connections
|
|
|
|
### Security Considerations
|
|
|
|
#### Data Encryption
|
|
- All order data encrypted using NIP-04
|
|
- Private keys never stored in plain text
|
|
- Secure communication channels
|
|
- Payment information protection
|
|
|
|
#### Privacy Protection
|
|
- Minimal data collection
|
|
- User consent for data sharing
|
|
- Anonymity options for users
|
|
- Secure storage practices
|
|
|
|
#### Payment Security
|
|
- Lightning Network security
|
|
- Payment verification
|
|
- Fraud prevention measures
|
|
- Secure key management
|
|
|
|
### Performance Considerations
|
|
|
|
#### Optimization Strategies
|
|
- Lazy loading of cart components
|
|
- Efficient state management
|
|
- Minimal re-renders
|
|
- Optimized storage operations
|
|
|
|
#### Scalability
|
|
- Modular component architecture
|
|
- Efficient data structures
|
|
- Caching strategies
|
|
- Performance monitoring
|
|
|
|
### Testing Strategy
|
|
|
|
#### Unit Testing
|
|
- Component functionality
|
|
- Store actions and mutations
|
|
- Utility functions
|
|
- Integration points
|
|
|
|
#### Integration Testing
|
|
- End-to-end checkout flow
|
|
- Payment processing
|
|
- Order management
|
|
- Real-time updates
|
|
|
|
#### User Testing
|
|
- Usability testing
|
|
- Performance testing
|
|
- Security testing
|
|
- Accessibility testing
|
|
|
|
### Deployment and Rollout
|
|
|
|
#### Phase 1 Deployment
|
|
- Enhanced shopping cart
|
|
- Basic checkout functionality
|
|
- Order placement system
|
|
|
|
#### Phase 2 Deployment
|
|
- Payment integration
|
|
- Order tracking
|
|
- Enhanced user experience
|
|
|
|
#### Phase 3 Deployment
|
|
- Advanced features
|
|
- Performance optimizations
|
|
- Full feature set
|
|
|
|
### Success Metrics
|
|
|
|
#### User Experience Metrics
|
|
- Cart abandonment rate
|
|
- Checkout completion rate
|
|
- Time to complete purchase
|
|
- User satisfaction scores
|
|
|
|
#### Technical Metrics
|
|
- Page load times
|
|
- Cart sync performance
|
|
- Order processing speed
|
|
- Error rates
|
|
|
|
#### Business Metrics
|
|
- Conversion rates
|
|
- Average order value
|
|
- Repeat purchase rate
|
|
- Customer retention
|
|
|
|
### Future Enhancements
|
|
|
|
#### Long-term Vision
|
|
- Multi-currency support
|
|
- Advanced analytics
|
|
- AI-powered recommendations
|
|
- Mobile app development
|
|
- API for third-party integrations
|
|
|
|
#### Scalability Plans
|
|
- Microservices architecture
|
|
- Distributed storage
|
|
- Global relay network
|
|
- Cross-platform support
|
|
|
|
### Conclusion
|
|
|
|
This roadmap provides a comprehensive plan for integrating the nostr-market-app purchasing functionality into the web-app. The phased approach ensures core functionality is delivered first while building toward a full-featured e-commerce platform.
|
|
|
|
The integration will maintain the decentralized, Nostr-based architecture while providing a professional, user-friendly shopping experience. Each phase builds upon the previous one, ensuring a smooth development process and consistent user experience.
|
|
|
|
Key success factors include:
|
|
- Maintaining the existing architecture and design patterns
|
|
- Ensuring seamless integration with current systems
|
|
- Prioritizing user experience and performance
|
|
- Implementing robust security measures
|
|
- Creating a scalable and maintainable codebase
|
|
|
|
This roadmap serves as a living document that should be updated as development progresses and new requirements emerge.
|