11 KiB
Product Model Analysis: Nostr Market vs LNbits Integration
Date: 2025-01-27 Project: Ario Web App - Market Module Analysis: Comparison between nostr-market-app reference implementation and current LNbits integration
Executive Summary
This analysis compares the Product data models across three implementations:
- nostr-market-app (JavaScript reference implementation)
- LNbits Nostrmarket API (Python/FastAPI backend)
- Ario Web App (Vue 3/TypeScript frontend)
Key Finding: Critical Nostr-specific fields are missing from our current implementation, which may impact full Nostr marketplace compatibility.
Current Product Model Implementations
1. nostr-market-app (Reference Implementation)
Location: ../nostr-market-app/src/composables/useEvents.js:140-150
{
// Core product data
id: string,
stall_id: string,
name: string,
price: number,
currency: string, // TOP-LEVEL
quantity: number,
images: string[],
categories: string[],
description?: string, // TOP-LEVEL
// Nostr-specific fields
pubkey: string, // CRITICAL: Merchant public key
eventId: string, // CRITICAL: Nostr event ID
relayUrls: string[], // CRITICAL: Source relay URLs
// Processing metadata
stallName: string, // Added during processing
createdAt: number, // Added during processing
formattedPrice?: string // Conditional formatting
}
2. LNbits Nostrmarket API
Location: src/modules/market/services/nostrmarketAPI.ts:71-84
{
id?: string,
stall_id: string,
name: string,
categories: string[],
images: string[],
price: number,
quantity: number,
active: boolean,
pending: boolean,
// NESTED CONFIG STRUCTURE
config: {
description?: string, // NESTED (different from reference)
currency?: string, // NESTED (different from reference)
use_autoreply?: boolean,
autoreply_message?: string,
shipping: ProductShippingCost[]
},
event_id?: string,
event_created_at?: number
}
3. Ario Web App (Current Implementation)
Location: src/modules/market/types/market.ts:29-43
{
id: string,
stall_id: string,
stallName: string,
name: string,
description?: string, // TOP-LEVEL (matches reference)
price: number,
currency: string, // TOP-LEVEL (matches reference)
quantity: number,
images?: string[],
categories?: string[],
createdAt: number,
updatedAt: number,
nostrEventId?: string
}
Critical Discrepancies Analysis
CRITICAL MISSING FIELDS
| Field | nostr-market-app | LNbits API | Ario Web App | Impact Level |
|---|---|---|---|---|
pubkey |
Required | Missing | MISSING | CRITICAL |
eventId |
Required | event_id |
nostrEventId |
HIGH |
relayUrls |
Required | Missing | MISSING | HIGH |
Impact Analysis:
pubkey: Essential for Nostr protocol compliance and merchant identificationeventId: Required for proper event tracking and updatesrelayUrls: Needed for distributed Nostr functionality and relay management
STRUCTURAL DIFFERENCES
| Field | nostr-market-app | LNbits API | Ario Web App | Status |
|---|---|---|---|---|
description |
Top-level | config.description |
Top-level | INCONSISTENT |
currency |
Top-level | config.currency |
Top-level | INCONSISTENT |
active |
Missing | Present | Missing | MEDIUM |
pending |
Missing | Present | Missing | MEDIUM |
TIMESTAMP HANDLING
| Implementation | Created At | Event Created |
|---|---|---|
| nostr-market-app | createdAt (processed) |
|
| LNbits API | event_created_at |
|
| Ario Web App | createdAt, updatedAt |
Processing Flow Comparison
nostr-market-app Processing
graph TD
A[Nostr Event] --> B[Parse Content]
B --> C[Extract Categories from Tags]
C --> D[Add Stall Info]
D --> E[Add Processing Metadata]
E --> F[Final Product Object]
Key Steps:
- Parse Nostr event content (JSON)
- Extract categories from
ttags - Enrich with stall name and merchant info
- Add processing timestamps
- Store in market store
Current Ario Implementation
graph TD
A[LNbits API] --> B[Enrich with Required Fields]
B --> C[Type Conversion]
C --> D[Market Store]
Key Steps:
- Fetch from LNbits API
- Add missing required fields (
stallName,currency, etc.) - Convert to Market Product type
- Store in Pinia store
Compatibility Issues
1. Nostr Protocol Compliance
// CURRENT - Missing critical Nostr fields
const product = await nostrmarketAPI.getProduct(id)
// Missing: pubkey, eventId, relayUrls
// SHOULD BE - Full Nostr compatibility
const product = {
...apiProduct,
pubkey: merchantPubkey, // From merchant context
eventId: apiProduct.event_id, // Map API field
relayUrls: [...relayUrls] // From relay context
}
2. Configuration Mismatch
// CURRENT - Flat structure conflicts with API
interface Product {
currency: string, // Top-level
description?: string // Top-level
}
// vs API expectation:
config: {
currency?: string, // Nested
description?: string // Nested
}
3. Event ID Handling
// Multiple formats across implementations:
event_id // LNbits API format
eventId // nostr-market-app format
nostrEventId // Our current format
Recommended Solutions
Option 1: Unified Product Model (Recommended)
Create a comprehensive model that supports all three implementations:
export interface Product {
// Core LNbits fields
id: string
stall_id: string
name: string
price: number
quantity: number
categories?: string[]
images?: string[]
active: boolean
pending: boolean
// Nostr-specific fields (CRITICAL ADDITIONS)
pubkey: string // ADD: Merchant public key
eventId: string // ADD: Nostr event ID
relayUrls: string[] // ADD: Relay URLs
// Processed fields
stallName: string
description?: string // Top-level (matches nostr-market-app)
currency: string // Top-level (matches nostr-market-app)
createdAt: number
updatedAt: number
// LNbits compatibility (optional)
config?: ProductConfig // For API requests
event_id?: string // LNbits format mapping
event_created_at?: number // LNbits format mapping
nostrEventId?: string // Legacy compatibility
}
Option 2: Type Adapters
Create adapter functions to handle different formats:
// Type adapters for different sources
export const adaptLNbitsToMarket = (
product: LNbitsProduct,
context: { pubkey: string; relayUrls: string[] }
): Product => ({
...product,
pubkey: context.pubkey,
eventId: product.event_id || '',
relayUrls: context.relayUrls,
currency: product.config?.currency || 'sats',
description: product.config?.description,
createdAt: product.event_created_at || Date.now(),
updatedAt: Date.now()
})
export const adaptNostrToMarket = (
product: NostrProduct
): Product => ({
// Direct mapping for nostr-market-app format
...product,
// Additional processing as needed
})
Option 3: Progressive Enhancement
Gradually add missing fields without breaking existing functionality:
// Phase 1: Add critical Nostr fields
export interface Product extends CurrentProduct {
pubkey?: string // Optional for backward compatibility
eventId?: string // Optional for backward compatibility
relayUrls?: string[] // Optional for backward compatibility
}
// Phase 2: Implement field population
// Phase 3: Make fields required
Implementation Priority
Phase 1: Critical Fixes (High Priority)
- Add
pubkeyfield to Product model - Map
event_idtoeventIdconsistently - Add
relayUrlsarray - Update type definitions
Phase 2: Structure Alignment (Medium Priority)
- Implement configuration adapters
- Standardize currency/description placement
- Add active/pending state handling
Phase 3: Full Compatibility (Future)
- Implement complete nostr-market-app compatibility
- Add relay management features
- Implement proper Nostr event handling
Testing Requirements
Unit Tests Needed
describe('Product Model Compatibility', () => {
test('should adapt LNbits API format to unified format', () => {
const lnbitsProduct = { /* LNbits format */ }
const context = { pubkey: 'abc123', relayUrls: ['wss://relay.com'] }
const result = adaptLNbitsToMarket(lnbitsProduct, context)
expect(result.pubkey).toBe('abc123')
expect(result.relayUrls).toContain('wss://relay.com')
expect(result.currency).toBeDefined()
})
test('should maintain backward compatibility', () => {
const currentProduct = { /* Current format */ }
// Should not break existing functionality
expect(() => processProduct(currentProduct)).not.toThrow()
})
})
Integration Tests
- API compatibility with LNbits
- Nostr event processing compatibility
- Market store operations
- UI component rendering
Migration Plan
Immediate Actions
- Document current state (this analysis)
- Update Product interface with optional Nostr fields
- Implement adapter functions
- Add field population in MerchantStore.vue
Short Term (1-2 weeks)
- Make Nostr fields required
- Update all product processing logic
- Add comprehensive tests
- Update documentation
Long Term (1-2 months)
- Full nostr-market-app compatibility
- Advanced Nostr features
- Performance optimization
- Enhanced relay management
Conclusion
The analysis reveals critical gaps in our current Product model that limit full Nostr marketplace compatibility. The missing pubkey, eventId, and relayUrls fields are essential for proper Nostr protocol integration.
Recommended Immediate Action: Implement Option 1 (Unified Product Model) with progressive enhancement to maintain backward compatibility while adding essential Nostr functionality.
Success Criteria:
- Full compatibility with nostr-market-app reference implementation
- Maintained LNbits API integration
- No breaking changes to existing functionality
- Enhanced Nostr marketplace capabilities
Document Version: 1.0 Last Updated: 2025-01-27 Next Review: Before implementing Product model changes