393 lines
No EOL
11 KiB
Markdown
393 lines
No EOL
11 KiB
Markdown
# 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:
|
|
1. **nostr-market-app** (JavaScript reference implementation)
|
|
2. **LNbits Nostrmarket API** (Python/FastAPI backend)
|
|
3. **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`
|
|
|
|
```javascript
|
|
{
|
|
// 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`
|
|
|
|
```typescript
|
|
{
|
|
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`
|
|
|
|
```typescript
|
|
{
|
|
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 identification
|
|
- **`eventId`**: Required for proper event tracking and updates
|
|
- **`relayUrls`**: 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
|
|
```mermaid
|
|
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:**
|
|
1. Parse Nostr event content (JSON)
|
|
2. Extract categories from `t` tags
|
|
3. Enrich with stall name and merchant info
|
|
4. Add processing timestamps
|
|
5. Store in market store
|
|
|
|
### Current Ario Implementation
|
|
```mermaid
|
|
graph TD
|
|
A[LNbits API] --> B[Enrich with Required Fields]
|
|
B --> C[Type Conversion]
|
|
C --> D[Market Store]
|
|
```
|
|
|
|
**Key Steps:**
|
|
1. Fetch from LNbits API
|
|
2. Add missing required fields (`stallName`, `currency`, etc.)
|
|
3. Convert to Market Product type
|
|
4. Store in Pinia store
|
|
|
|
---
|
|
|
|
## Compatibility Issues
|
|
|
|
### 1. **Nostr Protocol Compliance**
|
|
```typescript
|
|
// 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**
|
|
```typescript
|
|
// 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**
|
|
```typescript
|
|
// 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:
|
|
|
|
```typescript
|
|
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:
|
|
|
|
```typescript
|
|
// 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:
|
|
|
|
```typescript
|
|
// 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)
|
|
1. Add `pubkey` field to Product model
|
|
2. Map `event_id` to `eventId` consistently
|
|
3. Add `relayUrls` array
|
|
4. Update type definitions
|
|
|
|
### **Phase 2: Structure Alignment** (Medium Priority)
|
|
1. Implement configuration adapters
|
|
2. Standardize currency/description placement
|
|
3. Add active/pending state handling
|
|
|
|
### **Phase 3: Full Compatibility** (Future)
|
|
1. Implement complete nostr-market-app compatibility
|
|
2. Add relay management features
|
|
3. Implement proper Nostr event handling
|
|
|
|
---
|
|
|
|
## Testing Requirements
|
|
|
|
### Unit Tests Needed
|
|
```typescript
|
|
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
|
|
1. API compatibility with LNbits
|
|
2. Nostr event processing compatibility
|
|
3. Market store operations
|
|
4. UI component rendering
|
|
|
|
---
|
|
|
|
## Migration Plan
|
|
|
|
### **Immediate Actions**
|
|
1. Document current state (this analysis)
|
|
2. Update Product interface with optional Nostr fields
|
|
3. Implement adapter functions
|
|
4. Add field population in MerchantStore.vue
|
|
|
|
### **Short Term** (1-2 weeks)
|
|
1. Make Nostr fields required
|
|
2. Update all product processing logic
|
|
3. Add comprehensive tests
|
|
4. Update documentation
|
|
|
|
### **Long Term** (1-2 months)
|
|
1. Full nostr-market-app compatibility
|
|
2. Advanced Nostr features
|
|
3. Performance optimization
|
|
4. 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 |