- Add guides: quick-start, installation, configuration, grower, consumer, transport, vertical-farm - Add API references: REST, demand, vertical-farming - Add concepts: blockchain, seasonal-planning, carbon-footprint - Add architecture: data-flow, transport-tracking - Add vertical-farming: environmental-control, automation, integration - Add examples: seed-to-harvest, demand-driven-planting, vertical-farm-setup Completes Agent_5 documentation tasks from AGENT_REPORT.md
11 KiB
11 KiB
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:
// 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:
// 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:
// 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:
// 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:
// 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:
// 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:
// 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
// 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
- Reduced waste - Grow what people want
- Better prices - Pre-commitment secures sales
- Lower risk - Data-driven decisions
- Happy consumers - They get what they need
- Sustainability - Less overproduction
Best Practices
- Check demand signals weekly
- Start with high-demand, low-risk crops
- Commit supply early for best matching
- Adjust based on actual results
- Build relationships with regular consumers