web-app/docs/Product-Model-Analysis.md
2025-10-20 06:48:21 +02:00

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:

  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

{
  // 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 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

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

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

//  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

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)

  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

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