# Example: Demand-Driven Planting Complete workflow for responding to demand signals and optimizing production. ## Scenario You're a grower with 500 sqm of growing space. You want to plant what consumers actually need, not just guess. ## Step 1: Set Up Consumer Preferences First, consumers in your region register their preferences: ```typescript // Consumers register their preferences // POST /api/demand/preferences // Consumer A: Family of 4, organic focus const consumerA = { consumerId: 'consumer-001', location: { latitude: 40.7128, longitude: -74.0060, maxDeliveryRadiusKm: 25, city: 'Brooklyn' }, dietaryType: ['vegetarian'], preferredCategories: ['leafy_greens', 'nightshades', 'herbs'], preferredItems: [ { produceType: 'tomato', priority: 'must_have', weeklyQuantity: 3 }, { produceType: 'lettuce', priority: 'preferred', weeklyQuantity: 2 }, { produceType: 'basil', priority: 'nice_to_have', weeklyQuantity: 0.2 } ], certificationPreferences: ['organic', 'local'], freshnessImportance: 5, sustainabilityImportance: 5, householdSize: 4, weeklyBudget: 100 }; // Consumer B: Couple, price-conscious const consumerB = { consumerId: 'consumer-002', location: { latitude: 40.7200, longitude: -74.0100, maxDeliveryRadiusKm: 15, city: 'Brooklyn' }, preferredItems: [ { produceType: 'tomato', priority: 'preferred', weeklyQuantity: 1.5 }, { produceType: 'cucumber', priority: 'must_have', weeklyQuantity: 2 }, { produceType: 'pepper', priority: 'nice_to_have', weeklyQuantity: 1 } ], priceImportance: 5, householdSize: 2, weeklyBudget: 60 }; // Register preferences await fetch('/api/demand/preferences', { method: 'POST', body: JSON.stringify(consumerA) }); await fetch('/api/demand/preferences', { method: 'POST', body: JSON.stringify(consumerB) }); ``` ## Step 2: Generate Demand Signal The system aggregates preferences for your region: ```typescript // POST /api/demand/signal const signalRequest = { centerLat: 40.7150, centerLon: -74.0080, radiusKm: 30, regionName: 'Brooklyn North', season: 'summer' }; const response = await fetch('/api/demand/signal', { method: 'POST', body: JSON.stringify(signalRequest) }); const { data: demandSignal } = await response.json(); console.log(demandSignal); /* { id: 'demand-2024-abc123', region: { name: 'Brooklyn North', radiusKm: 30 }, seasonalPeriod: 'summer', demandItems: [ { produceType: 'tomato', weeklyDemandKg: 180, consumerCount: 95, aggregatePriority: 8, urgency: 'this_week', inSeason: true, matchedSupply: 60, gapKg: 120 // OPPORTUNITY! }, { produceType: 'lettuce', weeklyDemandKg: 120, consumerCount: 72, aggregatePriority: 6, inSeason: false, // Too hot for outdoor lettuce gapKg: 80 }, { produceType: 'cucumber', weeklyDemandKg: 90, gapKg: 45 }, { produceType: 'basil', weeklyDemandKg: 25, gapKg: 25 } ], totalConsumers: 150, totalWeeklyDemandKg: 415, supplyGapKg: 270, supplyStatus: 'shortage' // Opportunity! } */ ``` ## Step 3: Get Planting Recommendations Now, get personalized recommendations for your space: ```typescript // GET /api/demand/recommendations const response = await fetch( '/api/demand/recommendations?' + new URLSearchParams({ growerId: 'grower-001', lat: '40.7100', lon: '-74.0050', deliveryRadiusKm: '40', availableSpaceSqm: '500', season: 'summer' }) ); const { data } = await response.json(); const recommendations = data.recommendations; console.log(recommendations); /* [ { id: 'rec-001', produceType: 'tomato', category: 'nightshades', // What to plant recommendedQuantity: 200, // sqm quantityUnit: 'sqm', expectedYieldKg: 1600, // When plantByDate: '2024-05-15', expectedHarvestStart: '2024-08-01', expectedHarvestEnd: '2024-09-15', growingDays: 80, // Revenue projection projectedDemandKg: 480, // Monthly projectedPricePerKg: 4.50, projectedRevenue: 7200, marketConfidence: 85, // Risks riskFactors: [ { type: 'weather', severity: 'medium', description: 'Single season crop with weather sensitivity', mitigationSuggestion: 'Consider greenhouse for portion' } ], overallRisk: 'medium', // Why this recommendation explanation: 'Based on 3 demand signals showing 120kg weekly gap...' }, { produceType: 'cucumber', recommendedQuantity: 100, expectedYieldKg: 1000, projectedRevenue: 3500, overallRisk: 'low' }, { produceType: 'basil', recommendedQuantity: 50, expectedYieldKg: 100, projectedRevenue: 1500, overallRisk: 'low' } ] */ ``` ## Step 4: Make Planting Decision Review recommendations and decide: ```typescript // Space allocation based on recommendations const plantingPlan = { 'tomato': { sqm: 200, expectedYield: 1600, priority: 'high' }, 'cucumber': { sqm: 100, expectedYield: 1000, priority: 'medium' }, 'basil': { sqm: 50, expectedYield: 100, priority: 'medium' }, // Reserve 150 sqm for crop rotation / next planting 'reserved': { sqm: 150, purpose: 'fall crops' } }; console.log('Total allocated:', 350, 'sqm'); console.log('Expected total yield:', 2700, 'kg'); console.log('Projected revenue:', 12200, 'USD'); ``` ## Step 5: Commit Supply Pre-commit your planned production: ```typescript // POST /api/demand/supply const supplyCommitment = { growerId: 'grower-001', produceType: 'tomato', variety: 'Multiple heirloom', // What you're committing committedQuantityKg: 1600, availableFrom: '2024-08-01', availableUntil: '2024-09-30', // Pricing pricePerKg: 4.50, currency: 'USD', minimumOrderKg: 2, bulkDiscountThreshold: 10, bulkDiscountPercent: 10, // Quality certifications: ['local'], freshnessGuaranteeHours: 24, // Delivery deliveryRadiusKm: 40, deliveryMethods: ['grower_delivery', 'farmers_market', 'customer_pickup'] }; const response = await fetch('/api/demand/supply', { method: 'POST', body: JSON.stringify(supplyCommitment) }); const { data } = await response.json(); console.log('Supply committed:', data.id); console.log('Status:', data.status); // 'available' ``` ## Step 6: Get Matched The system matches supply with demand: ```typescript // System creates matches automatically, or manually: // POST /api/demand/match const match = { demandSignalId: 'demand-2024-abc123', supplyCommitmentId: data.id, consumerId: 'consumer-001', growerId: 'grower-001', produceType: 'tomato', matchedQuantityKg: 3, agreedPricePerKg: 4.50, totalPrice: 13.50, currency: 'USD', deliveryDate: '2024-08-05', deliveryMethod: 'home_delivery', deliveryLocation: { latitude: 40.7128, longitude: -74.0060, address: '123 Main St, Brooklyn' } }; await fetch('/api/demand/match', { method: 'POST', body: JSON.stringify(match) }); ``` ## Step 7: Forecast Future Demand Plan for upcoming seasons: ```typescript // GET /api/demand/forecast const response = await fetch( '/api/demand/forecast?' + new URLSearchParams({ region: 'Brooklyn North', weeks: '12' }) ); const { data: forecast } = await response.json(); console.log(forecast); /* { id: 'forecast-2024-xyz', region: 'Brooklyn North', forecastPeriod: { start: '2024-06-01', end: '2024-08-24' }, forecasts: [ { produceType: 'tomato', predictedDemandKg: 2400, confidence: 80, trend: 'increasing', seasonalFactor: 1.2, factors: [ { name: 'Seasonal peak', type: 'seasonal', impact: 20, description: 'Summer peak for tomatoes' } ] }, { produceType: 'lettuce', predictedDemandKg: 800, trend: 'decreasing', seasonalFactor: 0.6, // Too hot factors: [ { name: 'Heat sensitivity', impact: -40, description: 'Outdoor lettuce struggles in summer' } ] } ] } */ ``` ## Complete Workflow Script ```typescript // demand-driven-workflow.ts import { getDemandForecaster } from '@/lib/demand/forecaster'; async function demandDrivenWorkflow() { const forecaster = getDemandForecaster(); // 1. Register some consumer preferences const consumers = [ createConsumerPreference('consumer-001', [ { produceType: 'tomato', priority: 'must_have', weeklyQuantity: 3 } ]), createConsumerPreference('consumer-002', [ { produceType: 'tomato', priority: 'preferred', weeklyQuantity: 1.5 } ]), // ... more consumers ]; for (const consumer of consumers) { forecaster.registerPreference(consumer); } // 2. Generate demand signal const demandSignal = forecaster.generateDemandSignal( 40.7150, // latitude -74.0080, // longitude 30, // radius km 'Brooklyn North', 'summer' ); console.log('Demand signal generated'); console.log('Total demand:', demandSignal.totalWeeklyDemandKg, 'kg/week'); console.log('Supply gap:', demandSignal.supplyGapKg, 'kg/week'); console.log('Status:', demandSignal.supplyStatus); // 3. Get recommendations for grower const recommendations = forecaster.generatePlantingRecommendations( 'grower-001', 40.7100, // grower lat -74.0050, // grower lon 40, // delivery radius 500, // available sqm 'summer' ); console.log('\nRecommendations:'); for (const rec of recommendations) { console.log(`- ${rec.produceType}: ${rec.recommendedQuantity} sqm`); console.log(` Expected yield: ${rec.expectedYieldKg} kg`); console.log(` Projected revenue: $${rec.projectedRevenue}`); console.log(` Risk: ${rec.overallRisk}`); } // 4. Commit supply const supply = { id: `supply-${Date.now()}`, growerId: 'grower-001', produceType: 'tomato', committedQuantityKg: 1600, availableFrom: new Date(Date.now() + 60 * 24 * 60 * 60 * 1000).toISOString(), availableUntil: new Date(Date.now() + 120 * 24 * 60 * 60 * 1000).toISOString(), pricePerKg: 4.50, currency: 'USD', certifications: ['local'], status: 'available', remainingKg: 1600 }; forecaster.registerSupply(supply); console.log('\nSupply committed:', supply.committedQuantityKg, 'kg'); // 5. Generate updated signal (should show reduced gap) const updatedSignal = forecaster.generateDemandSignal( 40.7150, -74.0080, 30, 'Brooklyn North', 'summer' ); console.log('\nUpdated supply status:', updatedSignal.supplyStatus); console.log('Remaining gap:', updatedSignal.supplyGapKg, 'kg/week'); return { demandSignal, recommendations, supply, updatedSignal }; } // Run workflow demandDrivenWorkflow() .then(result => console.log('\nWorkflow complete!')) .catch(console.error); ``` ## Key Insights ### Why Demand-Driven Works 1. **Reduced waste** - Grow what people want 2. **Better prices** - Pre-commitment secures sales 3. **Lower risk** - Data-driven decisions 4. **Happy consumers** - They get what they need 5. **Sustainability** - Less overproduction ### Best Practices 1. Check demand signals weekly 2. Start with high-demand, low-risk crops 3. Commit supply early for best matching 4. Adjust based on actual results 5. Build relationships with regular consumers