Merge pull request #7 from vespo92/claude/complete-agent-15-tasks-01KKVPGN2dbGFsMSWvt1jHBK
Complete Agent 15 tasks from report
This commit is contained in:
commit
f8824781ff
21 changed files with 8237 additions and 0 deletions
471
docs/api/demand-api.md
Normal file
471
docs/api/demand-api.md
Normal file
|
|
@ -0,0 +1,471 @@
|
||||||
|
# Demand API Reference
|
||||||
|
|
||||||
|
Complete API reference for the LocalGreenChain Demand Forecasting system.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The Demand API enables demand-driven agriculture by:
|
||||||
|
- Capturing consumer preferences
|
||||||
|
- Aggregating regional demand signals
|
||||||
|
- Generating planting recommendations
|
||||||
|
- Matching supply with demand
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Consumer Preferences
|
||||||
|
|
||||||
|
### Register Preferences
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/demand/preferences
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"consumerId": "consumer-123",
|
||||||
|
|
||||||
|
"location": {
|
||||||
|
"latitude": 40.7128,
|
||||||
|
"longitude": -74.0060,
|
||||||
|
"maxDeliveryRadiusKm": 25,
|
||||||
|
"city": "Brooklyn",
|
||||||
|
"region": "New York"
|
||||||
|
},
|
||||||
|
|
||||||
|
"dietaryType": ["vegetarian"],
|
||||||
|
"allergies": ["peanuts"],
|
||||||
|
"dislikes": ["cilantro"],
|
||||||
|
|
||||||
|
"preferredCategories": [
|
||||||
|
"leafy_greens",
|
||||||
|
"herbs",
|
||||||
|
"nightshades"
|
||||||
|
],
|
||||||
|
|
||||||
|
"preferredItems": [
|
||||||
|
{
|
||||||
|
"produceType": "tomato",
|
||||||
|
"category": "nightshades",
|
||||||
|
"priority": "must_have",
|
||||||
|
"weeklyQuantity": 2,
|
||||||
|
"unit": "kg",
|
||||||
|
"seasonalOnly": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"produceType": "basil",
|
||||||
|
"category": "herbs",
|
||||||
|
"priority": "preferred",
|
||||||
|
"weeklyQuantity": 0.1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"certificationPreferences": ["organic", "local"],
|
||||||
|
"freshnessImportance": 5,
|
||||||
|
"priceImportance": 3,
|
||||||
|
"sustainabilityImportance": 5,
|
||||||
|
|
||||||
|
"deliveryPreferences": {
|
||||||
|
"method": ["home_delivery", "farmers_market"],
|
||||||
|
"frequency": "weekly",
|
||||||
|
"preferredDays": ["saturday"]
|
||||||
|
},
|
||||||
|
|
||||||
|
"householdSize": 4,
|
||||||
|
"weeklyBudget": 75,
|
||||||
|
"currency": "USD"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"consumerId": "consumer-123",
|
||||||
|
"createdAt": "2024-06-01T10:00:00Z",
|
||||||
|
"updatedAt": "2024-06-01T10:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Preferences
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/demand/preferences/{consumerId}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Preferences
|
||||||
|
|
||||||
|
```http
|
||||||
|
PUT /api/demand/preferences/{consumerId}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"preferredItems": [...]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Demand Signals
|
||||||
|
|
||||||
|
### Generate Demand Signal
|
||||||
|
|
||||||
|
Aggregate demand for a region:
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/demand/signal
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"centerLat": 40.7128,
|
||||||
|
"centerLon": -74.0060,
|
||||||
|
"radiusKm": 25,
|
||||||
|
"regionName": "Brooklyn",
|
||||||
|
"season": "summer"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"id": "demand-abc123",
|
||||||
|
"timestamp": "2024-06-01T10:00:00Z",
|
||||||
|
|
||||||
|
"region": {
|
||||||
|
"centerLat": 40.7128,
|
||||||
|
"centerLon": -74.0060,
|
||||||
|
"radiusKm": 25,
|
||||||
|
"name": "Brooklyn"
|
||||||
|
},
|
||||||
|
|
||||||
|
"periodStart": "2024-06-01T00:00:00Z",
|
||||||
|
"periodEnd": "2024-06-08T00:00:00Z",
|
||||||
|
"seasonalPeriod": "summer",
|
||||||
|
|
||||||
|
"demandItems": [
|
||||||
|
{
|
||||||
|
"produceType": "tomato",
|
||||||
|
"category": "nightshades",
|
||||||
|
"weeklyDemandKg": 180,
|
||||||
|
"monthlyDemandKg": 720,
|
||||||
|
"consumerCount": 95,
|
||||||
|
"aggregatePriority": 8,
|
||||||
|
"urgency": "this_week",
|
||||||
|
"preferredCertifications": ["organic"],
|
||||||
|
"averageWillingPrice": 4.50,
|
||||||
|
"priceUnit": "per_kg",
|
||||||
|
"inSeason": true,
|
||||||
|
"matchedSupply": 60,
|
||||||
|
"matchedGrowers": 5,
|
||||||
|
"gapKg": 120
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"totalConsumers": 150,
|
||||||
|
"totalWeeklyDemandKg": 450,
|
||||||
|
"confidenceLevel": 85,
|
||||||
|
"currentSupplyKg": 180,
|
||||||
|
"supplyGapKg": 270,
|
||||||
|
"supplyStatus": "shortage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Demand Signal
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/demand/signal/{signalId}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Query Demand Signals
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/demand/signal?lat=40.7128&lon=-74.0060&radius=50&season=summer
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Planting Recommendations
|
||||||
|
|
||||||
|
### Get Recommendations
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/demand/recommendations
|
||||||
|
?growerId=grower-123
|
||||||
|
&lat=40.7128
|
||||||
|
&lon=-74.0060
|
||||||
|
&deliveryRadiusKm=50
|
||||||
|
&availableSpaceSqm=500
|
||||||
|
&season=summer
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"recommendations": [
|
||||||
|
{
|
||||||
|
"id": "rec-abc123",
|
||||||
|
"timestamp": "2024-06-01T10:00:00Z",
|
||||||
|
"growerId": "grower-123",
|
||||||
|
|
||||||
|
"produceType": "tomato",
|
||||||
|
"variety": null,
|
||||||
|
"category": "nightshades",
|
||||||
|
|
||||||
|
"recommendedQuantity": 200,
|
||||||
|
"quantityUnit": "sqm",
|
||||||
|
"expectedYieldKg": 1600,
|
||||||
|
"yieldConfidence": 75,
|
||||||
|
|
||||||
|
"plantByDate": "2024-06-05T00:00:00Z",
|
||||||
|
"expectedHarvestStart": "2024-08-15T00:00:00Z",
|
||||||
|
"expectedHarvestEnd": "2024-09-05T00:00:00Z",
|
||||||
|
"growingDays": 80,
|
||||||
|
|
||||||
|
"projectedDemandKg": 480,
|
||||||
|
"projectedPricePerKg": 4.50,
|
||||||
|
"projectedRevenue": 7200,
|
||||||
|
"marketConfidence": 85,
|
||||||
|
|
||||||
|
"riskFactors": [
|
||||||
|
{
|
||||||
|
"type": "weather",
|
||||||
|
"severity": "medium",
|
||||||
|
"description": "Single season crop with weather sensitivity",
|
||||||
|
"mitigationSuggestion": "Consider greenhouse growing"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"overallRisk": "medium",
|
||||||
|
|
||||||
|
"demandSignalIds": ["demand-abc123"],
|
||||||
|
"explanation": "Based on 1 demand signal showing 120kg weekly gap..."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Demand Forecasts
|
||||||
|
|
||||||
|
### Get Forecast
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/demand/forecast
|
||||||
|
?region=Brooklyn
|
||||||
|
&weeks=12
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"id": "forecast-abc123",
|
||||||
|
"generatedAt": "2024-06-01T10:00:00Z",
|
||||||
|
"region": "Brooklyn",
|
||||||
|
|
||||||
|
"forecastPeriod": {
|
||||||
|
"start": "2024-06-01T00:00:00Z",
|
||||||
|
"end": "2024-08-24T00:00:00Z"
|
||||||
|
},
|
||||||
|
|
||||||
|
"forecasts": [
|
||||||
|
{
|
||||||
|
"produceType": "tomato",
|
||||||
|
"category": "nightshades",
|
||||||
|
"predictedDemandKg": 2400,
|
||||||
|
"confidenceInterval": {
|
||||||
|
"low": 1680,
|
||||||
|
"high": 3120
|
||||||
|
},
|
||||||
|
"confidence": 75,
|
||||||
|
"trend": "increasing",
|
||||||
|
"trendStrength": 65,
|
||||||
|
"seasonalFactor": 1.2,
|
||||||
|
"predictedPricePerKg": 4.50,
|
||||||
|
"factors": [
|
||||||
|
{
|
||||||
|
"name": "Seasonal adjustment",
|
||||||
|
"type": "seasonal",
|
||||||
|
"impact": 20,
|
||||||
|
"description": "In season - higher demand expected"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"modelVersion": "1.0.0",
|
||||||
|
"dataPointsUsed": 45,
|
||||||
|
"lastTrainingDate": "2024-06-01T00:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Supply Commitments
|
||||||
|
|
||||||
|
### Register Supply
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/demand/supply
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"growerId": "grower-123",
|
||||||
|
"produceType": "tomato",
|
||||||
|
"variety": "Cherokee Purple",
|
||||||
|
|
||||||
|
"committedQuantityKg": 400,
|
||||||
|
"availableFrom": "2024-08-01T00:00:00Z",
|
||||||
|
"availableUntil": "2024-09-30T00:00:00Z",
|
||||||
|
|
||||||
|
"pricePerKg": 4.50,
|
||||||
|
"currency": "USD",
|
||||||
|
"minimumOrderKg": 2,
|
||||||
|
"bulkDiscountThreshold": 10,
|
||||||
|
"bulkDiscountPercent": 10,
|
||||||
|
|
||||||
|
"certifications": ["organic"],
|
||||||
|
"freshnessGuaranteeHours": 24,
|
||||||
|
|
||||||
|
"deliveryRadiusKm": 50,
|
||||||
|
"deliveryMethods": ["grower_delivery", "farmers_market"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"id": "supply-abc123",
|
||||||
|
"status": "available",
|
||||||
|
"remainingKg": 400
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Supply Commitment
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/demand/supply/{supplyId}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Supply
|
||||||
|
|
||||||
|
```http
|
||||||
|
PUT /api/demand/supply/{supplyId}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"remainingKg": 350,
|
||||||
|
"status": "partially_committed"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Market Matching
|
||||||
|
|
||||||
|
### Create Match
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/demand/match
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"demandSignalId": "demand-abc123",
|
||||||
|
"supplyCommitmentId": "supply-abc123",
|
||||||
|
"consumerId": "consumer-123",
|
||||||
|
"growerId": "grower-123",
|
||||||
|
|
||||||
|
"produceType": "tomato",
|
||||||
|
"matchedQuantityKg": 2,
|
||||||
|
|
||||||
|
"agreedPricePerKg": 4.50,
|
||||||
|
"totalPrice": 9.00,
|
||||||
|
"currency": "USD",
|
||||||
|
|
||||||
|
"deliveryDate": "2024-08-03T00:00:00Z",
|
||||||
|
"deliveryMethod": "home_delivery",
|
||||||
|
"deliveryLocation": {
|
||||||
|
"latitude": 40.7128,
|
||||||
|
"longitude": -74.0060,
|
||||||
|
"address": "123 Main St, Brooklyn, NY"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"id": "match-abc123",
|
||||||
|
"status": "pending"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Match Status
|
||||||
|
|
||||||
|
```http
|
||||||
|
PUT /api/demand/match/{matchId}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"status": "confirmed"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Enums
|
||||||
|
|
||||||
|
### Priority Levels
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type Priority = 'must_have' | 'preferred' | 'nice_to_have' | 'occasional';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Produce Categories
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type ProduceCategory =
|
||||||
|
| 'leafy_greens' | 'root_vegetables' | 'nightshades'
|
||||||
|
| 'brassicas' | 'alliums' | 'legumes' | 'squash'
|
||||||
|
| 'herbs' | 'microgreens' | 'sprouts' | 'mushrooms'
|
||||||
|
| 'fruits' | 'berries' | 'citrus' | 'tree_fruits'
|
||||||
|
| 'melons' | 'edible_flowers';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Urgency Levels
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type Urgency = 'immediate' | 'this_week' | 'this_month' | 'next_season';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Supply Status
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type SupplyStatus = 'surplus' | 'balanced' | 'shortage' | 'critical';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Match Status
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type MatchStatus = 'pending' | 'confirmed' | 'in_transit' | 'delivered' | 'completed' | 'cancelled';
|
||||||
|
```
|
||||||
314
docs/api/rest-api.md
Normal file
314
docs/api/rest-api.md
Normal file
|
|
@ -0,0 +1,314 @@
|
||||||
|
# REST API Reference
|
||||||
|
|
||||||
|
Complete API reference for LocalGreenChain.
|
||||||
|
|
||||||
|
## Base URL
|
||||||
|
|
||||||
|
```
|
||||||
|
Development: http://localhost:3001/api
|
||||||
|
Production: https://api.localgreenchain.org/api
|
||||||
|
```
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
Most endpoints require authentication via API key or session token:
|
||||||
|
|
||||||
|
```http
|
||||||
|
Authorization: Bearer <your-api-token>
|
||||||
|
```
|
||||||
|
|
||||||
|
Or via cookie for web sessions.
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
All responses follow this structure:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": { ... },
|
||||||
|
"error": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Error responses:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"data": null,
|
||||||
|
"error": {
|
||||||
|
"code": "VALIDATION_ERROR",
|
||||||
|
"message": "Invalid plant ID format"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## HTTP Status Codes
|
||||||
|
|
||||||
|
| Code | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| 200 | Success |
|
||||||
|
| 201 | Created |
|
||||||
|
| 400 | Bad Request |
|
||||||
|
| 401 | Unauthorized |
|
||||||
|
| 403 | Forbidden |
|
||||||
|
| 404 | Not Found |
|
||||||
|
| 500 | Internal Server Error |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Plants API
|
||||||
|
|
||||||
|
### Register Plant
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/plants/register
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"commonName": "Tomato",
|
||||||
|
"scientificName": "Solanum lycopersicum",
|
||||||
|
"location": {
|
||||||
|
"latitude": 40.7128,
|
||||||
|
"longitude": -74.0060,
|
||||||
|
"city": "New York",
|
||||||
|
"country": "USA"
|
||||||
|
},
|
||||||
|
"owner": {
|
||||||
|
"id": "user-123",
|
||||||
|
"name": "John Doe"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"id": "plant-abc123",
|
||||||
|
"blockHash": "0x1234...",
|
||||||
|
"timestamp": "2024-06-01T10:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Clone Plant
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/plants/clone
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"parentPlantId": "plant-abc123",
|
||||||
|
"propagationType": "clone",
|
||||||
|
"newPlant": {
|
||||||
|
"location": { ... },
|
||||||
|
"owner": { ... }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Plant by ID
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/plants/{plantId}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Plant Lineage
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/plants/lineage/{plantId}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Find Nearby Plants
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/plants/nearby?lat=40.7128&lon=-74.0060&radius=50
|
||||||
|
```
|
||||||
|
|
||||||
|
Query Parameters:
|
||||||
|
- `lat` (required): Latitude
|
||||||
|
- `lon` (required): Longitude
|
||||||
|
- `radius` (optional): Search radius in km (default: 50)
|
||||||
|
|
||||||
|
### Search Plants
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/plants/search?q=tomato&type=species
|
||||||
|
```
|
||||||
|
|
||||||
|
Query Parameters:
|
||||||
|
- `q` (required): Search query
|
||||||
|
- `type` (optional): `species`, `location`, `owner`
|
||||||
|
|
||||||
|
### Get Network Statistics
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/plants/network
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"totalPlants": 15234,
|
||||||
|
"chainLength": 15235,
|
||||||
|
"difficulty": 3,
|
||||||
|
"activeGrowers": 892,
|
||||||
|
"countriesRepresented": 45
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Transport API
|
||||||
|
|
||||||
|
See [Transport API Reference](./transport-api.md) for full details.
|
||||||
|
|
||||||
|
### Key Endpoints
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/transport/seed-acquisition
|
||||||
|
POST /api/transport/planting
|
||||||
|
POST /api/transport/growing
|
||||||
|
POST /api/transport/harvest
|
||||||
|
POST /api/transport/distribution
|
||||||
|
POST /api/transport/seed-saving
|
||||||
|
POST /api/transport/seed-sharing
|
||||||
|
|
||||||
|
GET /api/transport/journey/{plantId}
|
||||||
|
GET /api/transport/footprint/{userId}
|
||||||
|
GET /api/transport/verify/{blockHash}
|
||||||
|
GET /api/transport/qr/{id}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Demand API
|
||||||
|
|
||||||
|
See [Demand API Reference](./demand-api.md) for full details.
|
||||||
|
|
||||||
|
### Key Endpoints
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/demand/preferences
|
||||||
|
GET /api/demand/preferences/{consumerId}
|
||||||
|
POST /api/demand/signal
|
||||||
|
GET /api/demand/recommendations
|
||||||
|
GET /api/demand/forecast
|
||||||
|
POST /api/demand/supply
|
||||||
|
POST /api/demand/match
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Vertical Farming API
|
||||||
|
|
||||||
|
See [Vertical Farming API Reference](./vertical-farming-api.md) for full details.
|
||||||
|
|
||||||
|
### Key Endpoints
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/vertical-farm/register
|
||||||
|
GET /api/vertical-farm/{farmId}
|
||||||
|
GET /api/vertical-farm/{farmId}/zones
|
||||||
|
POST /api/vertical-farm/{farmId}/zones
|
||||||
|
GET /api/vertical-farm/{farmId}/analytics
|
||||||
|
|
||||||
|
POST /api/vertical-farm/batch/start
|
||||||
|
GET /api/vertical-farm/batch/{batchId}
|
||||||
|
PUT /api/vertical-farm/batch/{batchId}/environment
|
||||||
|
POST /api/vertical-farm/batch/{batchId}/harvest
|
||||||
|
|
||||||
|
GET /api/vertical-farm/recipes
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error Codes
|
||||||
|
|
||||||
|
| Code | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `VALIDATION_ERROR` | Input validation failed |
|
||||||
|
| `NOT_FOUND` | Resource not found |
|
||||||
|
| `UNAUTHORIZED` | Authentication required |
|
||||||
|
| `FORBIDDEN` | Insufficient permissions |
|
||||||
|
| `CHAIN_ERROR` | Blockchain operation failed |
|
||||||
|
| `DUPLICATE` | Resource already exists |
|
||||||
|
| `RATE_LIMITED` | Too many requests |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
Default limits:
|
||||||
|
- 100 requests per minute per IP
|
||||||
|
- 1000 requests per hour per user
|
||||||
|
|
||||||
|
Headers returned:
|
||||||
|
```http
|
||||||
|
X-RateLimit-Limit: 100
|
||||||
|
X-RateLimit-Remaining: 95
|
||||||
|
X-RateLimit-Reset: 1625097600
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pagination
|
||||||
|
|
||||||
|
List endpoints support pagination:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/plants/search?q=tomato&page=1&limit=20
|
||||||
|
```
|
||||||
|
|
||||||
|
Response includes:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": [...],
|
||||||
|
"pagination": {
|
||||||
|
"page": 1,
|
||||||
|
"limit": 20,
|
||||||
|
"total": 150,
|
||||||
|
"totalPages": 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Webhooks
|
||||||
|
|
||||||
|
Register webhooks for events:
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/webhooks
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"url": "https://yourdomain.com/webhook",
|
||||||
|
"events": ["plant.registered", "transport.completed"],
|
||||||
|
"secret": "your-webhook-secret"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Webhook payload:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"event": "plant.registered",
|
||||||
|
"timestamp": "2024-06-01T10:00:00Z",
|
||||||
|
"data": {
|
||||||
|
"plantId": "plant-abc123",
|
||||||
|
"commonName": "Tomato"
|
||||||
|
},
|
||||||
|
"signature": "sha256=..."
|
||||||
|
}
|
||||||
|
```
|
||||||
523
docs/api/vertical-farming-api.md
Normal file
523
docs/api/vertical-farming-api.md
Normal file
|
|
@ -0,0 +1,523 @@
|
||||||
|
# Vertical Farming API Reference
|
||||||
|
|
||||||
|
Complete API reference for the LocalGreenChain Vertical Farming system.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The Vertical Farming API enables:
|
||||||
|
- Farm registration and management
|
||||||
|
- Zone configuration and monitoring
|
||||||
|
- Crop batch lifecycle management
|
||||||
|
- Environment tracking and alerts
|
||||||
|
- Analytics and reporting
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Farm Management
|
||||||
|
|
||||||
|
### Register Farm
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/vertical-farm/register
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Urban Greens VF",
|
||||||
|
"ownerId": "owner-123",
|
||||||
|
|
||||||
|
"location": {
|
||||||
|
"latitude": 40.7128,
|
||||||
|
"longitude": -74.0060,
|
||||||
|
"address": "123 Industrial Blvd",
|
||||||
|
"city": "Brooklyn",
|
||||||
|
"country": "USA",
|
||||||
|
"timezone": "America/New_York"
|
||||||
|
},
|
||||||
|
|
||||||
|
"specs": {
|
||||||
|
"totalAreaSqm": 500,
|
||||||
|
"growingAreaSqm": 400,
|
||||||
|
"numberOfLevels": 4,
|
||||||
|
"ceilingHeightM": 4,
|
||||||
|
"totalGrowingPositions": 5000,
|
||||||
|
"currentActivePlants": 0,
|
||||||
|
"powerCapacityKw": 150,
|
||||||
|
"waterStorageL": 10000,
|
||||||
|
"backupPowerHours": 24,
|
||||||
|
"certifications": ["gap", "local_food_safety"],
|
||||||
|
"buildingType": "warehouse",
|
||||||
|
"insulation": "high_efficiency"
|
||||||
|
},
|
||||||
|
|
||||||
|
"automationLevel": "semi_automated"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"id": "farm-abc123",
|
||||||
|
"name": "Urban Greens VF",
|
||||||
|
"status": "operational",
|
||||||
|
"createdAt": "2024-06-01T10:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Farm
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/vertical-farm/{farmId}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Farm
|
||||||
|
|
||||||
|
```http
|
||||||
|
PUT /api/vertical-farm/{farmId}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"status": "maintenance",
|
||||||
|
"specs": {
|
||||||
|
"currentActivePlants": 4500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### List User Farms
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/vertical-farm?ownerId=owner-123
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Zone Management
|
||||||
|
|
||||||
|
### Create Zone
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/vertical-farm/{farmId}/zones
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Zone A - Leafy Greens",
|
||||||
|
"level": 1,
|
||||||
|
"areaSqm": 100,
|
||||||
|
"lengthM": 20,
|
||||||
|
"widthM": 5,
|
||||||
|
"growingMethod": "NFT",
|
||||||
|
"plantPositions": 1200,
|
||||||
|
|
||||||
|
"environmentTargets": {
|
||||||
|
"temperatureC": { "min": 18, "max": 24, "target": 21 },
|
||||||
|
"humidityPercent": { "min": 55, "max": 75, "target": 65 },
|
||||||
|
"co2Ppm": { "min": 800, "max": 1400, "target": 1000 },
|
||||||
|
"lightPpfd": { "min": 200, "max": 400, "target": 300 },
|
||||||
|
"lightHours": 16,
|
||||||
|
"nutrientEc": { "min": 1.2, "max": 1.8, "target": 1.5 },
|
||||||
|
"nutrientPh": { "min": 5.5, "max": 6.5, "target": 6.0 },
|
||||||
|
"waterTempC": { "min": 18, "max": 22, "target": 20 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"id": "zone-abc123",
|
||||||
|
"name": "Zone A - Leafy Greens",
|
||||||
|
"status": "empty"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Zones
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/vertical-farm/{farmId}/zones
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Zone Details
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/vertical-farm/{farmId}/zones/{zoneId}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Zone
|
||||||
|
|
||||||
|
```http
|
||||||
|
PUT /api/vertical-farm/{farmId}/zones/{zoneId}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"status": "preparing",
|
||||||
|
"environmentTargets": { ... }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Growing Recipes
|
||||||
|
|
||||||
|
### List Recipes
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/vertical-farm/recipes
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": "recipe-lettuce-butterhead",
|
||||||
|
"name": "Butterhead Lettuce - Fast Cycle",
|
||||||
|
"cropType": "lettuce",
|
||||||
|
"variety": "butterhead",
|
||||||
|
"version": "1.0",
|
||||||
|
"expectedDays": 35,
|
||||||
|
"expectedYieldGrams": 180,
|
||||||
|
"expectedYieldPerSqm": 4000,
|
||||||
|
"requirements": {
|
||||||
|
"positions": 1,
|
||||||
|
"zoneType": "NFT",
|
||||||
|
"minimumPpfd": 200,
|
||||||
|
"idealTemperatureC": 21
|
||||||
|
},
|
||||||
|
"source": "internal",
|
||||||
|
"rating": 4.5,
|
||||||
|
"timesUsed": 156
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Recipe Details
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/vertical-farm/recipes/{recipeId}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response includes full stage definitions:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"id": "recipe-lettuce-butterhead",
|
||||||
|
"stages": [
|
||||||
|
{
|
||||||
|
"name": "Germination",
|
||||||
|
"daysStart": 0,
|
||||||
|
"daysEnd": 3,
|
||||||
|
"temperature": { "day": 20, "night": 18 },
|
||||||
|
"humidity": { "day": 80, "night": 85 },
|
||||||
|
"co2Ppm": 800,
|
||||||
|
"lightHours": 18,
|
||||||
|
"lightPpfd": 150,
|
||||||
|
"nutrientRecipeId": "nutrient-seedling",
|
||||||
|
"targetEc": 0.8,
|
||||||
|
"targetPh": 6.0,
|
||||||
|
"actions": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add Custom Recipe
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/vertical-farm/recipes
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Custom Lettuce - High Yield",
|
||||||
|
"cropType": "lettuce",
|
||||||
|
"variety": "romaine",
|
||||||
|
"stages": [ ... ],
|
||||||
|
"expectedDays": 42,
|
||||||
|
"expectedYieldGrams": 220
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Crop Batches
|
||||||
|
|
||||||
|
### Start Batch
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/vertical-farm/batch/start
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"farmId": "farm-abc123",
|
||||||
|
"zoneId": "zone-abc123",
|
||||||
|
"recipeId": "recipe-lettuce-butterhead",
|
||||||
|
"seedBatchId": "seeds-lettuce-001",
|
||||||
|
"plantCount": 200
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"id": "batch-abc123",
|
||||||
|
"farmId": "farm-abc123",
|
||||||
|
"zoneId": "zone-abc123",
|
||||||
|
"cropType": "lettuce",
|
||||||
|
"plantCount": 200,
|
||||||
|
"plantingDate": "2024-06-01T10:00:00Z",
|
||||||
|
"expectedHarvestDate": "2024-07-06T10:00:00Z",
|
||||||
|
"expectedYieldKg": 36,
|
||||||
|
"currentStage": "Germination",
|
||||||
|
"currentDay": 0,
|
||||||
|
"healthScore": 100,
|
||||||
|
"status": "germinating",
|
||||||
|
"plantIds": ["batch-abc123-plant-0", "..."]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Batch
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/vertical-farm/batch/{batchId}
|
||||||
|
```
|
||||||
|
|
||||||
|
### List Batches
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/vertical-farm/batch?farmId=farm-abc123&status=growing
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Batch Progress
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/vertical-farm/batch/{batchId}/progress
|
||||||
|
```
|
||||||
|
|
||||||
|
This recalculates current day, stage, and updates environment targets.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Environment Tracking
|
||||||
|
|
||||||
|
### Record Environment
|
||||||
|
|
||||||
|
```http
|
||||||
|
PUT /api/vertical-farm/batch/{batchId}/environment
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"timestamp": "2024-06-15T12:00:00Z",
|
||||||
|
"temperatureC": 21.5,
|
||||||
|
"humidityPercent": 68,
|
||||||
|
"co2Ppm": 1050,
|
||||||
|
"vpd": 0.85,
|
||||||
|
"ppfd": 295,
|
||||||
|
"dli": 17.0,
|
||||||
|
"waterTempC": 19.5,
|
||||||
|
"ec": 1.55,
|
||||||
|
"ph": 6.1,
|
||||||
|
"dissolvedOxygenPpm": 8.2,
|
||||||
|
"airflowMs": 0.5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response includes any triggered alerts:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"recorded": true,
|
||||||
|
"alerts": [
|
||||||
|
{
|
||||||
|
"parameter": "temperature",
|
||||||
|
"type": "high",
|
||||||
|
"value": 21.5,
|
||||||
|
"threshold": 21,
|
||||||
|
"timestamp": "2024-06-15T12:00:00Z",
|
||||||
|
"acknowledged": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"healthScore": 99
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Environment History
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/vertical-farm/batch/{batchId}/environment
|
||||||
|
?from=2024-06-01T00:00:00Z
|
||||||
|
&to=2024-06-15T00:00:00Z
|
||||||
|
```
|
||||||
|
|
||||||
|
### Acknowledge Alert
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/vertical-farm/batch/{batchId}/alerts/{alertId}/acknowledge
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Harvest
|
||||||
|
|
||||||
|
### Complete Harvest
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/vertical-farm/batch/{batchId}/harvest
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"actualYieldKg": 38.5,
|
||||||
|
"qualityGrade": "A",
|
||||||
|
"notes": "Excellent crop, exceeded expectations"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"batchId": "batch-abc123",
|
||||||
|
"status": "completed",
|
||||||
|
"actualYieldKg": 38.5,
|
||||||
|
"expectedYieldKg": 36,
|
||||||
|
"yieldVariance": 6.9,
|
||||||
|
"qualityGrade": "A",
|
||||||
|
"actualHarvestDate": "2024-07-06T14:00:00Z",
|
||||||
|
"cycleLength": 35
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Analytics
|
||||||
|
|
||||||
|
### Get Farm Analytics
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/vertical-farm/{farmId}/analytics?period=30
|
||||||
|
```
|
||||||
|
|
||||||
|
Query Parameters:
|
||||||
|
- `period`: Number of days to analyze (default: 30)
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"farmId": "farm-abc123",
|
||||||
|
"generatedAt": "2024-07-01T10:00:00Z",
|
||||||
|
"period": "30 days",
|
||||||
|
|
||||||
|
"production": {
|
||||||
|
"totalYieldKg": 450.5,
|
||||||
|
"yieldPerSqmPerYear": 4107.5,
|
||||||
|
"cropCyclesCompleted": 12,
|
||||||
|
"averageCyclesDays": 28.5
|
||||||
|
},
|
||||||
|
|
||||||
|
"quality": {
|
||||||
|
"averageQualityScore": 92.3,
|
||||||
|
"gradeAPercent": 85,
|
||||||
|
"wastagePercent": 4.5
|
||||||
|
},
|
||||||
|
|
||||||
|
"efficiency": {
|
||||||
|
"cropSuccessRate": 98,
|
||||||
|
"spaceUtilization": 88,
|
||||||
|
"laborHoursPerKg": 0.3
|
||||||
|
},
|
||||||
|
|
||||||
|
"financial": {
|
||||||
|
"revenueUsd": 9010,
|
||||||
|
"costUsd": 4505,
|
||||||
|
"profitMarginPercent": 50,
|
||||||
|
"revenuePerSqm": 22.53
|
||||||
|
},
|
||||||
|
|
||||||
|
"environmental": {
|
||||||
|
"carbonFootprintKgPerKg": 0.28,
|
||||||
|
"waterUseLPerKg": 4.5,
|
||||||
|
"energyUseKwhPerKg": 15.2
|
||||||
|
},
|
||||||
|
|
||||||
|
"topCropsByYield": [
|
||||||
|
{ "crop": "lettuce", "yieldKg": 250.2 },
|
||||||
|
{ "crop": "basil", "yieldKg": 120.5 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"topCropsByRevenue": [
|
||||||
|
{ "crop": "basil", "revenueUsd": 4820 },
|
||||||
|
{ "crop": "lettuce", "revenueUsd": 3750 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"topCropsByEfficiency": [
|
||||||
|
{ "crop": "microgreens", "efficiencyScore": 95 },
|
||||||
|
{ "crop": "lettuce", "efficiencyScore": 92 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Enums
|
||||||
|
|
||||||
|
### Farm Status
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type FarmStatus = 'offline' | 'starting' | 'operational' | 'maintenance' | 'emergency';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Zone Status
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type ZoneStatus = 'empty' | 'preparing' | 'planted' | 'growing' | 'harvesting' | 'cleaning';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Growing Method
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type GrowingMethod = 'NFT' | 'DWC' | 'ebb_flow' | 'aeroponics' | 'vertical_towers' | 'rack_system';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Batch Status
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type BatchStatus = 'germinating' | 'growing' | 'ready' | 'harvesting' | 'completed' | 'failed';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alert Type
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type AlertType = 'low' | 'high' | 'critical_low' | 'critical_high' | 'sensor_fault';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Quality Grade
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type QualityGrade = 'A' | 'B' | 'C' | 'processing';
|
||||||
|
```
|
||||||
369
docs/architecture/data-flow.md
Normal file
369
docs/architecture/data-flow.md
Normal file
|
|
@ -0,0 +1,369 @@
|
||||||
|
# Data Flow Architecture
|
||||||
|
|
||||||
|
Understanding how data flows through the LocalGreenChain system.
|
||||||
|
|
||||||
|
## System Overview
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ LOCALGREENCHAIN DATA FLOW │
|
||||||
|
├─────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ INPUTS PROCESSING OUTPUTS │
|
||||||
|
│ ────── ────────── ─────── │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────┐ ┌─────────────┐ ┌──────────┐ │
|
||||||
|
│ │Consumer │──preferences─│ Demand │──signals───→│ Planting │ │
|
||||||
|
│ │Prefs │ │ Forecaster │ │Recommends│ │
|
||||||
|
│ └─────────┘ └─────────────┘ └──────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌─────────┐ ┌──────▼──────┐ ┌──────────┐ │
|
||||||
|
│ │Transport│──events─────→│ Transport │──journeys──→│ QR │ │
|
||||||
|
│ │Events │ │ Chain │ │ Codes │ │
|
||||||
|
│ └─────────┘ └─────────────┘ └──────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌─────────┐ ┌──────▼──────┐ ┌──────────┐ │
|
||||||
|
│ │Vertical │──readings───→│ VF │──analytics─→│Dashboard │ │
|
||||||
|
│ │Farm IoT │ │ Controller │ │ │ │
|
||||||
|
│ └─────────┘ └─────────────┘ └──────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌──────▼──────┐ │
|
||||||
|
│ │ Plant │ │
|
||||||
|
│ │ Blockchain │ │
|
||||||
|
│ └─────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌──────▼──────┐ │
|
||||||
|
│ │ JSON/DB │ │
|
||||||
|
│ │ Storage │ │
|
||||||
|
│ └─────────────┘ │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Flow Patterns
|
||||||
|
|
||||||
|
### 1. Consumer Preference Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
Consumer → Web UI → API → DemandForecaster → Storage
|
||||||
|
│ │
|
||||||
|
│ ▼
|
||||||
|
│ Aggregation
|
||||||
|
│ │
|
||||||
|
│ ▼
|
||||||
|
└────────────────── Demand Signal
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Planting Recommendations
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Grower Dashboard
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Transport Event Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
Grower/Transporter
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
API Request
|
||||||
|
│
|
||||||
|
├──→ Validation
|
||||||
|
│
|
||||||
|
├──→ Distance Calculation (Haversine)
|
||||||
|
│
|
||||||
|
├──→ Carbon Calculation
|
||||||
|
│
|
||||||
|
├──→ TransportChain.recordEvent()
|
||||||
|
│ │
|
||||||
|
│ ├──→ Create Block
|
||||||
|
│ ├──→ Mine Block (PoW)
|
||||||
|
│ ├──→ Add to Chain
|
||||||
|
│ └──→ Index Event
|
||||||
|
│
|
||||||
|
└──→ Response with Block Hash
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Vertical Farm Data Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
IoT Sensors
|
||||||
|
│
|
||||||
|
├──→ Temperature
|
||||||
|
├──→ Humidity
|
||||||
|
├──→ CO2
|
||||||
|
├──→ Light
|
||||||
|
├──→ EC/pH
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
API Endpoint (/api/vertical-farm/batch/{id}/environment)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
VerticalFarmController.recordEnvironment()
|
||||||
|
│
|
||||||
|
├──→ Compare to Targets
|
||||||
|
│ │
|
||||||
|
│ ▼
|
||||||
|
│ Generate Alerts (if out of range)
|
||||||
|
│
|
||||||
|
├──→ Update Batch Health Score
|
||||||
|
│
|
||||||
|
└──→ Store in Environment Log
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Analytics Generation
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Transformations
|
||||||
|
|
||||||
|
### Preference → Demand Signal
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Input: Individual preferences
|
||||||
|
const preferences: ConsumerPreference[] = [
|
||||||
|
{ consumerId: "A", preferredItems: [{ produceType: "tomato", weeklyQuantity: 2 }] },
|
||||||
|
{ consumerId: "B", preferredItems: [{ produceType: "tomato", weeklyQuantity: 1 }] },
|
||||||
|
{ consumerId: "C", preferredItems: [{ produceType: "tomato", weeklyQuantity: 3 }] }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Transformation: Aggregate by region
|
||||||
|
// Output: Demand Signal
|
||||||
|
const signal: DemandSignal = {
|
||||||
|
region: { name: "Brooklyn", radiusKm: 25 },
|
||||||
|
demandItems: [
|
||||||
|
{
|
||||||
|
produceType: "tomato",
|
||||||
|
weeklyDemandKg: 6, // Sum of individual demands
|
||||||
|
consumerCount: 3,
|
||||||
|
aggregatePriority: 8.5 // Weighted average
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Transport Events → Plant Journey
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Input: Individual events
|
||||||
|
const events: TransportEvent[] = [
|
||||||
|
{ eventType: "seed_acquisition", plantId: "P1", distanceKm: 50 },
|
||||||
|
{ eventType: "planting", plantId: "P1", distanceKm: 0 },
|
||||||
|
{ eventType: "growing_transport", plantId: "P1", distanceKm: 5 },
|
||||||
|
{ eventType: "harvest", plantId: "P1", distanceKm: 0 },
|
||||||
|
{ eventType: "distribution", plantId: "P1", distanceKm: 20 }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Transformation: Aggregate for plant
|
||||||
|
// Output: Plant Journey
|
||||||
|
const journey: PlantJourney = {
|
||||||
|
plantId: "P1",
|
||||||
|
events: events,
|
||||||
|
totalFoodMiles: 75, // Sum of distances
|
||||||
|
totalCarbonKg: 3.5, // Sum of carbon
|
||||||
|
currentStage: "post_harvest"
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Storage Architecture
|
||||||
|
|
||||||
|
### File-Based Storage (Default)
|
||||||
|
|
||||||
|
```
|
||||||
|
data/
|
||||||
|
├── plantchain.json # Main plant blockchain
|
||||||
|
│ └── { difficulty, chain: Block[] }
|
||||||
|
│
|
||||||
|
├── transport.json # Transport chain
|
||||||
|
│ └── { difficulty, chain: TransportBlock[] }
|
||||||
|
│
|
||||||
|
├── demand.json # Demand data
|
||||||
|
│ └── {
|
||||||
|
│ preferences: Map<id, Preference>,
|
||||||
|
│ signals: Map<id, Signal>,
|
||||||
|
│ supply: Map<id, Supply>,
|
||||||
|
│ matches: Map<id, Match>
|
||||||
|
│ }
|
||||||
|
│
|
||||||
|
└── vertical-farms.json # VF data
|
||||||
|
└── {
|
||||||
|
farms: Map<id, Farm>,
|
||||||
|
recipes: Map<id, Recipe>,
|
||||||
|
batches: Map<id, Batch>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Storage (Production)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- PostgreSQL schema (conceptual)
|
||||||
|
|
||||||
|
CREATE TABLE blocks (
|
||||||
|
index INTEGER PRIMARY KEY,
|
||||||
|
timestamp TIMESTAMPTZ,
|
||||||
|
data JSONB,
|
||||||
|
previous_hash VARCHAR(64),
|
||||||
|
hash VARCHAR(64),
|
||||||
|
nonce INTEGER
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE plants (
|
||||||
|
id VARCHAR(36) PRIMARY KEY,
|
||||||
|
common_name VARCHAR(255),
|
||||||
|
scientific_name VARCHAR(255),
|
||||||
|
location GEOGRAPHY(POINT),
|
||||||
|
owner_id VARCHAR(36),
|
||||||
|
generation INTEGER,
|
||||||
|
parent_id VARCHAR(36),
|
||||||
|
block_index INTEGER REFERENCES blocks(index)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE transport_events (
|
||||||
|
id VARCHAR(36) PRIMARY KEY,
|
||||||
|
event_type VARCHAR(50),
|
||||||
|
plant_ids VARCHAR(36)[],
|
||||||
|
from_location GEOGRAPHY(POINT),
|
||||||
|
to_location GEOGRAPHY(POINT),
|
||||||
|
distance_km DECIMAL,
|
||||||
|
carbon_kg DECIMAL,
|
||||||
|
block_index INTEGER
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Caching Strategy
|
||||||
|
|
||||||
|
### Cache Layers
|
||||||
|
|
||||||
|
```
|
||||||
|
Request
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────┐
|
||||||
|
│ API Response │ TTL: 60s (dynamic data)
|
||||||
|
│ Cache │ TTL: 3600s (static data)
|
||||||
|
└────────┬────────┘
|
||||||
|
│ miss
|
||||||
|
▼
|
||||||
|
┌─────────────────┐
|
||||||
|
│ Query Cache │ Pre-computed queries
|
||||||
|
│ (Redis) │ Hot data in memory
|
||||||
|
└────────┬────────┘
|
||||||
|
│ miss
|
||||||
|
▼
|
||||||
|
┌─────────────────┐
|
||||||
|
│ Data Store │ JSON files or Database
|
||||||
|
│ │
|
||||||
|
└─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cached Data
|
||||||
|
|
||||||
|
| Data Type | Cache TTL | Reason |
|
||||||
|
|-----------|-----------|--------|
|
||||||
|
| Plant details | 1 hour | Rarely changes |
|
||||||
|
| Transport journey | 5 minutes | Updates on events |
|
||||||
|
| Demand signals | 1 hour | Recalculated periodically |
|
||||||
|
| Farm analytics | 15 minutes | Computed from batches |
|
||||||
|
| Recipes | 24 hours | Static data |
|
||||||
|
|
||||||
|
## Event-Driven Updates
|
||||||
|
|
||||||
|
### Event Types
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type SystemEvent =
|
||||||
|
| { type: "plant.registered"; plantId: string }
|
||||||
|
| { type: "transport.recorded"; blockHash: string }
|
||||||
|
| { type: "batch.started"; batchId: string }
|
||||||
|
| { type: "alert.triggered"; zoneId: string; alert: EnvironmentAlert }
|
||||||
|
| { type: "harvest.completed"; batchId: string }
|
||||||
|
| { type: "supply.matched"; matchId: string };
|
||||||
|
```
|
||||||
|
|
||||||
|
### Event Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
Event Source → Event Bus → Event Handlers
|
||||||
|
│
|
||||||
|
├──→ Cache Invalidation
|
||||||
|
├──→ Webhook Dispatch
|
||||||
|
├──→ Real-time UI Update
|
||||||
|
└──→ Analytics Update
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Data Flow
|
||||||
|
|
||||||
|
### Request Lifecycle
|
||||||
|
|
||||||
|
```
|
||||||
|
Client Request
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────┐
|
||||||
|
│ Router │ Match endpoint
|
||||||
|
└──────┬──────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────┐
|
||||||
|
│ Middleware │ Auth, validation, logging
|
||||||
|
└──────┬──────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────┐
|
||||||
|
│ Handler │ Business logic
|
||||||
|
└──────┬──────┘
|
||||||
|
│
|
||||||
|
├──→ Service Layer (Forecaster, Controller, Chain)
|
||||||
|
│
|
||||||
|
├──→ Data Layer (Storage, Cache)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────┐
|
||||||
|
│ Response │ Format JSON, headers
|
||||||
|
└──────┬──────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Client Response
|
||||||
|
```
|
||||||
|
|
||||||
|
## Real-Time Data
|
||||||
|
|
||||||
|
### WebSocket Connections
|
||||||
|
|
||||||
|
```
|
||||||
|
Client ←──WebSocket──→ Server
|
||||||
|
│
|
||||||
|
├── Environment readings
|
||||||
|
├── Alert notifications
|
||||||
|
├── Batch progress updates
|
||||||
|
└── Demand signal changes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Polling Fallback
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// If WebSocket unavailable
|
||||||
|
const POLL_INTERVALS = {
|
||||||
|
environment: 30_000, // 30 seconds
|
||||||
|
batchProgress: 60_000, // 1 minute
|
||||||
|
demandSignals: 300_000, // 5 minutes
|
||||||
|
analytics: 900_000 // 15 minutes
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Integrity
|
||||||
|
|
||||||
|
### Validation Points
|
||||||
|
|
||||||
|
1. **API Input** - Schema validation (JSON Schema/Zod)
|
||||||
|
2. **Business Logic** - Domain rules enforcement
|
||||||
|
3. **Blockchain** - Hash verification
|
||||||
|
4. **Storage** - Type checking
|
||||||
|
|
||||||
|
### Consistency Guarantees
|
||||||
|
|
||||||
|
| Operation | Guarantee |
|
||||||
|
|-----------|-----------|
|
||||||
|
| Block creation | Atomic (single file write) |
|
||||||
|
| Batch operations | Transaction-like (rollback on error) |
|
||||||
|
| Cross-chain refs | Eventually consistent |
|
||||||
|
| Cache updates | Best effort (can stale) |
|
||||||
489
docs/architecture/transport-tracking.md
Normal file
489
docs/architecture/transport-tracking.md
Normal file
|
|
@ -0,0 +1,489 @@
|
||||||
|
# Transport Tracking Architecture
|
||||||
|
|
||||||
|
Deep dive into the seed-to-seed transport tracking system.
|
||||||
|
|
||||||
|
## Architecture Overview
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ TRANSPORT TRACKING SYSTEM │
|
||||||
|
├─────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ TRANSPORT CHAIN │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
|
||||||
|
│ │ │Genesis │→ │ Block 1 │→ │ Block 2 │→ │ Block N │ │ │
|
||||||
|
│ │ │ │ │ Seed │ │ Plant │ │ Harvest │ │ │
|
||||||
|
│ │ │ │ │ Acquire │ │ │ │ │ │ │
|
||||||
|
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ └─────────────────────────────────────────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌──────────────────┼──────────────────┐ │
|
||||||
|
│ ▼ ▼ ▼ │
|
||||||
|
│ ┌────────────────┐ ┌──────────────┐ ┌───────────────┐ │
|
||||||
|
│ │ Event Index │ │ Plant Index │ │ Batch Index │ │
|
||||||
|
│ │ (by event ID) │ │ (by plant ID)│ │ (by batch ID) │ │
|
||||||
|
│ └────────────────┘ └──────────────┘ └───────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ SERVICES │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
|
||||||
|
│ │ │Distance │ │ Carbon │ │ QR │ │ Journey │ │ │
|
||||||
|
│ │ │Calculator│ │Calculator│ │Generator│ │ Builder │ │ │
|
||||||
|
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ └─────────────────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## TransportChain Class
|
||||||
|
|
||||||
|
### Core Structure
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class TransportChain {
|
||||||
|
// Blockchain data
|
||||||
|
public chain: TransportBlock[];
|
||||||
|
public difficulty: number;
|
||||||
|
|
||||||
|
// Indexes for fast lookups
|
||||||
|
private eventIndex: Map<string, TransportBlock[]>;
|
||||||
|
private plantEvents: Map<string, TransportEvent[]>;
|
||||||
|
private batchEvents: Map<string, TransportEvent[]>;
|
||||||
|
|
||||||
|
// Core operations
|
||||||
|
recordEvent(event: TransportEvent): TransportBlock;
|
||||||
|
getPlantJourney(plantId: string): PlantJourney | null;
|
||||||
|
getEnvironmentalImpact(userId: string): EnvironmentalImpact;
|
||||||
|
generateQRData(plantId?: string, batchId?: string): TransportQRData;
|
||||||
|
isChainValid(): boolean;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Block Creation Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
Event Input
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ Calculate Distance │ (if not provided)
|
||||||
|
│ Haversine Formula │
|
||||||
|
└──────────┬──────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ Calculate Carbon │ (if not provided)
|
||||||
|
│ factor × distance │ × weight
|
||||||
|
└──────────┬──────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ Create Block │
|
||||||
|
│ - index │
|
||||||
|
│ - timestamp │
|
||||||
|
│ - event data │
|
||||||
|
│ - previousHash │
|
||||||
|
│ - cumulative stats │
|
||||||
|
└──────────┬──────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ Mine Block │
|
||||||
|
│ Find nonce where │
|
||||||
|
│ hash starts with │
|
||||||
|
│ N zeros │
|
||||||
|
└──────────┬──────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ Add to Chain │
|
||||||
|
│ Update Indexes │
|
||||||
|
└──────────┬──────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Return Block
|
||||||
|
```
|
||||||
|
|
||||||
|
## Event Processing
|
||||||
|
|
||||||
|
### Event Type Handlers
|
||||||
|
|
||||||
|
Each event type extracts different IDs for indexing:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function extractPlantIds(event: TransportEvent): string[] {
|
||||||
|
switch (event.eventType) {
|
||||||
|
case 'planting':
|
||||||
|
return event.plantIds;
|
||||||
|
|
||||||
|
case 'growing_transport':
|
||||||
|
return event.plantIds;
|
||||||
|
|
||||||
|
case 'harvest':
|
||||||
|
return event.plantIds;
|
||||||
|
|
||||||
|
case 'seed_saving':
|
||||||
|
return event.parentPlantIds;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractBatchIds(event: TransportEvent): string[] {
|
||||||
|
switch (event.eventType) {
|
||||||
|
case 'seed_acquisition':
|
||||||
|
return [event.seedBatchId];
|
||||||
|
|
||||||
|
case 'planting':
|
||||||
|
return [event.seedBatchId];
|
||||||
|
|
||||||
|
case 'harvest':
|
||||||
|
const ids = [event.harvestBatchId];
|
||||||
|
if (event.seedBatchIdCreated) ids.push(event.seedBatchIdCreated);
|
||||||
|
return ids;
|
||||||
|
|
||||||
|
case 'processing':
|
||||||
|
return [...event.harvestBatchIds, event.processingBatchId];
|
||||||
|
|
||||||
|
case 'distribution':
|
||||||
|
case 'consumer_delivery':
|
||||||
|
return event.batchIds;
|
||||||
|
|
||||||
|
case 'seed_saving':
|
||||||
|
return [event.newSeedBatchId];
|
||||||
|
|
||||||
|
case 'seed_sharing':
|
||||||
|
return [event.seedBatchId];
|
||||||
|
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Distance Calculation
|
||||||
|
|
||||||
|
### Haversine Formula
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
static calculateDistance(
|
||||||
|
from: TransportLocation,
|
||||||
|
to: TransportLocation
|
||||||
|
): number {
|
||||||
|
const R = 6371; // Earth's radius in km
|
||||||
|
|
||||||
|
const dLat = toRadians(to.latitude - from.latitude);
|
||||||
|
const dLon = toRadians(to.longitude - from.longitude);
|
||||||
|
|
||||||
|
const a =
|
||||||
|
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||||
|
Math.cos(toRadians(from.latitude)) *
|
||||||
|
Math.cos(toRadians(to.latitude)) *
|
||||||
|
Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
||||||
|
|
||||||
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||||
|
|
||||||
|
return R * c; // Distance in kilometers
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Accuracy Notes
|
||||||
|
|
||||||
|
| Distance | Accuracy |
|
||||||
|
|----------|----------|
|
||||||
|
| < 10 km | ± 10 meters |
|
||||||
|
| 10-100 km | ± 100 meters |
|
||||||
|
| 100-1000 km | ± 1 km |
|
||||||
|
| > 1000 km | ± 10 km |
|
||||||
|
|
||||||
|
## Carbon Calculation
|
||||||
|
|
||||||
|
### Weight Estimation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function estimateWeight(event: TransportEvent): number {
|
||||||
|
switch (event.eventType) {
|
||||||
|
case 'seed_acquisition':
|
||||||
|
case 'seed_saving':
|
||||||
|
case 'seed_sharing':
|
||||||
|
return 0.1; // Seeds are light
|
||||||
|
|
||||||
|
case 'planting':
|
||||||
|
return 0.5; // Seedlings
|
||||||
|
|
||||||
|
case 'growing_transport':
|
||||||
|
return 2; // Potted plants
|
||||||
|
|
||||||
|
case 'harvest':
|
||||||
|
return event.netWeight || 5;
|
||||||
|
|
||||||
|
case 'processing':
|
||||||
|
return event.outputWeight || 5;
|
||||||
|
|
||||||
|
case 'distribution':
|
||||||
|
case 'consumer_delivery':
|
||||||
|
return 5; // Default produce weight
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Carbon Formula
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function calculateCarbon(
|
||||||
|
method: TransportMethod,
|
||||||
|
distanceKm: number,
|
||||||
|
weightKg: number
|
||||||
|
): number {
|
||||||
|
const factor = CARBON_FACTORS[method] || 0.1;
|
||||||
|
return factor * distanceKm * weightKg;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Journey Reconstruction
|
||||||
|
|
||||||
|
### Algorithm
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function getPlantJourney(plantId: string): PlantJourney | null {
|
||||||
|
// 1. Get all events for this plant
|
||||||
|
const events = plantEvents.get(plantId);
|
||||||
|
if (!events || events.length === 0) return null;
|
||||||
|
|
||||||
|
// 2. Sort by timestamp
|
||||||
|
const sorted = [...events].sort(
|
||||||
|
(a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3. Calculate totals
|
||||||
|
let totalFoodMiles = 0;
|
||||||
|
let totalCarbonKg = 0;
|
||||||
|
let daysInTransit = 0;
|
||||||
|
|
||||||
|
for (const event of sorted) {
|
||||||
|
totalFoodMiles += event.distanceKm;
|
||||||
|
totalCarbonKg += event.carbonFootprintKg;
|
||||||
|
daysInTransit += event.durationMinutes / (60 * 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Determine current stage
|
||||||
|
const currentStage = determineStage(sorted);
|
||||||
|
|
||||||
|
// 5. Find lineage info
|
||||||
|
const seedAcquisition = sorted.find(e => e.eventType === 'seed_acquisition');
|
||||||
|
const planting = sorted.find(e => e.eventType === 'planting');
|
||||||
|
|
||||||
|
// 6. Build journey object
|
||||||
|
return {
|
||||||
|
plantId,
|
||||||
|
seedBatchOrigin: seedAcquisition?.seedBatchId || planting?.seedBatchId,
|
||||||
|
currentCustodian: sorted[sorted.length - 1].receiverId,
|
||||||
|
currentLocation: sorted[sorted.length - 1].toLocation,
|
||||||
|
currentStage,
|
||||||
|
events: sorted,
|
||||||
|
totalFoodMiles,
|
||||||
|
totalCarbonKg,
|
||||||
|
daysInTransit: Math.round(daysInTransit),
|
||||||
|
daysGrowing: calculateGrowingDays(sorted),
|
||||||
|
generation: seedAcquisition?.generation || 0,
|
||||||
|
ancestorPlantIds: seedAcquisition?.parentPlantIds || [],
|
||||||
|
descendantSeedBatches: findDescendantSeeds(sorted)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## QR Code Generation
|
||||||
|
|
||||||
|
### Data Structure
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface TransportQRData {
|
||||||
|
plantId?: string;
|
||||||
|
batchId?: string;
|
||||||
|
blockchainAddress: string; // First 42 chars of latest hash
|
||||||
|
quickLookupUrl: string; // Web URL for tracking
|
||||||
|
lineageHash: string; // SHA256 of all events (16 chars)
|
||||||
|
currentCustodian: string; // Current holder
|
||||||
|
lastEventType: TransportEventType;
|
||||||
|
lastEventTimestamp: string;
|
||||||
|
verificationCode: string; // Random 8-char code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generation Process
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ Get events for │
|
||||||
|
│ plant/batch │
|
||||||
|
└──────────┬──────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ Calculate lineage │
|
||||||
|
│ hash (SHA256) │
|
||||||
|
└──────────┬──────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ Get blockchain │
|
||||||
|
│ address (latest │
|
||||||
|
│ block hash) │
|
||||||
|
└──────────┬──────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ Generate │
|
||||||
|
│ verification code │
|
||||||
|
└──────────┬──────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ Build QR data │
|
||||||
|
│ object │
|
||||||
|
└──────────┬──────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Return QRData
|
||||||
|
```
|
||||||
|
|
||||||
|
## Chain Validation
|
||||||
|
|
||||||
|
### Validation Checks
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function isChainValid(): boolean {
|
||||||
|
for (let i = 1; i < chain.length; i++) {
|
||||||
|
const current = chain[i];
|
||||||
|
const previous = chain[i - 1];
|
||||||
|
|
||||||
|
// Check 1: Hash integrity
|
||||||
|
const expectedHash = calculateHash(
|
||||||
|
current.index,
|
||||||
|
current.timestamp,
|
||||||
|
current.transportEvent,
|
||||||
|
current.previousHash,
|
||||||
|
current.nonce
|
||||||
|
);
|
||||||
|
if (current.hash !== expectedHash) {
|
||||||
|
return false; // Hash has been tampered
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check 2: Chain linkage
|
||||||
|
if (current.previousHash !== previous.hash) {
|
||||||
|
return false; // Chain is broken
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check 3: Proof of work
|
||||||
|
const target = '0'.repeat(difficulty);
|
||||||
|
if (current.hash.substring(0, difficulty) !== target) {
|
||||||
|
return false; // PoW not satisfied
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Storage and Persistence
|
||||||
|
|
||||||
|
### Export Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"difficulty": 3,
|
||||||
|
"chain": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"timestamp": "2024-01-01T00:00:00Z",
|
||||||
|
"transportEvent": { ... },
|
||||||
|
"previousHash": "0",
|
||||||
|
"hash": "000abc...",
|
||||||
|
"nonce": 12345,
|
||||||
|
"cumulativeCarbonKg": 0,
|
||||||
|
"cumulativeFoodMiles": 0,
|
||||||
|
"chainLength": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Import Process
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
static fromJSON(data: any): TransportChain {
|
||||||
|
const chain = new TransportChain(data.difficulty);
|
||||||
|
chain.chain = data.chain;
|
||||||
|
|
||||||
|
// Rebuild indexes from chain
|
||||||
|
for (const block of chain.chain) {
|
||||||
|
chain.indexEvent(block.transportEvent, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
return chain;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
|
||||||
|
### Indexing Strategy
|
||||||
|
|
||||||
|
| Index | Use Case | Complexity |
|
||||||
|
|-------|----------|------------|
|
||||||
|
| eventIndex | Event lookup by ID | O(1) |
|
||||||
|
| plantEvents | Plant journey | O(1) |
|
||||||
|
| batchEvents | Batch tracking | O(1) |
|
||||||
|
|
||||||
|
### Mining Optimization
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Parallel mining hint (future)
|
||||||
|
// Can be parallelized across CPU cores
|
||||||
|
function mineBlockParallel(block: TransportBlock): void {
|
||||||
|
const workers = os.cpus().length;
|
||||||
|
const ranges = divideNonceRange(0, MAX_NONCE, workers);
|
||||||
|
|
||||||
|
// Each worker tries nonces in its range
|
||||||
|
// First to find valid hash wins
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration Points
|
||||||
|
|
||||||
|
### With Plant Blockchain
|
||||||
|
|
||||||
|
```
|
||||||
|
Transport Chain Plant Chain
|
||||||
|
────────────── ───────────
|
||||||
|
plantIds in events ←─────────→ plantId in registrations
|
||||||
|
harvestBatchId ←─────────→ linked to plant
|
||||||
|
seedBatchId ←─────────→ lineage reference
|
||||||
|
```
|
||||||
|
|
||||||
|
### With Vertical Farm Controller
|
||||||
|
|
||||||
|
```
|
||||||
|
VF Controller Transport Chain
|
||||||
|
───────────── ───────────────
|
||||||
|
startCropBatch() ─creates─→ planting event
|
||||||
|
completeHarvest() ─creates─→ harvest event
|
||||||
|
─creates─→ distribution event
|
||||||
|
```
|
||||||
|
|
||||||
|
### With Demand Forecaster
|
||||||
|
|
||||||
|
```
|
||||||
|
Demand Forecaster Transport Chain
|
||||||
|
───────────────── ───────────────
|
||||||
|
supply matching ─tracks─→ distribution events
|
||||||
|
market matches ─creates─→ consumer_delivery events
|
||||||
|
```
|
||||||
298
docs/concepts/blockchain.md
Normal file
298
docs/concepts/blockchain.md
Normal file
|
|
@ -0,0 +1,298 @@
|
||||||
|
# Blockchain Architecture
|
||||||
|
|
||||||
|
Understanding LocalGreenChain's blockchain implementation for plant lineage and transport tracking.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
LocalGreenChain uses a custom proof-of-work blockchain designed specifically for agricultural traceability. Unlike cryptocurrency blockchains, our focus is on:
|
||||||
|
|
||||||
|
- **Immutability** - Plant records cannot be altered
|
||||||
|
- **Traceability** - Complete chain of custody
|
||||||
|
- **Efficiency** - Lightweight for agricultural use
|
||||||
|
- **Privacy** - User-controlled data visibility
|
||||||
|
|
||||||
|
## Core Concepts
|
||||||
|
|
||||||
|
### Blocks
|
||||||
|
|
||||||
|
Each block contains:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface PlantBlock {
|
||||||
|
index: number; // Position in chain
|
||||||
|
timestamp: string; // ISO 8601 datetime
|
||||||
|
data: PlantData; // Plant or transport data
|
||||||
|
previousHash: string; // Link to previous block
|
||||||
|
hash: string; // This block's hash
|
||||||
|
nonce: number; // Proof-of-work solution
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Chain Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ BLOCKCHAIN │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||||
|
│ │ Genesis │───→│ Block 1 │───→│ Block 2 │───→│ Block 3 │ │
|
||||||
|
│ │ Block │ │ │ │ │ │ │ │
|
||||||
|
│ │ │ │ hash: A │ │ hash: B │ │ hash: C │ │
|
||||||
|
│ │ prev: 0 │ │ prev: G │ │ prev: A │ │ prev: B │ │
|
||||||
|
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
|
||||||
|
│ G A B C │
|
||||||
|
│ │
|
||||||
|
│ Each block contains: │
|
||||||
|
│ - Plant registration OR transport event │
|
||||||
|
│ - Timestamp │
|
||||||
|
│ - Cryptographic link to previous block │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Proof of Work
|
||||||
|
|
||||||
|
### Mining Process
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function mineBlock(block: PlantBlock): void {
|
||||||
|
const target = '0'.repeat(difficulty);
|
||||||
|
|
||||||
|
while (block.hash.substring(0, difficulty) !== target) {
|
||||||
|
block.nonce++;
|
||||||
|
block.hash = calculateHash(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Difficulty Levels
|
||||||
|
|
||||||
|
| Difficulty | Leading Zeros | Avg. Time | Use Case |
|
||||||
|
|------------|---------------|-----------|----------|
|
||||||
|
| 1 | 0 | < 1ms | Development |
|
||||||
|
| 2 | 00 | ~10ms | Testing |
|
||||||
|
| 3 | 000 | ~100ms | Default |
|
||||||
|
| 4 | 0000 | ~1s | Production |
|
||||||
|
| 5 | 00000 | ~10s | High Security |
|
||||||
|
|
||||||
|
### Hash Calculation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function calculateHash(block: PlantBlock): string {
|
||||||
|
const data = `${block.index}${block.timestamp}${JSON.stringify(block.data)}${block.previousHash}${block.nonce}`;
|
||||||
|
return crypto.createHash('sha256').update(data).digest('hex');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Chain Integrity
|
||||||
|
|
||||||
|
### Validation
|
||||||
|
|
||||||
|
Every block must satisfy:
|
||||||
|
|
||||||
|
1. **Correct Hash** - Hash matches recalculated hash
|
||||||
|
2. **Valid Previous Hash** - Links to actual previous block
|
||||||
|
3. **Proof of Work** - Hash meets difficulty requirement
|
||||||
|
4. **Timestamp Order** - Blocks are chronological
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function isChainValid(chain: PlantBlock[]): boolean {
|
||||||
|
for (let i = 1; i < chain.length; i++) {
|
||||||
|
const current = chain[i];
|
||||||
|
const previous = chain[i - 1];
|
||||||
|
|
||||||
|
// Verify hash
|
||||||
|
const expectedHash = calculateHash(current);
|
||||||
|
if (current.hash !== expectedHash) return false;
|
||||||
|
|
||||||
|
// Verify chain link
|
||||||
|
if (current.previousHash !== previous.hash) return false;
|
||||||
|
|
||||||
|
// Verify proof of work
|
||||||
|
const target = '0'.repeat(difficulty);
|
||||||
|
if (current.hash.substring(0, difficulty) !== target) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Types
|
||||||
|
|
||||||
|
### Plant Registration Block
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
index: 42,
|
||||||
|
timestamp: "2024-06-01T10:00:00Z",
|
||||||
|
data: {
|
||||||
|
type: "plant_registration",
|
||||||
|
plantId: "plant-abc123",
|
||||||
|
commonName: "Tomato",
|
||||||
|
scientificName: "Solanum lycopersicum",
|
||||||
|
location: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060
|
||||||
|
},
|
||||||
|
owner: {
|
||||||
|
id: "user-123",
|
||||||
|
name: "John Doe"
|
||||||
|
},
|
||||||
|
generation: 0,
|
||||||
|
parentPlantId: null
|
||||||
|
},
|
||||||
|
previousHash: "00abc...",
|
||||||
|
hash: "00def...",
|
||||||
|
nonce: 12345
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Transport Event Block
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
index: 43,
|
||||||
|
timestamp: "2024-06-15T08:00:00Z",
|
||||||
|
data: {
|
||||||
|
type: "transport_event",
|
||||||
|
eventType: "harvest",
|
||||||
|
plantIds: ["plant-abc123"],
|
||||||
|
fromLocation: { ... },
|
||||||
|
toLocation: { ... },
|
||||||
|
transportMethod: "electric_vehicle",
|
||||||
|
carbonFootprintKg: 2.5,
|
||||||
|
distanceKm: 25
|
||||||
|
},
|
||||||
|
previousHash: "00def...",
|
||||||
|
hash: "00ghi...",
|
||||||
|
nonce: 67890
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Lineage Tracking
|
||||||
|
|
||||||
|
### Parent-Child Relationships
|
||||||
|
|
||||||
|
```
|
||||||
|
Original Plant (Gen 0)
|
||||||
|
├── previousHash: null
|
||||||
|
├── propagationType: null
|
||||||
|
│
|
||||||
|
├─→ Clone A (Gen 1)
|
||||||
|
│ ├── previousHash: Original
|
||||||
|
│ ├── propagationType: "clone"
|
||||||
|
│ │
|
||||||
|
│ ├─→ Seed A-1 (Gen 2)
|
||||||
|
│ │ └── propagationType: "seed"
|
||||||
|
│ │
|
||||||
|
│ └─→ Clone A-2 (Gen 2)
|
||||||
|
│ └── propagationType: "clone"
|
||||||
|
│
|
||||||
|
└─→ Seed B (Gen 1)
|
||||||
|
├── propagationType: "seed"
|
||||||
|
│
|
||||||
|
└─→ Clone B-1 (Gen 2)
|
||||||
|
└── propagationType: "clone"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lineage Query
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function getLineage(plantId: string, generations: number): LineageTree {
|
||||||
|
const plant = findPlant(plantId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
plant,
|
||||||
|
ancestors: getAncestors(plant.parentPlantId, generations),
|
||||||
|
descendants: getDescendants(plantId, generations)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cross-Chain References
|
||||||
|
|
||||||
|
### Transport Chain ↔ Plant Chain
|
||||||
|
|
||||||
|
Transport events reference plants by ID:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Transport chain references plant chain
|
||||||
|
{
|
||||||
|
eventType: "harvest",
|
||||||
|
plantIds: ["plant-abc123", "plant-abc124"], // References plant chain
|
||||||
|
harvestBatchId: "batch-001"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plant chain may reference transport
|
||||||
|
{
|
||||||
|
plantId: "plant-abc123",
|
||||||
|
lastTransportBlock: 156, // Reference to transport chain
|
||||||
|
currentCustodian: "user-456"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
### Storage
|
||||||
|
|
||||||
|
```
|
||||||
|
Block Size: ~1-2 KB typical
|
||||||
|
Growth Rate: ~10-100 blocks/day (varies by activity)
|
||||||
|
Storage/year: ~10-100 MB for active installation
|
||||||
|
```
|
||||||
|
|
||||||
|
### Indexing
|
||||||
|
|
||||||
|
Secondary indexes for fast lookups:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Plant ID → Block indices
|
||||||
|
plantIndex: Map<string, number[]>
|
||||||
|
|
||||||
|
// User ID → Block indices
|
||||||
|
userIndex: Map<string, number[]>
|
||||||
|
|
||||||
|
// Location → Block indices (geohash)
|
||||||
|
locationIndex: Map<string, number[]>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
### Tamper Resistance
|
||||||
|
|
||||||
|
1. **Hash Chain** - Altering any block changes all subsequent hashes
|
||||||
|
2. **Proof of Work** - Expensive to recompute chain
|
||||||
|
3. **Distributed Copies** - Multiple users hold chain copies
|
||||||
|
4. **Signature Support** - Optional digital signatures
|
||||||
|
|
||||||
|
### Attack Resistance
|
||||||
|
|
||||||
|
| Attack | Defense |
|
||||||
|
|--------|---------|
|
||||||
|
| Data tampering | Hash verification fails |
|
||||||
|
| Chain rewrite | PoW cost prohibitive |
|
||||||
|
| Fake blocks | Signature verification |
|
||||||
|
| Replay | Timestamps + indices |
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### For Developers
|
||||||
|
|
||||||
|
1. **Validate on load** - Always verify chain integrity
|
||||||
|
2. **Backup regularly** - Export chain to JSON
|
||||||
|
3. **Monitor growth** - Archive old blocks if needed
|
||||||
|
4. **Index selectively** - Only index what you query
|
||||||
|
|
||||||
|
### For Operators
|
||||||
|
|
||||||
|
1. **Set appropriate difficulty** - Balance speed vs security
|
||||||
|
2. **Backup before updates** - Chain is your source of truth
|
||||||
|
3. **Monitor disk space** - Plan for growth
|
||||||
|
4. **Test restores** - Verify backups work
|
||||||
|
|
||||||
|
## Future Considerations
|
||||||
|
|
||||||
|
- **Distributed Consensus** - Multi-node verification
|
||||||
|
- **Sharding** - Geographic or species-based partitions
|
||||||
|
- **Merkle Trees** - Efficient verification
|
||||||
|
- **Zero-Knowledge Proofs** - Privacy-preserving verification
|
||||||
322
docs/concepts/carbon-footprint.md
Normal file
322
docs/concepts/carbon-footprint.md
Normal file
|
|
@ -0,0 +1,322 @@
|
||||||
|
# Carbon Footprint Tracking
|
||||||
|
|
||||||
|
Understanding environmental impact measurement in LocalGreenChain.
|
||||||
|
|
||||||
|
## Why Track Carbon?
|
||||||
|
|
||||||
|
Food production accounts for 26% of global greenhouse gas emissions. By tracking carbon at every step, LocalGreenChain enables:
|
||||||
|
|
||||||
|
1. **Awareness** - Know the impact of your food
|
||||||
|
2. **Optimization** - Choose lower-carbon options
|
||||||
|
3. **Reduction** - Make data-driven improvements
|
||||||
|
4. **Comparison** - See savings vs conventional
|
||||||
|
|
||||||
|
## Carbon Sources in Agriculture
|
||||||
|
|
||||||
|
### Traditional Supply Chain
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ CONVENTIONAL FOOD CARBON FOOTPRINT │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ Growing Transport Processing Retail Consumer │
|
||||||
|
│ ████████ ████████████ ████ ████ ████ │
|
||||||
|
│ 30% 50% 8% 7% 5% │
|
||||||
|
│ │
|
||||||
|
│ Total: 2.5 kg CO2 per kg produce (average) │
|
||||||
|
│ │
|
||||||
|
│ Key Contributors: │
|
||||||
|
│ - Fertilizer production and application │
|
||||||
|
│ - Long-distance trucking (refrigerated) │
|
||||||
|
│ - International shipping │
|
||||||
|
│ - Cold storage facilities │
|
||||||
|
│ - Last-mile delivery │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### LocalGreenChain Model
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ LOCALGREENCHAIN CARBON FOOTPRINT │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ Growing Transport Processing Direct │
|
||||||
|
│ ████ ██ █ (Consumer) │
|
||||||
|
│ 60% 25% 10% 5% │
|
||||||
|
│ │
|
||||||
|
│ Total: 0.3 kg CO2 per kg produce (average) │
|
||||||
|
│ │
|
||||||
|
│ Savings: 88% reduction vs conventional │
|
||||||
|
│ │
|
||||||
|
│ Why Lower: │
|
||||||
|
│ - Local production (short transport) │
|
||||||
|
│ - Organic/sustainable methods │
|
||||||
|
│ - No cold storage needed (fresh delivery) │
|
||||||
|
│ - Efficient vertical farming │
|
||||||
|
│ - Direct grower-consumer connection │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Transport Carbon Factors
|
||||||
|
|
||||||
|
### By Transport Method
|
||||||
|
|
||||||
|
| Method | kg CO2 / km / kg | Notes |
|
||||||
|
|--------|------------------|-------|
|
||||||
|
| Walking | 0 | Zero emissions |
|
||||||
|
| Bicycle | 0 | Zero emissions |
|
||||||
|
| Electric Vehicle | 0.02 | Grid-dependent |
|
||||||
|
| Hybrid Vehicle | 0.08 | Partial electric |
|
||||||
|
| Gasoline Vehicle | 0.12 | Standard car |
|
||||||
|
| Diesel Truck | 0.15 | Delivery truck |
|
||||||
|
| Electric Truck | 0.03 | Large EV |
|
||||||
|
| Refrigerated Truck | 0.25 | Cooling adds load |
|
||||||
|
| Rail | 0.01 | Very efficient |
|
||||||
|
| Ship | 0.008 | Bulk efficiency |
|
||||||
|
| Air Freight | 0.50 | Highest impact |
|
||||||
|
| Drone | 0.01 | Short distance only |
|
||||||
|
|
||||||
|
### Calculation Formula
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function calculateTransportCarbon(
|
||||||
|
method: TransportMethod,
|
||||||
|
distanceKm: number,
|
||||||
|
weightKg: number
|
||||||
|
): number {
|
||||||
|
const factor = CARBON_FACTORS[method];
|
||||||
|
return factor * distanceKm * weightKg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example: 20 kg tomatoes, 25 km by electric vehicle
|
||||||
|
const carbon = 0.02 * 25 * 20; // = 10 kg CO2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Food Miles
|
||||||
|
|
||||||
|
### Definition
|
||||||
|
|
||||||
|
Food miles = total distance food travels from origin to consumer.
|
||||||
|
|
||||||
|
### Why It Matters
|
||||||
|
|
||||||
|
```
|
||||||
|
California Tomato to NYC:
|
||||||
|
├── Farm to packing: 20 miles
|
||||||
|
├── Packing to distribution: 50 miles
|
||||||
|
├── Distribution to cross-country truck: 10 miles
|
||||||
|
├── California to NYC: 2,800 miles
|
||||||
|
├── NYC distribution to store: 30 miles
|
||||||
|
├── Store to consumer: 5 miles
|
||||||
|
└── TOTAL: 2,915 miles
|
||||||
|
|
||||||
|
Local Brooklyn Tomato:
|
||||||
|
├── Farm to consumer: 12 miles
|
||||||
|
└── TOTAL: 12 miles
|
||||||
|
|
||||||
|
Savings: 99.6% reduction in food miles
|
||||||
|
```
|
||||||
|
|
||||||
|
### Distance Calculation
|
||||||
|
|
||||||
|
LocalGreenChain uses the Haversine formula:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function calculateDistance(
|
||||||
|
from: { lat: number; lon: number },
|
||||||
|
to: { lat: number; lon: number }
|
||||||
|
): number {
|
||||||
|
const R = 6371; // Earth's radius in km
|
||||||
|
|
||||||
|
const dLat = toRadians(to.lat - from.lat);
|
||||||
|
const dLon = toRadians(to.lon - from.lon);
|
||||||
|
|
||||||
|
const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
|
||||||
|
Math.cos(toRadians(from.lat)) *
|
||||||
|
Math.cos(toRadians(to.lat)) *
|
||||||
|
Math.sin(dLon/2) * Math.sin(dLon/2);
|
||||||
|
|
||||||
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
||||||
|
|
||||||
|
return R * c; // Distance in km
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cumulative Tracking
|
||||||
|
|
||||||
|
### Per-Plant Journey
|
||||||
|
|
||||||
|
Every transport event adds to the total:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface PlantJourney {
|
||||||
|
plantId: string;
|
||||||
|
events: TransportEvent[];
|
||||||
|
|
||||||
|
totalFoodMiles: number; // Sum of all distances
|
||||||
|
totalCarbonKg: number; // Sum of all emissions
|
||||||
|
|
||||||
|
// Breakdown
|
||||||
|
milesPerStage: {
|
||||||
|
seedAcquisition: number;
|
||||||
|
growing: number;
|
||||||
|
harvest: number;
|
||||||
|
distribution: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Per-User Footprint
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface EnvironmentalImpact {
|
||||||
|
totalCarbonKg: number;
|
||||||
|
totalFoodMiles: number;
|
||||||
|
|
||||||
|
// Efficiency metrics
|
||||||
|
carbonPerKgProduce: number;
|
||||||
|
milesPerKgProduce: number;
|
||||||
|
|
||||||
|
// Breakdown by transport method
|
||||||
|
breakdownByMethod: {
|
||||||
|
[method: string]: {
|
||||||
|
distance: number;
|
||||||
|
carbon: number;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Comparison to conventional
|
||||||
|
comparisonToConventional: {
|
||||||
|
carbonSaved: number;
|
||||||
|
milesSaved: number;
|
||||||
|
percentageReduction: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conventional Comparison
|
||||||
|
|
||||||
|
### Baseline Assumptions
|
||||||
|
|
||||||
|
| Produce | Conventional (kg CO2/kg) | Local (kg CO2/kg) | Savings |
|
||||||
|
|---------|--------------------------|-------------------|---------|
|
||||||
|
| Tomatoes | 2.8 | 0.32 | 89% |
|
||||||
|
| Lettuce | 1.5 | 0.15 | 90% |
|
||||||
|
| Peppers | 2.2 | 0.28 | 87% |
|
||||||
|
| Basil | 1.8 | 0.18 | 90% |
|
||||||
|
| Strawberries | 2.0 | 0.25 | 88% |
|
||||||
|
|
||||||
|
### Calculation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function compareToConventional(
|
||||||
|
totalCarbonKg: number,
|
||||||
|
totalWeightKg: number
|
||||||
|
): Comparison {
|
||||||
|
// Conventional average: 2.5 kg CO2 per kg produce
|
||||||
|
// Conventional miles: 1,500 average
|
||||||
|
|
||||||
|
const conventionalCarbon = totalWeightKg * 2.5;
|
||||||
|
const conventionalMiles = totalWeightKg * 1500;
|
||||||
|
|
||||||
|
return {
|
||||||
|
carbonSaved: Math.max(0, conventionalCarbon - totalCarbonKg),
|
||||||
|
milesSaved: Math.max(0, conventionalMiles - totalFoodMiles),
|
||||||
|
percentageReduction: Math.round(
|
||||||
|
(1 - totalCarbonKg / conventionalCarbon) * 100
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Vertical Farming Impact
|
||||||
|
|
||||||
|
### Energy-Based Carbon
|
||||||
|
|
||||||
|
Vertical farms trade transport carbon for energy carbon:
|
||||||
|
|
||||||
|
```
|
||||||
|
Outdoor Growing: 0.2 kg CO2/kg (minimal energy)
|
||||||
|
+ Transport (1,500 mi): 2.3 kg CO2/kg
|
||||||
|
= Total: 2.5 kg CO2/kg
|
||||||
|
|
||||||
|
Vertical Farm: 0.25 kg CO2/kg (lighting/HVAC)
|
||||||
|
+ Transport (10 mi): 0.02 kg CO2/kg
|
||||||
|
= Total: 0.27 kg CO2/kg
|
||||||
|
|
||||||
|
Net Savings: 89%
|
||||||
|
```
|
||||||
|
|
||||||
|
### Factors Affecting VF Carbon
|
||||||
|
|
||||||
|
| Factor | Impact | Optimization |
|
||||||
|
|--------|--------|--------------|
|
||||||
|
| Grid carbon intensity | High | Renewable energy |
|
||||||
|
| LED efficiency | Medium | Latest technology |
|
||||||
|
| HVAC efficiency | Medium | Heat pumps |
|
||||||
|
| Insulation | Low | Building design |
|
||||||
|
|
||||||
|
## Reporting
|
||||||
|
|
||||||
|
### Environmental Impact Dashboard
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ YOUR ENVIRONMENTAL IMPACT │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ This Month vs Conventional │
|
||||||
|
│ ──────────── ───────────────── │
|
||||||
|
│ Total Produce: 45 kg You Saved: │
|
||||||
|
│ Carbon: 8.5 kg CO2 □ 104 kg CO2 │
|
||||||
|
│ Food Miles: 245 km □ 67,255 food miles │
|
||||||
|
│ □ 93% reduction │
|
||||||
|
│ │
|
||||||
|
│ Breakdown by Transport Method │
|
||||||
|
│ ───────────────────────────── │
|
||||||
|
│ Electric Vehicle: ████████████████ 180 km (0.8 kg CO2) │
|
||||||
|
│ Walking: █████ 45 km (0 kg CO2) │
|
||||||
|
│ Bicycle: ██ 20 km (0 kg CO2) │
|
||||||
|
│ │
|
||||||
|
│ Your Ranking: Top 15% of consumers │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### For Growers
|
||||||
|
|
||||||
|
1. **Local seed sources** - Reduce acquisition miles
|
||||||
|
2. **Clean transport** - Electric, bicycle, walk
|
||||||
|
3. **Batch deliveries** - Combine shipments
|
||||||
|
4. **Direct sales** - Skip distribution chain
|
||||||
|
5. **Renewable energy** - Solar for operations
|
||||||
|
|
||||||
|
### For Consumers
|
||||||
|
|
||||||
|
1. **Buy local** - Shorter supply chain
|
||||||
|
2. **Accept imperfect** - Reduces waste transport
|
||||||
|
3. **Plan purchases** - Fewer delivery trips
|
||||||
|
4. **Pick up when possible** - Zero delivery carbon
|
||||||
|
5. **Choose in-season** - No climate-controlled transport
|
||||||
|
|
||||||
|
### For System Operators
|
||||||
|
|
||||||
|
1. **Route optimization** - Minimize total distance
|
||||||
|
2. **Load optimization** - Full trucks, no empty returns
|
||||||
|
3. **Hub placement** - Strategic distribution points
|
||||||
|
4. **Electric fleet** - Transition to zero-emission
|
||||||
|
5. **Carbon tracking** - Continuous monitoring
|
||||||
|
|
||||||
|
## Future Improvements
|
||||||
|
|
||||||
|
- **Scope 3 emissions** - Full lifecycle analysis
|
||||||
|
- **Carbon offsetting** - Tree planting, etc.
|
||||||
|
- **Carbon credits** - Tradeable savings
|
||||||
|
- **Real-time tracking** - GPS + carbon calculation
|
||||||
|
- **AI optimization** - Minimize total footprint
|
||||||
328
docs/concepts/seasonal-planning.md
Normal file
328
docs/concepts/seasonal-planning.md
Normal file
|
|
@ -0,0 +1,328 @@
|
||||||
|
# Seasonal Planning
|
||||||
|
|
||||||
|
Understanding seasonal agriculture optimization in LocalGreenChain.
|
||||||
|
|
||||||
|
## The Seasonal Imperative
|
||||||
|
|
||||||
|
Traditional agriculture follows natural seasons. LocalGreenChain optimizes this by:
|
||||||
|
|
||||||
|
1. **Matching production to seasons** - Grow what grows best
|
||||||
|
2. **Forecasting seasonal demand** - Plant for expected consumption
|
||||||
|
3. **Extending seasons** - Greenhouses and vertical farms
|
||||||
|
4. **Planning transitions** - Smooth handoffs between seasons
|
||||||
|
|
||||||
|
## Seasonal Calendar
|
||||||
|
|
||||||
|
### Northern Hemisphere
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ SEASONAL GROWING CALENDAR │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC │
|
||||||
|
│ ├────┼────┼────┼────┼────┼────┼────┼────┼────┼────┼────┤ │
|
||||||
|
│ │ │
|
||||||
|
│ │ WINTER SPRING SUMMER FALL WINTER │
|
||||||
|
│ │ │
|
||||||
|
│ │ Indoor: Cool Season: Warm Season: Cool Season: │
|
||||||
|
│ │ Microgreens Lettuce Tomatoes Kale │
|
||||||
|
│ │ Sprouts Spinach Peppers Broccoli │
|
||||||
|
│ │ Peas Cucumbers Brussels │
|
||||||
|
│ │ Radishes Basil Sprouts │
|
||||||
|
│ │ Squash Carrots │
|
||||||
|
│ │ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Seasonal Factors
|
||||||
|
|
||||||
|
Each crop has seasonal multipliers:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const SEASONAL_FACTORS = {
|
||||||
|
tomato: {
|
||||||
|
spring: 0.3, // Early season - limited
|
||||||
|
summer: 1.2, // Peak season - abundant
|
||||||
|
fall: 0.6, // Late season - declining
|
||||||
|
winter: 0.0 // Not available outdoors
|
||||||
|
},
|
||||||
|
lettuce: {
|
||||||
|
spring: 1.2, // Ideal conditions
|
||||||
|
summer: 0.5, // Too hot - bolts
|
||||||
|
fall: 1.2, // Ideal conditions
|
||||||
|
winter: 0.3 // Limited (greenhouse only)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Demand Seasonality
|
||||||
|
|
||||||
|
### Consumer Patterns
|
||||||
|
|
||||||
|
```
|
||||||
|
Salads (Lettuce, Greens):
|
||||||
|
├── Summer: ████████████████ High demand
|
||||||
|
├── Spring: ████████████ Moderate-high
|
||||||
|
├── Fall: ████████ Moderate
|
||||||
|
└── Winter: ████ Lower
|
||||||
|
|
||||||
|
Tomatoes:
|
||||||
|
├── Summer: ████████████████████ Peak
|
||||||
|
├── Fall: ████████████ Good
|
||||||
|
├── Spring: ████████ Moderate (imported)
|
||||||
|
└── Winter: ████ Low (imported)
|
||||||
|
|
||||||
|
Root Vegetables:
|
||||||
|
├── Fall: ████████████████ Peak (harvest)
|
||||||
|
├── Winter: ████████████████ High (storage)
|
||||||
|
├── Spring: ████████ Moderate
|
||||||
|
└── Summer: ████ Low
|
||||||
|
```
|
||||||
|
|
||||||
|
### Forecasting Seasonal Demand
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function applySeasonalFactor(
|
||||||
|
baseDemand: number,
|
||||||
|
produceType: string,
|
||||||
|
season: Season
|
||||||
|
): number {
|
||||||
|
const factors = SEASONAL_FACTORS[produceType];
|
||||||
|
const factor = factors?.[season] ?? 1.0;
|
||||||
|
return baseDemand * factor;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Planning Cycles
|
||||||
|
|
||||||
|
### Spring Planning (Feb-Mar)
|
||||||
|
|
||||||
|
1. **Review winter performance**
|
||||||
|
2. **Order seeds for spring/summer crops**
|
||||||
|
3. **Start indoor seedlings**
|
||||||
|
4. **Plan succession plantings**
|
||||||
|
5. **Commit supply to demand signals**
|
||||||
|
|
||||||
|
### Summer Planning (May-Jun)
|
||||||
|
|
||||||
|
1. **Adjust for actual spring results**
|
||||||
|
2. **Plan fall crop transitions**
|
||||||
|
3. **Order fall seeds**
|
||||||
|
4. **Plan preservation (canning, freezing)**
|
||||||
|
5. **Monitor water needs**
|
||||||
|
|
||||||
|
### Fall Planning (Aug-Sep)
|
||||||
|
|
||||||
|
1. **Seed saving from summer crops**
|
||||||
|
2. **Plant winter storage crops**
|
||||||
|
3. **Extend season with row covers**
|
||||||
|
4. **Plan winter production (indoor)**
|
||||||
|
5. **Prepare for first frost**
|
||||||
|
|
||||||
|
### Winter Planning (Nov-Dec)
|
||||||
|
|
||||||
|
1. **Review year's performance**
|
||||||
|
2. **Order next year's seeds**
|
||||||
|
3. **Plan crop rotation**
|
||||||
|
4. **Maintain indoor production**
|
||||||
|
5. **Update demand preferences**
|
||||||
|
|
||||||
|
## Seasonal Recommendations
|
||||||
|
|
||||||
|
### How Recommendations Work
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function generateSeasonalRecommendations(
|
||||||
|
grower: Grower,
|
||||||
|
season: Season,
|
||||||
|
demandSignals: DemandSignal[]
|
||||||
|
): PlantingRecommendation[] {
|
||||||
|
const recommendations = [];
|
||||||
|
|
||||||
|
for (const crop of getSeasonalCrops(season)) {
|
||||||
|
// Check if in season for this region
|
||||||
|
if (!isValidForSeason(crop, season, grower.hardinessZone)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find matching demand
|
||||||
|
const demand = findDemandForCrop(demandSignals, crop);
|
||||||
|
|
||||||
|
// Calculate recommendation
|
||||||
|
if (demand.gapKg > 0) {
|
||||||
|
recommendations.push({
|
||||||
|
produceType: crop,
|
||||||
|
plantByDate: getPlantByDate(crop, season),
|
||||||
|
expectedHarvestDate: getHarvestDate(crop, season),
|
||||||
|
...
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return recommendations;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extending Seasons
|
||||||
|
|
||||||
|
### Season Extension Techniques
|
||||||
|
|
||||||
|
| Technique | Season Extension | Crops Suited |
|
||||||
|
|-----------|------------------|--------------|
|
||||||
|
| Row Covers | +2-4 weeks | Greens, roots |
|
||||||
|
| Cold Frames | +4-6 weeks | Salads, herbs |
|
||||||
|
| Hoop Houses | +6-10 weeks | Most crops |
|
||||||
|
| Heated Greenhouse | Year-round | All crops |
|
||||||
|
| Vertical Farm | Year-round | Leafy, herbs |
|
||||||
|
|
||||||
|
### Integration with Vertical Farms
|
||||||
|
|
||||||
|
```
|
||||||
|
Outdoor Season: ████████████████░░░░░░░░████████████████
|
||||||
|
Greenhouse: ████████████████████████████████████████
|
||||||
|
Vertical Farm: ████████████████████████████████████████
|
||||||
|
|
||||||
|
Combined Supply: ████████████████████████████████████████
|
||||||
|
```
|
||||||
|
|
||||||
|
Vertical farms fill gaps:
|
||||||
|
- Early spring (before outdoor ready)
|
||||||
|
- Mid-summer (heat gaps)
|
||||||
|
- Late fall (after frost)
|
||||||
|
- Winter (full production)
|
||||||
|
|
||||||
|
## Crop Rotation
|
||||||
|
|
||||||
|
### Benefits
|
||||||
|
|
||||||
|
1. **Soil health** - Different nutrient needs
|
||||||
|
2. **Pest reduction** - Break pest cycles
|
||||||
|
3. **Disease prevention** - Reduce pathogen buildup
|
||||||
|
4. **Yield improvement** - Better long-term production
|
||||||
|
|
||||||
|
### Rotation Groups
|
||||||
|
|
||||||
|
```
|
||||||
|
Year 1: LEAFY GREENS (Nitrogen users)
|
||||||
|
Lettuce, Spinach, Kale, Chard
|
||||||
|
↓
|
||||||
|
Year 2: FRUITING (Heavy feeders)
|
||||||
|
Tomatoes, Peppers, Squash, Cucumbers
|
||||||
|
↓
|
||||||
|
Year 3: LEGUMES (Nitrogen fixers)
|
||||||
|
Beans, Peas, Cover crops
|
||||||
|
↓
|
||||||
|
Year 4: ROOTS (Light feeders)
|
||||||
|
Carrots, Beets, Radishes, Onions
|
||||||
|
↓
|
||||||
|
Back to Year 1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rotation in LocalGreenChain
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface SeasonalPlan {
|
||||||
|
growerId: string;
|
||||||
|
year: number;
|
||||||
|
season: Season;
|
||||||
|
|
||||||
|
// Previous year data for rotation
|
||||||
|
previousYearCrops: Map<Zone, string>;
|
||||||
|
|
||||||
|
// Current plan respects rotation
|
||||||
|
plannedCrops: PlannedCrop[];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Succession Planting
|
||||||
|
|
||||||
|
### Concept
|
||||||
|
|
||||||
|
Plant same crop multiple times for continuous harvest:
|
||||||
|
|
||||||
|
```
|
||||||
|
Week 1: Plant batch A [●●●●●]
|
||||||
|
Week 3: Plant batch B [●●●●●] → Batch A growing [○○○●●]
|
||||||
|
Week 5: Plant batch C [●●●●●] → Batch A harvest [✓✓✓○○]
|
||||||
|
Week 7: Plant batch D [●●●●●] → Batch B harvest [✓✓✓○○]
|
||||||
|
...
|
||||||
|
|
||||||
|
Result: Continuous harvest every 2 weeks
|
||||||
|
```
|
||||||
|
|
||||||
|
### Scheduling
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function planSuccessionPlanting(
|
||||||
|
crop: string,
|
||||||
|
totalWeeks: number,
|
||||||
|
harvestFrequency: number
|
||||||
|
): PlantingSchedule[] {
|
||||||
|
const schedules = [];
|
||||||
|
const growingDays = SEASONAL_DATA[crop].growingDays;
|
||||||
|
|
||||||
|
let weekOffset = 0;
|
||||||
|
while (weekOffset < totalWeeks) {
|
||||||
|
schedules.push({
|
||||||
|
plantWeek: weekOffset,
|
||||||
|
harvestWeek: weekOffset + Math.ceil(growingDays / 7)
|
||||||
|
});
|
||||||
|
weekOffset += harvestFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
return schedules;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### For Growers
|
||||||
|
|
||||||
|
1. **Plan early** - Order seeds 2-3 months ahead
|
||||||
|
2. **Track frost dates** - Know your last spring/first fall frost
|
||||||
|
3. **Use succession** - Continuous harvest beats big batches
|
||||||
|
4. **Save seeds** - Preserve locally-adapted varieties
|
||||||
|
5. **Check demand** - Align planting with signals
|
||||||
|
|
||||||
|
### For Consumers
|
||||||
|
|
||||||
|
1. **Embrace seasonality** - Best produce is in-season
|
||||||
|
2. **Set preferences** - System learns your patterns
|
||||||
|
3. **Be flexible** - Accept seasonal variety
|
||||||
|
4. **Preserve** - Learn to freeze, can, dry
|
||||||
|
5. **Plan ahead** - Subscribe to seasonal boxes
|
||||||
|
|
||||||
|
## Data-Driven Optimization
|
||||||
|
|
||||||
|
### Tracking Seasonal Performance
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface SeasonalAnalytics {
|
||||||
|
season: Season;
|
||||||
|
year: number;
|
||||||
|
|
||||||
|
// What worked
|
||||||
|
successfulCrops: {
|
||||||
|
crop: string;
|
||||||
|
yieldVsExpected: number; // >1.0 = outperformed
|
||||||
|
qualityScore: number;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
// What didn't
|
||||||
|
failedCrops: {
|
||||||
|
crop: string;
|
||||||
|
reason: string;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
// Learnings for next year
|
||||||
|
recommendations: string[];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Continuous Improvement
|
||||||
|
|
||||||
|
1. **Record everything** - Conditions, yields, issues
|
||||||
|
2. **Analyze yearly** - What patterns emerge?
|
||||||
|
3. **Adjust plans** - Apply learnings
|
||||||
|
4. **Share knowledge** - Community benefits
|
||||||
505
docs/examples/demand-driven-planting.md
Normal file
505
docs/examples/demand-driven-planting.md
Normal file
|
|
@ -0,0 +1,505 @@
|
||||||
|
# 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
|
||||||
466
docs/examples/seed-to-harvest.md
Normal file
466
docs/examples/seed-to-harvest.md
Normal file
|
|
@ -0,0 +1,466 @@
|
||||||
|
# Example: Seed to Harvest Workflow
|
||||||
|
|
||||||
|
Complete working example of tracking a plant from seed acquisition through harvest.
|
||||||
|
|
||||||
|
## Scenario
|
||||||
|
|
||||||
|
You're a grower who just acquired tomato seeds and wants to track them through the full growing cycle.
|
||||||
|
|
||||||
|
## Step 1: Acquire Seeds
|
||||||
|
|
||||||
|
### Record Seed Acquisition
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// POST /api/transport/seed-acquisition
|
||||||
|
|
||||||
|
const seedAcquisitionEvent = {
|
||||||
|
// Event identity
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
eventType: 'seed_acquisition',
|
||||||
|
|
||||||
|
// Seed details
|
||||||
|
seedBatchId: 'seeds-tomato-2024-001',
|
||||||
|
sourceType: 'purchase',
|
||||||
|
species: 'Solanum lycopersicum',
|
||||||
|
variety: 'Cherokee Purple',
|
||||||
|
quantity: 100,
|
||||||
|
quantityUnit: 'seeds',
|
||||||
|
generation: 1,
|
||||||
|
certifications: ['organic', 'heirloom'],
|
||||||
|
|
||||||
|
// Location tracking
|
||||||
|
fromLocation: {
|
||||||
|
latitude: 38.9072,
|
||||||
|
longitude: -77.0369,
|
||||||
|
locationType: 'seed_bank',
|
||||||
|
facilityName: 'Heritage Seed Company',
|
||||||
|
city: 'Washington',
|
||||||
|
country: 'USA'
|
||||||
|
},
|
||||||
|
toLocation: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060,
|
||||||
|
locationType: 'farm',
|
||||||
|
facilityName: 'Brooklyn Urban Farm',
|
||||||
|
city: 'Brooklyn',
|
||||||
|
country: 'USA'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Transport details
|
||||||
|
transportMethod: 'local_delivery',
|
||||||
|
distanceKm: 350,
|
||||||
|
durationMinutes: 1440, // 1 day shipping
|
||||||
|
|
||||||
|
// Parties
|
||||||
|
senderId: 'heritage-seeds-001',
|
||||||
|
receiverId: 'grower-brooklyn-001',
|
||||||
|
status: 'delivered'
|
||||||
|
};
|
||||||
|
|
||||||
|
// API call
|
||||||
|
const response = await fetch('/api/transport/seed-acquisition', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(seedAcquisitionEvent)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data: block } = await response.json();
|
||||||
|
console.log('Seed acquisition recorded:', block.hash);
|
||||||
|
// Output: Seed acquisition recorded: 000abc123...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 2: Plant Seeds
|
||||||
|
|
||||||
|
### Record Planting Event
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Wait until planting day...
|
||||||
|
|
||||||
|
// POST /api/transport/planting
|
||||||
|
|
||||||
|
const plantingEvent = {
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
eventType: 'planting',
|
||||||
|
|
||||||
|
// Link to seeds
|
||||||
|
seedBatchId: 'seeds-tomato-2024-001',
|
||||||
|
|
||||||
|
// New plants created
|
||||||
|
plantIds: Array.from({ length: 25 }, (_, i) =>
|
||||||
|
`plant-tomato-2024-${String(i + 1).padStart(3, '0')}`
|
||||||
|
),
|
||||||
|
quantityPlanted: 25,
|
||||||
|
|
||||||
|
// Planting details
|
||||||
|
plantingMethod: 'indoor_start',
|
||||||
|
growingEnvironment: 'greenhouse',
|
||||||
|
sowingDepth: 6, // mm
|
||||||
|
spacing: 5, // cm (seed starting trays)
|
||||||
|
|
||||||
|
// Timeline
|
||||||
|
expectedHarvestDate: new Date(
|
||||||
|
Date.now() + 80 * 24 * 60 * 60 * 1000 // 80 days
|
||||||
|
).toISOString(),
|
||||||
|
|
||||||
|
// Location (same farm, different area)
|
||||||
|
fromLocation: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060,
|
||||||
|
locationType: 'farm',
|
||||||
|
facilityName: 'Brooklyn Urban Farm - Seed Storage'
|
||||||
|
},
|
||||||
|
toLocation: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060,
|
||||||
|
locationType: 'greenhouse',
|
||||||
|
facilityName: 'Brooklyn Urban Farm - Greenhouse'
|
||||||
|
},
|
||||||
|
|
||||||
|
transportMethod: 'walking',
|
||||||
|
distanceKm: 0.05,
|
||||||
|
durationMinutes: 5,
|
||||||
|
|
||||||
|
senderId: 'grower-brooklyn-001',
|
||||||
|
receiverId: 'grower-brooklyn-001',
|
||||||
|
status: 'verified'
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch('/api/transport/planting', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(plantingEvent)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data: block } = await response.json();
|
||||||
|
console.log('Planting recorded:', block.hash);
|
||||||
|
console.log('Plants created:', plantingEvent.plantIds.length);
|
||||||
|
// Output: 25 plants now tracked on blockchain
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 3: Track Growing Transport (Optional)
|
||||||
|
|
||||||
|
### Record Transplanting
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 3 weeks later - transplant to final positions
|
||||||
|
|
||||||
|
// POST /api/transport/growing
|
||||||
|
|
||||||
|
const transplantEvent = {
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
eventType: 'growing_transport',
|
||||||
|
|
||||||
|
// Which plants
|
||||||
|
plantIds: plantingEvent.plantIds,
|
||||||
|
|
||||||
|
// Transplant details
|
||||||
|
reason: 'transplant',
|
||||||
|
plantStage: 'seedling',
|
||||||
|
handlingMethod: 'potted',
|
||||||
|
rootDisturbance: 'minimal',
|
||||||
|
acclimatizationRequired: true,
|
||||||
|
acclimatizationDays: 3,
|
||||||
|
|
||||||
|
// Location (greenhouse to outdoor beds)
|
||||||
|
fromLocation: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060,
|
||||||
|
locationType: 'greenhouse',
|
||||||
|
facilityName: 'Brooklyn Urban Farm - Greenhouse'
|
||||||
|
},
|
||||||
|
toLocation: {
|
||||||
|
latitude: 40.7125,
|
||||||
|
longitude: -74.0055,
|
||||||
|
locationType: 'farm',
|
||||||
|
facilityName: 'Brooklyn Urban Farm - Plot A'
|
||||||
|
},
|
||||||
|
|
||||||
|
transportMethod: 'walking',
|
||||||
|
distanceKm: 0.1,
|
||||||
|
durationMinutes: 30,
|
||||||
|
|
||||||
|
// Environmental conditions during move
|
||||||
|
environmentalConditions: {
|
||||||
|
temperatureMin: 18,
|
||||||
|
temperatureMax: 24,
|
||||||
|
temperatureAvg: 21,
|
||||||
|
humidityMin: 50,
|
||||||
|
humidityMax: 70,
|
||||||
|
humidityAvg: 60,
|
||||||
|
lightExposure: 'ambient'
|
||||||
|
},
|
||||||
|
|
||||||
|
senderId: 'grower-brooklyn-001',
|
||||||
|
receiverId: 'grower-brooklyn-001',
|
||||||
|
status: 'verified'
|
||||||
|
};
|
||||||
|
|
||||||
|
await fetch('/api/transport/growing', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(transplantEvent)
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 4: Harvest
|
||||||
|
|
||||||
|
### Record Harvest Event
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 80 days from planting - harvest time!
|
||||||
|
|
||||||
|
// POST /api/transport/harvest
|
||||||
|
|
||||||
|
const harvestEvent = {
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
eventType: 'harvest',
|
||||||
|
|
||||||
|
// Which plants
|
||||||
|
plantIds: plantingEvent.plantIds,
|
||||||
|
harvestBatchId: 'harvest-tomato-2024-001',
|
||||||
|
|
||||||
|
// Harvest details
|
||||||
|
harvestType: 'partial', // More to come
|
||||||
|
produceType: 'tomatoes',
|
||||||
|
|
||||||
|
// Quantities
|
||||||
|
grossWeight: 45, // kg
|
||||||
|
netWeight: 42, // after culls
|
||||||
|
weightUnit: 'kg',
|
||||||
|
itemCount: 180, // individual tomatoes
|
||||||
|
|
||||||
|
// Quality
|
||||||
|
qualityGrade: 'A',
|
||||||
|
qualityNotes: 'Excellent color, firm texture, no blemishes',
|
||||||
|
|
||||||
|
// Storage requirements
|
||||||
|
packagingType: 'cardboard flats',
|
||||||
|
temperatureRequired: {
|
||||||
|
min: 10,
|
||||||
|
max: 15,
|
||||||
|
optimal: 12,
|
||||||
|
unit: 'celsius'
|
||||||
|
},
|
||||||
|
shelfLifeHours: 168, // 1 week
|
||||||
|
|
||||||
|
// Seed saving!
|
||||||
|
seedsSaved: true,
|
||||||
|
seedBatchIdCreated: 'seeds-tomato-2024-002', // Next generation!
|
||||||
|
|
||||||
|
// Location
|
||||||
|
fromLocation: {
|
||||||
|
latitude: 40.7125,
|
||||||
|
longitude: -74.0055,
|
||||||
|
locationType: 'farm',
|
||||||
|
facilityName: 'Brooklyn Urban Farm - Plot A'
|
||||||
|
},
|
||||||
|
toLocation: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060,
|
||||||
|
locationType: 'warehouse',
|
||||||
|
facilityName: 'Brooklyn Urban Farm - Pack House'
|
||||||
|
},
|
||||||
|
|
||||||
|
transportMethod: 'walking',
|
||||||
|
distanceKm: 0.1,
|
||||||
|
durationMinutes: 45,
|
||||||
|
|
||||||
|
senderId: 'grower-brooklyn-001',
|
||||||
|
receiverId: 'grower-brooklyn-001',
|
||||||
|
status: 'verified'
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch('/api/transport/harvest', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(harvestEvent)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data: block } = await response.json();
|
||||||
|
console.log('Harvest recorded:', block.hash);
|
||||||
|
console.log('Next generation seeds:', harvestEvent.seedBatchIdCreated);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 5: View the Journey
|
||||||
|
|
||||||
|
### Get Complete Plant Journey
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// GET /api/transport/journey/plant-tomato-2024-001
|
||||||
|
|
||||||
|
const response = await fetch('/api/transport/journey/plant-tomato-2024-001');
|
||||||
|
const { data: journey } = await response.json();
|
||||||
|
|
||||||
|
console.log(journey);
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
plantId: 'plant-tomato-2024-001',
|
||||||
|
seedBatchOrigin: 'seeds-tomato-2024-001',
|
||||||
|
currentCustodian: 'grower-brooklyn-001',
|
||||||
|
currentLocation: {
|
||||||
|
facilityName: 'Brooklyn Urban Farm - Pack House',
|
||||||
|
city: 'Brooklyn'
|
||||||
|
},
|
||||||
|
currentStage: 'post_harvest',
|
||||||
|
|
||||||
|
events: [
|
||||||
|
{ eventType: 'seed_acquisition', ... },
|
||||||
|
{ eventType: 'planting', ... },
|
||||||
|
{ eventType: 'growing_transport', ... },
|
||||||
|
{ eventType: 'harvest', ... }
|
||||||
|
],
|
||||||
|
|
||||||
|
totalFoodMiles: 350.25, // km
|
||||||
|
totalCarbonKg: 1.75,
|
||||||
|
daysInTransit: 1,
|
||||||
|
daysGrowing: 80,
|
||||||
|
|
||||||
|
generation: 1,
|
||||||
|
ancestorPlantIds: [],
|
||||||
|
descendantSeedBatches: ['seeds-tomato-2024-002']
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Environmental Impact
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// GET /api/transport/footprint/grower-brooklyn-001
|
||||||
|
|
||||||
|
const response = await fetch('/api/transport/footprint/grower-brooklyn-001');
|
||||||
|
const { data: impact } = await response.json();
|
||||||
|
|
||||||
|
console.log(impact);
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
totalCarbonKg: 1.75,
|
||||||
|
totalFoodMiles: 350.25,
|
||||||
|
carbonPerKgProduce: 0.042, // Very low!
|
||||||
|
|
||||||
|
comparisonToConventional: {
|
||||||
|
carbonSaved: 103.25, // kg CO2
|
||||||
|
milesSaved: 62649.75, // miles
|
||||||
|
percentageReduction: 98 // Amazing!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate QR Code
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// GET /api/transport/qr/plant-tomato-2024-001
|
||||||
|
|
||||||
|
const response = await fetch('/api/transport/qr/plant-tomato-2024-001');
|
||||||
|
const { data: qrData } = await response.json();
|
||||||
|
|
||||||
|
console.log(qrData);
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
plantId: 'plant-tomato-2024-001',
|
||||||
|
blockchainAddress: '000abc123def456789...',
|
||||||
|
quickLookupUrl: 'https://localgreenchain.org/track/plant-tomato-2024-001',
|
||||||
|
lineageHash: 'a1b2c3d4e5f6',
|
||||||
|
currentCustodian: 'grower-brooklyn-001',
|
||||||
|
lastEventType: 'harvest',
|
||||||
|
lastEventTimestamp: '2024-08-15T10:00:00Z',
|
||||||
|
verificationCode: 'A1B2C3D4'
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Consumer scans QR code → sees complete journey
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complete Code Example
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Full workflow in one script
|
||||||
|
|
||||||
|
import { TransportChain, getTransportChain } from '@/lib/transport/tracker';
|
||||||
|
|
||||||
|
async function seedToHarvestWorkflow() {
|
||||||
|
// Initialize chain
|
||||||
|
const chain = getTransportChain();
|
||||||
|
|
||||||
|
// Step 1: Acquire seeds
|
||||||
|
const seedEvent = createSeedAcquisitionEvent();
|
||||||
|
const seedBlock = chain.recordEvent(seedEvent);
|
||||||
|
console.log('Seeds acquired, block:', seedBlock.hash);
|
||||||
|
|
||||||
|
// Step 2: Plant
|
||||||
|
const plantEvent = createPlantingEvent(seedEvent.seedBatchId);
|
||||||
|
const plantBlock = chain.recordEvent(plantEvent);
|
||||||
|
console.log('Planted, block:', plantBlock.hash);
|
||||||
|
|
||||||
|
// Step 3: Transplant (optional)
|
||||||
|
const transplantEvent = createTransplantEvent(plantEvent.plantIds);
|
||||||
|
const transplantBlock = chain.recordEvent(transplantEvent);
|
||||||
|
console.log('Transplanted, block:', transplantBlock.hash);
|
||||||
|
|
||||||
|
// Step 4: Harvest
|
||||||
|
const harvestEvent = createHarvestEvent(plantEvent.plantIds);
|
||||||
|
const harvestBlock = chain.recordEvent(harvestEvent);
|
||||||
|
console.log('Harvested, block:', harvestBlock.hash);
|
||||||
|
|
||||||
|
// Get journey for first plant
|
||||||
|
const journey = chain.getPlantJourney(plantEvent.plantIds[0]);
|
||||||
|
console.log('Journey:', journey);
|
||||||
|
|
||||||
|
// Get environmental impact
|
||||||
|
const impact = chain.getEnvironmentalImpact('grower-brooklyn-001');
|
||||||
|
console.log('Impact:', impact);
|
||||||
|
|
||||||
|
// Verify chain integrity
|
||||||
|
const isValid = chain.isChainValid();
|
||||||
|
console.log('Chain valid:', isValid); // true
|
||||||
|
|
||||||
|
return {
|
||||||
|
seedBatchId: seedEvent.seedBatchId,
|
||||||
|
plantIds: plantEvent.plantIds,
|
||||||
|
harvestBatchId: harvestEvent.harvestBatchId,
|
||||||
|
nextGeneration: harvestEvent.seedBatchIdCreated,
|
||||||
|
journey,
|
||||||
|
impact
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run it!
|
||||||
|
seedToHarvestWorkflow()
|
||||||
|
.then(result => console.log('Complete!', result))
|
||||||
|
.catch(console.error);
|
||||||
|
```
|
||||||
|
|
||||||
|
## What Happens Next?
|
||||||
|
|
||||||
|
### Distribution
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Continue the chain with distribution...
|
||||||
|
POST /api/transport/distribution
|
||||||
|
{
|
||||||
|
batchIds: ['harvest-tomato-2024-001'],
|
||||||
|
destinationType: 'farmers_market',
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Next Generation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// The cycle continues with saved seeds...
|
||||||
|
POST /api/transport/seed-acquisition
|
||||||
|
{
|
||||||
|
seedBatchId: 'seeds-tomato-2024-002', // From this harvest
|
||||||
|
sourceType: 'previous_harvest',
|
||||||
|
generation: 2, // Second generation!
|
||||||
|
geneticLineageId: 'lineage-cherokee-purple-001',
|
||||||
|
parentPlantIds: ['plant-tomato-2024-001', 'plant-tomato-2024-005'],
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The seed-to-seed cycle is complete!
|
||||||
498
docs/examples/vertical-farm-setup.md
Normal file
498
docs/examples/vertical-farm-setup.md
Normal file
|
|
@ -0,0 +1,498 @@
|
||||||
|
# Example: Vertical Farm Setup
|
||||||
|
|
||||||
|
Complete workflow for setting up and operating a vertical farm with LocalGreenChain.
|
||||||
|
|
||||||
|
## Scenario
|
||||||
|
|
||||||
|
You're setting up a 400 sqm vertical farm to grow lettuce, basil, and microgreens year-round.
|
||||||
|
|
||||||
|
## Step 1: Register Your Farm
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// POST /api/vertical-farm/register
|
||||||
|
|
||||||
|
const farmRegistration = {
|
||||||
|
name: 'Urban Greens VF',
|
||||||
|
ownerId: 'operator-001',
|
||||||
|
|
||||||
|
location: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060,
|
||||||
|
address: '500 Industrial Way',
|
||||||
|
city: 'Brooklyn',
|
||||||
|
country: 'USA',
|
||||||
|
timezone: 'America/New_York'
|
||||||
|
},
|
||||||
|
|
||||||
|
specs: {
|
||||||
|
totalAreaSqm: 500,
|
||||||
|
growingAreaSqm: 400,
|
||||||
|
numberOfLevels: 4,
|
||||||
|
ceilingHeightM: 4,
|
||||||
|
totalGrowingPositions: 5000,
|
||||||
|
currentActivePlants: 0,
|
||||||
|
powerCapacityKw: 150,
|
||||||
|
waterStorageL: 10000,
|
||||||
|
backupPowerHours: 24,
|
||||||
|
certifications: ['gap', 'local_food_safety'],
|
||||||
|
buildingType: 'warehouse',
|
||||||
|
insulation: 'high_efficiency'
|
||||||
|
},
|
||||||
|
|
||||||
|
automationLevel: 'semi_automated'
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch('/api/vertical-farm/register', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(farmRegistration)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data: farm } = await response.json();
|
||||||
|
console.log('Farm registered:', farm.id);
|
||||||
|
console.log('Status:', farm.status); // 'operational'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 2: Configure Growing Zones
|
||||||
|
|
||||||
|
Create zones for different crops:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Zone A: Lettuce (NFT system)
|
||||||
|
const zoneA = {
|
||||||
|
name: 'Zone A - Lettuce',
|
||||||
|
level: 1,
|
||||||
|
areaSqm: 150,
|
||||||
|
lengthM: 30,
|
||||||
|
widthM: 5,
|
||||||
|
growingMethod: 'NFT',
|
||||||
|
plantPositions: 1800,
|
||||||
|
|
||||||
|
environmentTargets: {
|
||||||
|
temperatureC: { min: 18, max: 24, target: 21 },
|
||||||
|
humidityPercent: { min: 55, max: 75, target: 65 },
|
||||||
|
co2Ppm: { min: 800, max: 1400, target: 1000 },
|
||||||
|
lightPpfd: { min: 200, max: 400, target: 300 },
|
||||||
|
lightHours: 16,
|
||||||
|
nutrientEc: { min: 1.2, max: 1.8, target: 1.5 },
|
||||||
|
nutrientPh: { min: 5.5, max: 6.5, target: 6.0 },
|
||||||
|
waterTempC: { min: 18, max: 22, target: 20 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Zone B: Basil (DWC system)
|
||||||
|
const zoneB = {
|
||||||
|
name: 'Zone B - Basil',
|
||||||
|
level: 2,
|
||||||
|
areaSqm: 100,
|
||||||
|
lengthM: 20,
|
||||||
|
widthM: 5,
|
||||||
|
growingMethod: 'DWC',
|
||||||
|
plantPositions: 1200,
|
||||||
|
|
||||||
|
environmentTargets: {
|
||||||
|
temperatureC: { min: 20, max: 28, target: 24 },
|
||||||
|
humidityPercent: { min: 50, max: 70, target: 60 },
|
||||||
|
co2Ppm: { min: 800, max: 1400, target: 1200 },
|
||||||
|
lightPpfd: { min: 300, max: 500, target: 400 },
|
||||||
|
lightHours: 18,
|
||||||
|
nutrientEc: { min: 1.0, max: 1.6, target: 1.3 },
|
||||||
|
nutrientPh: { min: 5.5, max: 6.5, target: 6.0 },
|
||||||
|
waterTempC: { min: 18, max: 22, target: 20 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Zone C: Microgreens (Rack system)
|
||||||
|
const zoneC = {
|
||||||
|
name: 'Zone C - Microgreens',
|
||||||
|
level: 3,
|
||||||
|
areaSqm: 100,
|
||||||
|
lengthM: 20,
|
||||||
|
widthM: 5,
|
||||||
|
growingMethod: 'rack_system',
|
||||||
|
plantPositions: 2000, // Tray positions
|
||||||
|
|
||||||
|
environmentTargets: {
|
||||||
|
temperatureC: { min: 18, max: 24, target: 21 },
|
||||||
|
humidityPercent: { min: 60, max: 80, target: 70 },
|
||||||
|
co2Ppm: { min: 600, max: 1200, target: 800 },
|
||||||
|
lightPpfd: { min: 150, max: 300, target: 250 },
|
||||||
|
lightHours: 16,
|
||||||
|
nutrientEc: { min: 0.5, max: 1.0, target: 0.8 },
|
||||||
|
nutrientPh: { min: 5.5, max: 6.5, target: 6.0 },
|
||||||
|
waterTempC: { min: 18, max: 22, target: 20 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create zones
|
||||||
|
for (const zone of [zoneA, zoneB, zoneC]) {
|
||||||
|
await fetch(`/api/vertical-farm/${farm.id}/zones`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(zone)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Zones configured: Lettuce, Basil, Microgreens');
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 3: View Available Recipes
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// GET /api/vertical-farm/recipes
|
||||||
|
|
||||||
|
const response = await fetch('/api/vertical-farm/recipes');
|
||||||
|
const { data: recipes } = await response.json();
|
||||||
|
|
||||||
|
console.log('Available recipes:');
|
||||||
|
for (const recipe of recipes) {
|
||||||
|
console.log(`- ${recipe.name}`);
|
||||||
|
console.log(` Crop: ${recipe.cropType}`);
|
||||||
|
console.log(` Days: ${recipe.expectedDays}`);
|
||||||
|
console.log(` Yield: ${recipe.expectedYieldGrams}g per plant`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Available recipes:
|
||||||
|
- Butterhead Lettuce - Fast Cycle
|
||||||
|
Crop: lettuce
|
||||||
|
Days: 35
|
||||||
|
Yield: 180g per plant
|
||||||
|
|
||||||
|
- Genovese Basil - Aromatic
|
||||||
|
Crop: basil
|
||||||
|
Days: 42
|
||||||
|
Yield: 120g per plant
|
||||||
|
|
||||||
|
- Microgreens Mix - Quick Turn
|
||||||
|
Crop: microgreens
|
||||||
|
Days: 14
|
||||||
|
Yield: 200g per tray
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 4: Start Crop Batches
|
||||||
|
|
||||||
|
### Link to Seed Source
|
||||||
|
|
||||||
|
First, ensure seeds are tracked in the transport chain:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Record seed acquisition (see seed-to-harvest example)
|
||||||
|
await fetch('/api/transport/seed-acquisition', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
seedBatchId: 'seeds-lettuce-vf-001',
|
||||||
|
sourceType: 'purchase',
|
||||||
|
species: 'Lactuca sativa',
|
||||||
|
quantity: 10000,
|
||||||
|
quantityUnit: 'seeds',
|
||||||
|
// ... other fields
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Start Lettuce Batch
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// POST /api/vertical-farm/batch/start
|
||||||
|
|
||||||
|
const lettuceBatch = {
|
||||||
|
farmId: farm.id,
|
||||||
|
zoneId: 'zone-a-id',
|
||||||
|
recipeId: 'recipe-lettuce-butterhead',
|
||||||
|
seedBatchId: 'seeds-lettuce-vf-001', // Links to transport chain!
|
||||||
|
plantCount: 200
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch('/api/vertical-farm/batch/start', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(lettuceBatch)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data: batch } = await response.json();
|
||||||
|
|
||||||
|
console.log('Batch started:', batch.id);
|
||||||
|
console.log('Expected harvest:', batch.expectedHarvestDate);
|
||||||
|
console.log('Expected yield:', batch.expectedYieldKg, 'kg');
|
||||||
|
console.log('Plant IDs:', batch.plantIds.length, 'plants tracked');
|
||||||
|
|
||||||
|
/*
|
||||||
|
Batch started: batch-lettuce-001
|
||||||
|
Expected harvest: 2024-07-06
|
||||||
|
Expected yield: 36 kg
|
||||||
|
Plant IDs: 200 plants tracked
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Start Microgreens Batch
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const microgreensBatch = {
|
||||||
|
farmId: farm.id,
|
||||||
|
zoneId: 'zone-c-id',
|
||||||
|
recipeId: 'recipe-microgreens-mix',
|
||||||
|
seedBatchId: 'seeds-microgreens-001',
|
||||||
|
plantCount: 50 // 50 trays
|
||||||
|
};
|
||||||
|
|
||||||
|
await fetch('/api/vertical-farm/batch/start', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(microgreensBatch)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Microgreens harvest in just 14 days!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 5: Report Environment Data
|
||||||
|
|
||||||
|
Set up automated reporting from your control system:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Environmental monitoring script
|
||||||
|
|
||||||
|
async function reportEnvironment() {
|
||||||
|
// Collect sensor data
|
||||||
|
const readings = await collectSensorData('zone-a-id');
|
||||||
|
|
||||||
|
// PUT /api/vertical-farm/batch/{batchId}/environment
|
||||||
|
const response = await fetch(`/api/vertical-farm/batch/${batch.id}/environment`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${API_KEY}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
temperatureC: readings.temperature, // 21.5
|
||||||
|
humidityPercent: readings.humidity, // 68
|
||||||
|
co2Ppm: readings.co2, // 1050
|
||||||
|
vpd: readings.vpd, // 0.85
|
||||||
|
ppfd: readings.ppfd, // 295
|
||||||
|
dli: readings.dli, // 17.0
|
||||||
|
waterTempC: readings.waterTemp, // 19.5
|
||||||
|
ec: readings.ec, // 1.55
|
||||||
|
ph: readings.ph, // 6.1
|
||||||
|
dissolvedOxygenPpm: readings.do, // 8.2
|
||||||
|
airflowMs: readings.airflow // 0.5
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data } = await response.json();
|
||||||
|
|
||||||
|
// Handle any alerts
|
||||||
|
if (data.alerts && data.alerts.length > 0) {
|
||||||
|
console.log('ALERTS:', data.alerts);
|
||||||
|
for (const alert of data.alerts) {
|
||||||
|
handleAlert(alert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Environment recorded. Health score:', data.healthScore);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report every 5 minutes
|
||||||
|
setInterval(reportEnvironment, 5 * 60 * 1000);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 6: Monitor Batch Progress
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Check batch status daily
|
||||||
|
|
||||||
|
async function checkBatchProgress(batchId: string) {
|
||||||
|
// GET /api/vertical-farm/batch/{batchId}
|
||||||
|
const response = await fetch(`/api/vertical-farm/batch/${batchId}`);
|
||||||
|
const { data: batch } = await response.json();
|
||||||
|
|
||||||
|
console.log(`
|
||||||
|
Batch: ${batch.id}
|
||||||
|
Crop: ${batch.cropType}
|
||||||
|
Day: ${batch.currentDay} / ${batch.expectedDays}
|
||||||
|
Stage: ${batch.currentStage}
|
||||||
|
Health: ${batch.healthScore}%
|
||||||
|
Status: ${batch.status}
|
||||||
|
Expected Harvest: ${batch.expectedHarvestDate}
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Check for issues
|
||||||
|
if (batch.issues.length > 0) {
|
||||||
|
console.log('ISSUES:');
|
||||||
|
for (const issue of batch.issues) {
|
||||||
|
console.log(`- ${issue.type}: ${issue.description}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Approaching harvest?
|
||||||
|
const daysToHarvest = batch.expectedDays - batch.currentDay;
|
||||||
|
if (daysToHarvest <= 3) {
|
||||||
|
console.log('ALERT: Prepare for harvest in', daysToHarvest, 'days');
|
||||||
|
}
|
||||||
|
|
||||||
|
return batch;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 7: Complete Harvest
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// POST /api/vertical-farm/batch/{batchId}/harvest
|
||||||
|
|
||||||
|
const harvestData = {
|
||||||
|
actualYieldKg: 38.5, // Exceeded expectation!
|
||||||
|
qualityGrade: 'A',
|
||||||
|
notes: 'Excellent crop. Slight overperformance due to optimal conditions.'
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch(`/api/vertical-farm/batch/${batch.id}/harvest`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(harvestData)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data: harvestResult } = await response.json();
|
||||||
|
|
||||||
|
console.log('Harvest completed!');
|
||||||
|
console.log('Actual yield:', harvestResult.actualYieldKg, 'kg');
|
||||||
|
console.log('Expected yield:', harvestResult.expectedYieldKg, 'kg');
|
||||||
|
console.log('Variance:', harvestResult.yieldVariance, '%');
|
||||||
|
console.log('Quality grade:', harvestResult.qualityGrade);
|
||||||
|
|
||||||
|
/*
|
||||||
|
This automatically:
|
||||||
|
1. Records harvest in transport chain
|
||||||
|
2. Links to seed origin (full traceability)
|
||||||
|
3. Updates batch status to 'completed'
|
||||||
|
4. Frees zone for next batch
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 8: View Analytics
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// GET /api/vertical-farm/{farmId}/analytics?period=30
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`/api/vertical-farm/${farm.id}/analytics?period=30`
|
||||||
|
);
|
||||||
|
const { data: analytics } = await response.json();
|
||||||
|
|
||||||
|
console.log(`
|
||||||
|
=== FARM ANALYTICS (30 days) ===
|
||||||
|
|
||||||
|
PRODUCTION
|
||||||
|
Total Yield: ${analytics.totalYieldKg} kg
|
||||||
|
Yield/sqm/year: ${analytics.yieldPerSqmPerYear} kg
|
||||||
|
Cycles Completed: ${analytics.cropCyclesCompleted}
|
||||||
|
Avg Cycle Length: ${analytics.averageCyclesDays} days
|
||||||
|
|
||||||
|
QUALITY
|
||||||
|
Avg Health Score: ${analytics.averageQualityScore}
|
||||||
|
Grade A: ${analytics.gradeAPercent}%
|
||||||
|
Wastage: ${analytics.wastagePercent}%
|
||||||
|
|
||||||
|
EFFICIENCY
|
||||||
|
Success Rate: ${analytics.cropSuccessRate}%
|
||||||
|
Space Utilization: ${analytics.spaceUtilization}%
|
||||||
|
Labor Hours/kg: ${analytics.laborHoursPerKg}
|
||||||
|
|
||||||
|
FINANCIAL
|
||||||
|
Revenue: $${analytics.revenueUsd}
|
||||||
|
Cost: $${analytics.costUsd}
|
||||||
|
Profit Margin: ${analytics.profitMarginPercent}%
|
||||||
|
Revenue/sqm: $${analytics.revenuePerSqm}
|
||||||
|
|
||||||
|
ENVIRONMENTAL
|
||||||
|
Carbon/kg: ${analytics.carbonFootprintKgPerKg} kg CO2
|
||||||
|
Water/kg: ${analytics.waterUseLPerKg} L
|
||||||
|
Energy/kg: ${analytics.energyUseKwhPerKg} kWh
|
||||||
|
|
||||||
|
TOP PERFORMERS
|
||||||
|
By Yield: ${analytics.topCropsByYield.map(c => c.crop).join(', ')}
|
||||||
|
By Revenue: ${analytics.topCropsByRevenue.map(c => c.crop).join(', ')}
|
||||||
|
`);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complete Setup Script
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// vertical-farm-setup.ts
|
||||||
|
|
||||||
|
import { getVerticalFarmController } from '@/lib/vertical-farming/controller';
|
||||||
|
|
||||||
|
async function setupVerticalFarm() {
|
||||||
|
const controller = getVerticalFarmController();
|
||||||
|
|
||||||
|
// 1. Register farm
|
||||||
|
const farm = await registerFarm();
|
||||||
|
console.log('Farm registered:', farm.id);
|
||||||
|
|
||||||
|
// 2. Configure zones
|
||||||
|
const zones = await configureZones(farm.id);
|
||||||
|
console.log('Zones configured:', zones.length);
|
||||||
|
|
||||||
|
// 3. View recipes
|
||||||
|
const recipes = controller.getRecipes();
|
||||||
|
console.log('Available recipes:', recipes.length);
|
||||||
|
|
||||||
|
// 4. Start batches for each zone
|
||||||
|
const batches = [];
|
||||||
|
for (const zone of zones) {
|
||||||
|
const recipe = selectRecipeForZone(zone, recipes);
|
||||||
|
const batch = controller.startCropBatch(
|
||||||
|
farm.id,
|
||||||
|
zone.id,
|
||||||
|
recipe.id,
|
||||||
|
`seeds-${recipe.cropType}-001`,
|
||||||
|
calculatePlantCount(zone, recipe)
|
||||||
|
);
|
||||||
|
batches.push(batch);
|
||||||
|
console.log(`Started ${recipe.cropType} in ${zone.name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Set up monitoring
|
||||||
|
setupEnvironmentMonitoring(batches);
|
||||||
|
|
||||||
|
// 6. Schedule harvest checks
|
||||||
|
scheduleHarvestAlerts(batches);
|
||||||
|
|
||||||
|
return { farm, zones, batches };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run setup
|
||||||
|
setupVerticalFarm()
|
||||||
|
.then(({ farm, zones, batches }) => {
|
||||||
|
console.log('\n=== SETUP COMPLETE ===');
|
||||||
|
console.log(`Farm: ${farm.name}`);
|
||||||
|
console.log(`Zones: ${zones.length}`);
|
||||||
|
console.log(`Active batches: ${batches.length}`);
|
||||||
|
})
|
||||||
|
.catch(console.error);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production Schedule
|
||||||
|
|
||||||
|
With continuous operation:
|
||||||
|
|
||||||
|
```
|
||||||
|
Week 1: Start lettuce batch A (200 plants)
|
||||||
|
Week 2: Start microgreens batch A (50 trays), basil batch A (150 plants)
|
||||||
|
Week 3: Harvest microgreens A, start microgreens B
|
||||||
|
Week 4: Harvest microgreens B, start microgreens C
|
||||||
|
Week 5: Harvest lettuce A, start lettuce B
|
||||||
|
Week 6: Harvest microgreens C, basil A, start new batches
|
||||||
|
...
|
||||||
|
|
||||||
|
Continuous harvest = continuous revenue!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Metrics to Track
|
||||||
|
|
||||||
|
| Metric | Target | Actual |
|
||||||
|
|--------|--------|--------|
|
||||||
|
| Yield/sqm/year | 60 kg | 65 kg |
|
||||||
|
| Energy/kg | 20 kWh | 15 kWh |
|
||||||
|
| Water/kg | 5 L | 4.5 L |
|
||||||
|
| Profit margin | 40% | 50% |
|
||||||
|
| Success rate | 95% | 98% |
|
||||||
303
docs/guides/configuration.md
Normal file
303
docs/guides/configuration.md
Normal file
|
|
@ -0,0 +1,303 @@
|
||||||
|
# Configuration Guide
|
||||||
|
|
||||||
|
Complete guide to configuring LocalGreenChain for your environment.
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
### Core Settings
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Server Configuration
|
||||||
|
PORT=3001 # HTTP port (default: 3001)
|
||||||
|
NODE_ENV=development # development, production, test
|
||||||
|
HOST=0.0.0.0 # Bind address
|
||||||
|
|
||||||
|
# Application
|
||||||
|
APP_NAME=LocalGreenChain # Application name
|
||||||
|
LOG_LEVEL=info # debug, info, warn, error
|
||||||
|
```
|
||||||
|
|
||||||
|
### Blockchain Settings
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Mining Configuration
|
||||||
|
BLOCKCHAIN_DIFFICULTY=3 # Proof-of-work difficulty (1-6)
|
||||||
|
AUTO_MINE=true # Auto-mine new blocks
|
||||||
|
|
||||||
|
# Chain Storage
|
||||||
|
CHAIN_FILE=data/plantchain.json
|
||||||
|
TRANSPORT_FILE=data/transport.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### API Keys
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Plant Identification
|
||||||
|
PLANTS_NET_API_KEY=your_key # plants.net API for plant ID
|
||||||
|
|
||||||
|
# Geocoding
|
||||||
|
GEOCODING_PROVIDER=nominatim # nominatim, google, mapbox
|
||||||
|
GOOGLE_MAPS_API_KEY= # If using Google
|
||||||
|
MAPBOX_TOKEN= # If using Mapbox
|
||||||
|
```
|
||||||
|
|
||||||
|
### Privacy Settings
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Tor Integration
|
||||||
|
TOR_ENABLED=false # Enable Tor hidden service
|
||||||
|
TOR_SOCKS_PORT=9050 # Tor SOCKS proxy port
|
||||||
|
TOR_CONTROL_PORT=9051 # Tor control port
|
||||||
|
|
||||||
|
# Location Privacy
|
||||||
|
LOCATION_PRIVACY=city # exact, fuzzy, city, country, hidden
|
||||||
|
LOCATION_FUZZ_RADIUS_KM=5 # Radius for fuzzy locations
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# File Storage (default)
|
||||||
|
STORAGE_TYPE=file
|
||||||
|
DATA_DIR=./data
|
||||||
|
|
||||||
|
# PostgreSQL (optional)
|
||||||
|
DATABASE_URL=postgresql://user:pass@localhost:5432/localgreenchain
|
||||||
|
|
||||||
|
# Redis Cache (optional)
|
||||||
|
REDIS_URL=redis://localhost:6379
|
||||||
|
CACHE_TTL=3600 # Cache TTL in seconds
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vertical Farming
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Default Farm Settings
|
||||||
|
VF_DEFAULT_RECIPE=lettuce-butterhead
|
||||||
|
VF_ALERT_THRESHOLD=0.1 # Alert when 10% outside targets
|
||||||
|
VF_LOG_INTERVAL=300 # Environment log interval (seconds)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Demand Forecasting
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Forecaster Settings
|
||||||
|
FORECAST_HORIZON_WEEKS=12 # Default forecast period
|
||||||
|
DEMAND_AGGREGATION_RADIUS=50 # Default radius in km
|
||||||
|
MIN_CONSUMERS_FOR_SIGNAL=5 # Minimum consumers for signal
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration Files
|
||||||
|
|
||||||
|
### .env File Structure
|
||||||
|
|
||||||
|
Create `.env` in project root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# LocalGreenChain Configuration
|
||||||
|
# Copy from .env.example and customize
|
||||||
|
|
||||||
|
#=== Server ===#
|
||||||
|
PORT=3001
|
||||||
|
NODE_ENV=development
|
||||||
|
|
||||||
|
#=== Blockchain ===#
|
||||||
|
BLOCKCHAIN_DIFFICULTY=3
|
||||||
|
|
||||||
|
#=== Privacy ===#
|
||||||
|
TOR_ENABLED=false
|
||||||
|
LOCATION_PRIVACY=city
|
||||||
|
|
||||||
|
#=== External APIs ===#
|
||||||
|
PLANTS_NET_API_KEY=
|
||||||
|
|
||||||
|
#=== Features ===#
|
||||||
|
ENABLE_TRANSPORT=true
|
||||||
|
ENABLE_DEMAND=true
|
||||||
|
ENABLE_VERTICAL_FARM=true
|
||||||
|
```
|
||||||
|
|
||||||
|
### TypeScript Configuration
|
||||||
|
|
||||||
|
`tsconfig.json` settings:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ESNext",
|
||||||
|
"strict": true,
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./*"],
|
||||||
|
"@lib/*": ["./lib/*"],
|
||||||
|
"@components/*": ["./components/*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Next.js Configuration
|
||||||
|
|
||||||
|
`next.config.js` options:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
module.exports = {
|
||||||
|
reactStrictMode: true,
|
||||||
|
swcMinify: true,
|
||||||
|
|
||||||
|
// API timeout
|
||||||
|
serverRuntimeConfig: {
|
||||||
|
apiTimeout: 30000
|
||||||
|
},
|
||||||
|
|
||||||
|
// Environment exposure
|
||||||
|
publicRuntimeConfig: {
|
||||||
|
appName: process.env.APP_NAME
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feature Toggles
|
||||||
|
|
||||||
|
Enable or disable specific features:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Core Features
|
||||||
|
ENABLE_TRANSPORT=true # Transport tracking
|
||||||
|
ENABLE_DEMAND=true # Demand forecasting
|
||||||
|
ENABLE_VERTICAL_FARM=true # Vertical farm integration
|
||||||
|
ENABLE_ENVIRONMENTAL=true # Environmental tracking
|
||||||
|
|
||||||
|
# Privacy Features
|
||||||
|
ENABLE_TOR=false # Tor hidden service
|
||||||
|
ENABLE_ANONYMOUS=true # Anonymous registration
|
||||||
|
|
||||||
|
# Experimental
|
||||||
|
ENABLE_AI_FORECAST=false # AI-powered forecasting
|
||||||
|
ENABLE_GENETICS=false # Genetic tracking
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Settings
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Session Management
|
||||||
|
SESSION_SECRET=your-secret-key-here
|
||||||
|
SESSION_TTL=86400 # Session lifetime (seconds)
|
||||||
|
|
||||||
|
# Rate Limiting
|
||||||
|
RATE_LIMIT_WINDOW=60000 # Window in ms
|
||||||
|
RATE_LIMIT_MAX=100 # Max requests per window
|
||||||
|
```
|
||||||
|
|
||||||
|
### CORS Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Allowed Origins
|
||||||
|
CORS_ORIGINS=http://localhost:3000,https://yourdomain.com
|
||||||
|
|
||||||
|
# CORS Options
|
||||||
|
CORS_CREDENTIALS=true
|
||||||
|
CORS_MAX_AGE=86400
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Tuning
|
||||||
|
|
||||||
|
### For Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Fast iteration
|
||||||
|
BLOCKCHAIN_DIFFICULTY=1 # Quick mining
|
||||||
|
LOG_LEVEL=debug # Verbose logging
|
||||||
|
CACHE_TTL=0 # No caching
|
||||||
|
```
|
||||||
|
|
||||||
|
### For Production
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Optimized performance
|
||||||
|
BLOCKCHAIN_DIFFICULTY=4 # More secure
|
||||||
|
LOG_LEVEL=warn # Minimal logging
|
||||||
|
CACHE_TTL=3600 # 1 hour cache
|
||||||
|
NODE_ENV=production # Production optimizations
|
||||||
|
```
|
||||||
|
|
||||||
|
## Multi-Environment Setup
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
`.env.development`:
|
||||||
|
```bash
|
||||||
|
PORT=3001
|
||||||
|
NODE_ENV=development
|
||||||
|
BLOCKCHAIN_DIFFICULTY=2
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
```
|
||||||
|
|
||||||
|
### Staging
|
||||||
|
|
||||||
|
`.env.staging`:
|
||||||
|
```bash
|
||||||
|
PORT=3001
|
||||||
|
NODE_ENV=staging
|
||||||
|
BLOCKCHAIN_DIFFICULTY=3
|
||||||
|
LOG_LEVEL=info
|
||||||
|
DATABASE_URL=postgresql://...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production
|
||||||
|
|
||||||
|
`.env.production`:
|
||||||
|
```bash
|
||||||
|
PORT=3001
|
||||||
|
NODE_ENV=production
|
||||||
|
BLOCKCHAIN_DIFFICULTY=4
|
||||||
|
LOG_LEVEL=warn
|
||||||
|
DATABASE_URL=postgresql://...
|
||||||
|
REDIS_URL=redis://...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Docker Environment
|
||||||
|
|
||||||
|
### Docker Compose Override
|
||||||
|
|
||||||
|
`docker-compose.override.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
environment:
|
||||||
|
- PORT=3001
|
||||||
|
- NODE_ENV=production
|
||||||
|
- BLOCKCHAIN_DIFFICULTY=4
|
||||||
|
volumes:
|
||||||
|
- ./data:/app/data
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
### Check Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Validate environment
|
||||||
|
bun run config:check
|
||||||
|
|
||||||
|
# Test configuration
|
||||||
|
bun run test:config
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Errors
|
||||||
|
|
||||||
|
| Error | Cause | Solution |
|
||||||
|
|-------|-------|----------|
|
||||||
|
| `Missing API key` | PLANTS_NET_API_KEY not set | Add key or disable feature |
|
||||||
|
| `Invalid difficulty` | Value out of range | Use 1-6 |
|
||||||
|
| `Database connection failed` | Wrong DATABASE_URL | Check credentials |
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [Installation Guide](./installation.md) - Complete setup
|
||||||
|
- [Grower Guide](./grower-guide.md) - Start growing
|
||||||
|
- [Transport Guide](./transport-guide.md) - Track transport
|
||||||
352
docs/guides/consumer-guide.md
Normal file
352
docs/guides/consumer-guide.md
Normal file
|
|
@ -0,0 +1,352 @@
|
||||||
|
# Consumer Guide
|
||||||
|
|
||||||
|
How to use LocalGreenChain to find, purchase, and track local produce.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Create Your Profile
|
||||||
|
|
||||||
|
Register as a consumer to receive personalized recommendations:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Consumer profile
|
||||||
|
{
|
||||||
|
consumerId: "consumer-uuid",
|
||||||
|
location: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060,
|
||||||
|
maxDeliveryRadiusKm: 25,
|
||||||
|
city: "Brooklyn"
|
||||||
|
},
|
||||||
|
householdSize: 4,
|
||||||
|
weeklyBudget: 75
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setting Your Preferences
|
||||||
|
|
||||||
|
### Food Preferences
|
||||||
|
|
||||||
|
Tell us what you like:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/demand/preferences
|
||||||
|
|
||||||
|
{
|
||||||
|
consumerId: "your-id",
|
||||||
|
|
||||||
|
// Dietary needs
|
||||||
|
dietaryType: ["vegetarian"],
|
||||||
|
allergies: ["peanuts"],
|
||||||
|
dislikes: ["cilantro"],
|
||||||
|
|
||||||
|
// What you want
|
||||||
|
preferredCategories: [
|
||||||
|
"leafy_greens",
|
||||||
|
"herbs",
|
||||||
|
"nightshades"
|
||||||
|
],
|
||||||
|
|
||||||
|
preferredItems: [
|
||||||
|
{
|
||||||
|
produceType: "tomato",
|
||||||
|
priority: "must_have",
|
||||||
|
weeklyQuantity: 2, // kg
|
||||||
|
seasonalOnly: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
produceType: "lettuce",
|
||||||
|
priority: "preferred",
|
||||||
|
weeklyQuantity: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
produceType: "basil",
|
||||||
|
priority: "nice_to_have"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// Quality preferences
|
||||||
|
certificationPreferences: ["organic", "local"],
|
||||||
|
freshnessImportance: 5, // 1-5 scale
|
||||||
|
priceImportance: 3,
|
||||||
|
sustainabilityImportance: 5,
|
||||||
|
|
||||||
|
// Delivery
|
||||||
|
deliveryPreferences: {
|
||||||
|
method: ["home_delivery", "farmers_market"],
|
||||||
|
frequency: "weekly",
|
||||||
|
preferredDays: ["saturday"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Priority Levels Explained
|
||||||
|
|
||||||
|
| Priority | Meaning | System Behavior |
|
||||||
|
|----------|---------|-----------------|
|
||||||
|
| `must_have` | Essential items | Prioritizes matching these first |
|
||||||
|
| `preferred` | Strong preference | Tries to include when possible |
|
||||||
|
| `nice_to_have` | Would enjoy | Adds if supply available |
|
||||||
|
| `occasional` | Sometimes interested | Suggests opportunistically |
|
||||||
|
|
||||||
|
## Finding Local Produce
|
||||||
|
|
||||||
|
### Browse Available Produce
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/plants/nearby?lat=40.7128&lon=-74.0060&radius=25
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Grower Profiles
|
||||||
|
|
||||||
|
Each grower shows:
|
||||||
|
- Location and distance from you
|
||||||
|
- Available produce
|
||||||
|
- Certifications (organic, etc.)
|
||||||
|
- Delivery methods
|
||||||
|
- Customer ratings
|
||||||
|
|
||||||
|
### Check Seasonal Availability
|
||||||
|
|
||||||
|
```
|
||||||
|
SPRING (Mar-May)
|
||||||
|
├── Lettuce ✓ Available locally
|
||||||
|
├── Spinach ✓ Available locally
|
||||||
|
├── Peas ✓ Limited supply
|
||||||
|
└── Tomatoes ✗ Not in season
|
||||||
|
|
||||||
|
SUMMER (Jun-Aug)
|
||||||
|
├── Tomatoes ✓ Peak availability
|
||||||
|
├── Peppers ✓ Available locally
|
||||||
|
├── Basil ✓ Abundant
|
||||||
|
└── Cucumbers ✓ Available locally
|
||||||
|
```
|
||||||
|
|
||||||
|
## Understanding Plant History
|
||||||
|
|
||||||
|
### Scanning QR Codes
|
||||||
|
|
||||||
|
Every item from LocalGreenChain has a QR code. Scan to see:
|
||||||
|
|
||||||
|
1. **Complete Journey** - From seed to your table
|
||||||
|
2. **Growing Conditions** - Environment during growth
|
||||||
|
3. **Transport History** - Every movement tracked
|
||||||
|
4. **Carbon Footprint** - Environmental impact
|
||||||
|
5. **Grower Info** - Who grew it and where
|
||||||
|
|
||||||
|
### What You'll See
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"plantId": "lgc_abc123",
|
||||||
|
"journey": {
|
||||||
|
"seedOrigin": "Heritage Seed Bank",
|
||||||
|
"grower": "Green Valley Farm",
|
||||||
|
"location": "Brooklyn, NY",
|
||||||
|
"distance": "12 miles from you",
|
||||||
|
"harvestDate": "2024-08-01",
|
||||||
|
"daysFromHarvest": 1
|
||||||
|
},
|
||||||
|
"environmental": {
|
||||||
|
"growingMethod": "greenhouse",
|
||||||
|
"certifications": ["organic"],
|
||||||
|
"carbonFootprint": "0.15 kg CO2/kg",
|
||||||
|
"waterUsage": "10% of conventional"
|
||||||
|
},
|
||||||
|
"lineage": {
|
||||||
|
"generation": 3,
|
||||||
|
"parentPlantIds": ["plant-parent-001"],
|
||||||
|
"variety": "Cherokee Purple Heirloom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ordering and Delivery
|
||||||
|
|
||||||
|
### Place an Order
|
||||||
|
|
||||||
|
Match with available supply:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/demand/match
|
||||||
|
|
||||||
|
{
|
||||||
|
consumerId: "your-id",
|
||||||
|
supplyCommitmentId: "supply-123",
|
||||||
|
produceType: "tomato",
|
||||||
|
matchedQuantityKg: 2,
|
||||||
|
deliveryDate: "2024-08-03",
|
||||||
|
deliveryMethod: "home_delivery"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Delivery Options
|
||||||
|
|
||||||
|
| Method | Description | Typical Cost |
|
||||||
|
|--------|-------------|--------------|
|
||||||
|
| `home_delivery` | Direct to your door | $$ |
|
||||||
|
| `pickup_point` | Central pickup location | $ |
|
||||||
|
| `farmers_market` | Weekly market booth | Free |
|
||||||
|
| `csa_distribution` | CSA share pickup | Subscription |
|
||||||
|
|
||||||
|
### Track Your Delivery
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/transport/journey/order-123
|
||||||
|
```
|
||||||
|
|
||||||
|
Real-time updates on:
|
||||||
|
- Current location
|
||||||
|
- Estimated arrival
|
||||||
|
- Temperature during transport
|
||||||
|
- Handler information
|
||||||
|
|
||||||
|
## Providing Feedback
|
||||||
|
|
||||||
|
### Rate Your Experience
|
||||||
|
|
||||||
|
After receiving produce:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/feedback
|
||||||
|
|
||||||
|
{
|
||||||
|
orderId: "order-123",
|
||||||
|
rating: 5,
|
||||||
|
qualityScore: 5,
|
||||||
|
freshnessScore: 5,
|
||||||
|
feedback: "Absolutely fresh, arrived within hours of harvest!"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Report Issues
|
||||||
|
|
||||||
|
If something isn't right:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/feedback/issue
|
||||||
|
|
||||||
|
{
|
||||||
|
orderId: "order-123",
|
||||||
|
issueType: "quality",
|
||||||
|
description: "Lettuce was wilted on arrival",
|
||||||
|
photos: ["url-to-photo"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environmental Impact
|
||||||
|
|
||||||
|
### Your Personal Impact
|
||||||
|
|
||||||
|
Track your contribution to sustainable agriculture:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/consumer/impact/your-id
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"totalPurchasesKg": 45,
|
||||||
|
"carbonSavedKg": 112,
|
||||||
|
"milesSaved": 67500,
|
||||||
|
"waterSavedLiters": 4500,
|
||||||
|
"localGrowersSupported": 8,
|
||||||
|
"comparisonToConventional": {
|
||||||
|
"carbonReduction": "89%",
|
||||||
|
"waterReduction": "90%",
|
||||||
|
"foodMilesReduction": "97%"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Understanding the Numbers
|
||||||
|
|
||||||
|
| Your Purchase | Conventional | LocalGreenChain | Savings |
|
||||||
|
|---------------|--------------|-----------------|---------|
|
||||||
|
| 1 kg tomatoes | 2.8 kg CO2 | 0.3 kg CO2 | 2.5 kg |
|
||||||
|
| Food miles | 1,500 miles | 12 miles | 1,488 mi |
|
||||||
|
| Water use | 50 liters | 5 liters | 45 L |
|
||||||
|
|
||||||
|
## Seasonal Planning
|
||||||
|
|
||||||
|
### Subscribe to Updates
|
||||||
|
|
||||||
|
Get notified when your favorites become available:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/consumer/alerts
|
||||||
|
|
||||||
|
{
|
||||||
|
produceType: "strawberry",
|
||||||
|
alertType: "in_season",
|
||||||
|
notification: "email"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Seasonal Calendar
|
||||||
|
|
||||||
|
Plan your eating around what's fresh:
|
||||||
|
|
||||||
|
```
|
||||||
|
JAN: Microgreens, Sprouts, Winter Greens
|
||||||
|
FEB: Microgreens, Early Sprouts
|
||||||
|
MAR: Lettuce, Spinach, Radishes
|
||||||
|
APR: Spring Greens, Peas, Herbs
|
||||||
|
MAY: Strawberries, Asparagus, Greens
|
||||||
|
JUN: Early Tomatoes, Cucumbers, Basil
|
||||||
|
JUL: Peak Tomatoes, Peppers, Corn
|
||||||
|
AUG: Melons, Squash, Late Tomatoes
|
||||||
|
SEP: Apples, Winter Squash, Kale
|
||||||
|
OCT: Root Vegetables, Late Greens
|
||||||
|
NOV: Storage Crops, Greens
|
||||||
|
DEC: Winter Storage, Microgreens
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### For Best Quality
|
||||||
|
|
||||||
|
1. **Order In Season** - Peak flavor and nutrition
|
||||||
|
2. **Accept Some Variation** - Farm-fresh isn't uniform
|
||||||
|
3. **Plan Ahead** - Pre-order for best selection
|
||||||
|
4. **Store Properly** - Follow storage guidelines
|
||||||
|
|
||||||
|
### For Maximum Impact
|
||||||
|
|
||||||
|
1. **Buy Local First** - Lower carbon footprint
|
||||||
|
2. **Support Small Growers** - Build community
|
||||||
|
3. **Accept Imperfect** - Reduce food waste
|
||||||
|
4. **Provide Feedback** - Help improve the system
|
||||||
|
|
||||||
|
### For Community
|
||||||
|
|
||||||
|
1. **Share with Neighbors** - Group orders reduce delivery
|
||||||
|
2. **Attend Markets** - Meet your growers
|
||||||
|
3. **Spread the Word** - Grow the network
|
||||||
|
4. **Save Seeds** - Close the loop
|
||||||
|
|
||||||
|
## Frequently Asked Questions
|
||||||
|
|
||||||
|
### How fresh is the produce?
|
||||||
|
|
||||||
|
Most items are harvested within 24-48 hours of delivery. The blockchain record shows exact harvest time.
|
||||||
|
|
||||||
|
### Is everything organic?
|
||||||
|
|
||||||
|
Not all growers are certified organic, but all practices are transparent. Check certifications in the plant profile.
|
||||||
|
|
||||||
|
### What if my order is wrong?
|
||||||
|
|
||||||
|
Contact support immediately. All issues are tracked and resolved. Our blockchain ensures accountability.
|
||||||
|
|
||||||
|
### Can I request specific varieties?
|
||||||
|
|
||||||
|
Yes! Set preferences for specific varieties. Growers see demand signals and may grow what you request.
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [Grower Guide](./grower-guide.md) - Understand how your food is grown
|
||||||
|
- [Transport Guide](./transport-guide.md) - Learn about the journey
|
||||||
|
- [Quick Start](./quick-start.md) - Get started immediately
|
||||||
359
docs/guides/grower-guide.md
Normal file
359
docs/guides/grower-guide.md
Normal file
|
|
@ -0,0 +1,359 @@
|
||||||
|
# Grower Guide
|
||||||
|
|
||||||
|
Complete workflow guide for growers using LocalGreenChain.
|
||||||
|
|
||||||
|
## Getting Started as a Grower
|
||||||
|
|
||||||
|
### 1. Register Your Account
|
||||||
|
|
||||||
|
Navigate to the registration page and create your grower profile:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Grower profile includes
|
||||||
|
{
|
||||||
|
id: "grower-uuid",
|
||||||
|
name: "Green Valley Farm",
|
||||||
|
location: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060,
|
||||||
|
city: "Brooklyn",
|
||||||
|
region: "New York"
|
||||||
|
},
|
||||||
|
capacity: {
|
||||||
|
outdoorSqMeters: 500,
|
||||||
|
greenhouseSqMeters: 200,
|
||||||
|
verticalFarmSqMeters: 0
|
||||||
|
},
|
||||||
|
certifications: ["organic", "local"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Set Up Your Growing Locations
|
||||||
|
|
||||||
|
Register each growing location:
|
||||||
|
|
||||||
|
- Outdoor plots
|
||||||
|
- Greenhouses
|
||||||
|
- Indoor growing areas
|
||||||
|
- Vertical farm zones (if applicable)
|
||||||
|
|
||||||
|
## Plant Registration Workflow
|
||||||
|
|
||||||
|
### Register Seeds
|
||||||
|
|
||||||
|
When you receive or save seeds, create a seed acquisition record:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Example: Register seed acquisition
|
||||||
|
POST /api/transport/seed-acquisition
|
||||||
|
|
||||||
|
{
|
||||||
|
seedBatchId: "seeds-tomato-2024-001",
|
||||||
|
sourceType: "purchase", // or "previous_harvest", "trade", "gift"
|
||||||
|
species: "Solanum lycopersicum",
|
||||||
|
variety: "Cherokee Purple",
|
||||||
|
quantity: 500,
|
||||||
|
quantityUnit: "seeds",
|
||||||
|
generation: 1,
|
||||||
|
certifications: ["organic", "heirloom"],
|
||||||
|
fromLocation: {
|
||||||
|
latitude: 38.9072,
|
||||||
|
longitude: -77.0369,
|
||||||
|
locationType: "seed_bank",
|
||||||
|
facilityName: "Heritage Seed Company"
|
||||||
|
},
|
||||||
|
toLocation: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060,
|
||||||
|
locationType: "farm",
|
||||||
|
facilityName: "Green Valley Farm"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Record Planting
|
||||||
|
|
||||||
|
When you plant seeds:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Example: Record planting event
|
||||||
|
POST /api/transport/planting
|
||||||
|
|
||||||
|
{
|
||||||
|
seedBatchId: "seeds-tomato-2024-001",
|
||||||
|
plantIds: ["plant-001", "plant-002", ...], // Auto-generated
|
||||||
|
plantingMethod: "transplant",
|
||||||
|
quantityPlanted: 50,
|
||||||
|
growingEnvironment: "greenhouse",
|
||||||
|
expectedHarvestDate: "2024-08-15",
|
||||||
|
fromLocation: { ... }, // Seed storage
|
||||||
|
toLocation: { ... } // Planting location
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Track Growing Transport
|
||||||
|
|
||||||
|
If you move plants (transplanting, hardening off):
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/transport/growing
|
||||||
|
|
||||||
|
{
|
||||||
|
plantIds: ["plant-001", "plant-002"],
|
||||||
|
reason: "transplant",
|
||||||
|
plantStage: "seedling",
|
||||||
|
handlingMethod: "potted",
|
||||||
|
rootDisturbance: "minimal"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Responding to Demand Signals
|
||||||
|
|
||||||
|
### View Regional Demand
|
||||||
|
|
||||||
|
Check what consumers in your area need:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/demand/signal?lat=40.7128&lon=-74.0060&radius=50
|
||||||
|
```
|
||||||
|
|
||||||
|
Response shows demand gaps:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"demandItems": [
|
||||||
|
{
|
||||||
|
"produceType": "tomato",
|
||||||
|
"weeklyDemandKg": 180,
|
||||||
|
"gapKg": 120,
|
||||||
|
"aggregatePriority": 8,
|
||||||
|
"urgency": "this_week"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"supplyStatus": "shortage"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Planting Recommendations
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/demand/recommendations?
|
||||||
|
growerId=your-id&
|
||||||
|
lat=40.7128&
|
||||||
|
lon=-74.0060&
|
||||||
|
availableSpaceSqm=100&
|
||||||
|
season=summer
|
||||||
|
```
|
||||||
|
|
||||||
|
Response includes actionable recommendations:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
{
|
||||||
|
"produceType": "tomato",
|
||||||
|
"recommendedQuantity": 50,
|
||||||
|
"expectedYieldKg": 400,
|
||||||
|
"projectedRevenue": 1800,
|
||||||
|
"plantByDate": "2024-05-15",
|
||||||
|
"overallRisk": "low",
|
||||||
|
"explanation": "Strong local demand with 120kg weekly gap..."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Commit Supply
|
||||||
|
|
||||||
|
Register your planned production:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/demand/supply
|
||||||
|
|
||||||
|
{
|
||||||
|
produceType: "tomato",
|
||||||
|
variety: "Cherokee Purple",
|
||||||
|
committedQuantityKg: 400,
|
||||||
|
availableFrom: "2024-08-01",
|
||||||
|
availableUntil: "2024-09-30",
|
||||||
|
pricePerKg: 4.50,
|
||||||
|
certifications: ["organic"],
|
||||||
|
deliveryRadiusKm: 50,
|
||||||
|
deliveryMethods: ["grower_delivery", "farmers_market"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Harvesting and Distribution
|
||||||
|
|
||||||
|
### Record Harvest
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/transport/harvest
|
||||||
|
|
||||||
|
{
|
||||||
|
plantIds: ["plant-001", "plant-002", ...],
|
||||||
|
harvestBatchId: "harvest-tomato-2024-001",
|
||||||
|
harvestType: "partial", // or "full", "continuous"
|
||||||
|
produceType: "tomatoes",
|
||||||
|
grossWeight: 45,
|
||||||
|
netWeight: 42,
|
||||||
|
weightUnit: "kg",
|
||||||
|
qualityGrade: "A",
|
||||||
|
shelfLifeHours: 168,
|
||||||
|
seedsSaved: true,
|
||||||
|
seedBatchIdCreated: "seeds-tomato-2024-002"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Distribute to Consumers
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/transport/distribution
|
||||||
|
|
||||||
|
{
|
||||||
|
batchIds: ["harvest-tomato-2024-001"],
|
||||||
|
destinationType: "consumer",
|
||||||
|
orderId: "order-123",
|
||||||
|
customerType: "individual",
|
||||||
|
deliveryWindow: {
|
||||||
|
start: "2024-08-01T09:00:00Z",
|
||||||
|
end: "2024-08-01T12:00:00Z"
|
||||||
|
},
|
||||||
|
transportMethod: "electric_vehicle"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Seed Saving
|
||||||
|
|
||||||
|
### Complete the Cycle
|
||||||
|
|
||||||
|
Save seeds for next generation:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/transport/seed-saving
|
||||||
|
|
||||||
|
{
|
||||||
|
parentPlantIds: ["plant-001", "plant-005", "plant-012"],
|
||||||
|
newSeedBatchId: "seeds-tomato-2024-002",
|
||||||
|
collectionMethod: "wet_seed",
|
||||||
|
seedCount: 250,
|
||||||
|
germinationRate: 92,
|
||||||
|
storageConditions: {
|
||||||
|
temperature: 4,
|
||||||
|
humidity: 30,
|
||||||
|
lightExposure: "dark",
|
||||||
|
containerType: "vacuum_sealed",
|
||||||
|
desiccant: true,
|
||||||
|
estimatedViability: 5
|
||||||
|
},
|
||||||
|
newGenerationNumber: 2,
|
||||||
|
availableForSharing: true,
|
||||||
|
sharingTerms: "trade"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Share Seeds
|
||||||
|
|
||||||
|
Connect with other growers:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/transport/seed-sharing
|
||||||
|
|
||||||
|
{
|
||||||
|
seedBatchId: "seeds-tomato-2024-002",
|
||||||
|
quantityShared: 50,
|
||||||
|
quantityUnit: "seeds",
|
||||||
|
sharingType: "trade",
|
||||||
|
tradeDetails: "Exchanged for 25 seeds of Brandywine",
|
||||||
|
recipientAgreement: true,
|
||||||
|
reportBackRequired: true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Analytics and Optimization
|
||||||
|
|
||||||
|
### View Your Environmental Impact
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/transport/footprint/your-user-id
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"totalCarbonKg": 12.5,
|
||||||
|
"totalFoodMiles": 245,
|
||||||
|
"carbonPerKgProduce": 0.15,
|
||||||
|
"comparisonToConventional": {
|
||||||
|
"carbonSaved": 187.5,
|
||||||
|
"milesSaved": 14755,
|
||||||
|
"percentageReduction": 94
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Track Plant Journeys
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/transport/journey/plant-001
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### For Maximum Impact
|
||||||
|
|
||||||
|
1. **Register Seeds Promptly** - Log as soon as you receive them
|
||||||
|
2. **Track All Movements** - Every transplant, every harvest
|
||||||
|
3. **Save Quality Seeds** - Maintain genetic diversity
|
||||||
|
4. **Respond to Demand** - Check signals weekly
|
||||||
|
5. **Commit Supply Early** - Pre-selling reduces waste
|
||||||
|
|
||||||
|
### For Quality
|
||||||
|
|
||||||
|
1. **Record Environmental Data** - Helps future planning
|
||||||
|
2. **Grade Honestly** - Build consumer trust
|
||||||
|
3. **Meet Delivery Windows** - Reliability matters
|
||||||
|
4. **Handle Gently** - Minimize transport damage
|
||||||
|
|
||||||
|
### For Community
|
||||||
|
|
||||||
|
1. **Share Seeds** - Especially rare varieties
|
||||||
|
2. **Report Results** - Help improve recommendations
|
||||||
|
3. **Connect Locally** - Build grower networks
|
||||||
|
4. **Teach Others** - Expand the ecosystem
|
||||||
|
|
||||||
|
## Data Flow Diagram
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ GROWER WORKFLOW │
|
||||||
|
├─────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||||
|
│ │ SEEDS │───→│ PLANT │───→│ GROW │ │
|
||||||
|
│ │ Acquire │ │ │ │Transport │ │
|
||||||
|
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||||
|
│ ↑ │ │
|
||||||
|
│ │ ▼ │
|
||||||
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||||
|
│ │ SAVE OR │←───│ HARVEST │←───│ MATURE │ │
|
||||||
|
│ │ SHARE │ │ │ │ │ │
|
||||||
|
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ ▼ │
|
||||||
|
│ │ ┌──────────┐ ┌──────────┐ │
|
||||||
|
│ │ │DISTRIBUTE│───→│ CONSUMER │ │
|
||||||
|
│ │ │ │ │ DELIVERY │ │
|
||||||
|
│ │ └──────────┘ └──────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ └──────────→ Next Generation Begins │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [Transport Guide](./transport-guide.md) - Detailed transport tracking
|
||||||
|
- [Vertical Farm Guide](./vertical-farm-guide.md) - Indoor growing
|
||||||
|
- [Consumer Guide](./consumer-guide.md) - Understand your customers
|
||||||
287
docs/guides/installation.md
Normal file
287
docs/guides/installation.md
Normal file
|
|
@ -0,0 +1,287 @@
|
||||||
|
# Installation Guide
|
||||||
|
|
||||||
|
Complete installation instructions for LocalGreenChain.
|
||||||
|
|
||||||
|
## System Requirements
|
||||||
|
|
||||||
|
### Minimum Requirements
|
||||||
|
|
||||||
|
| Component | Requirement |
|
||||||
|
|-----------|-------------|
|
||||||
|
| OS | macOS, Linux, Windows (WSL2) |
|
||||||
|
| Runtime | Bun 1.0+ |
|
||||||
|
| Memory | 2GB RAM |
|
||||||
|
| Storage | 500MB free space |
|
||||||
|
| Node.js | 18+ (optional, Bun preferred) |
|
||||||
|
|
||||||
|
### Recommended
|
||||||
|
|
||||||
|
| Component | Recommendation |
|
||||||
|
|-----------|----------------|
|
||||||
|
| Memory | 4GB+ RAM |
|
||||||
|
| Storage | 2GB+ free space |
|
||||||
|
| CPU | Multi-core processor |
|
||||||
|
|
||||||
|
## Installation Methods
|
||||||
|
|
||||||
|
### Method 1: Bun (Recommended)
|
||||||
|
|
||||||
|
Bun provides the fastest installation and runtime performance.
|
||||||
|
|
||||||
|
#### Install Bun
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# macOS/Linux/WSL
|
||||||
|
curl -fsSL https://bun.sh/install | bash
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
bun --version
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Clone and Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/yourusername/localgreenchain.git
|
||||||
|
cd localgreenchain
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Start Development Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Method 2: npm/Node.js
|
||||||
|
|
||||||
|
If you prefer npm:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/yourusername/localgreenchain.git
|
||||||
|
cd localgreenchain
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Method 3: Docker
|
||||||
|
|
||||||
|
For containerized deployment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone repository
|
||||||
|
git clone https://github.com/yourusername/localgreenchain.git
|
||||||
|
cd localgreenchain
|
||||||
|
|
||||||
|
# Build and run
|
||||||
|
docker build -t localgreenchain .
|
||||||
|
docker run -p 3001:3001 localgreenchain
|
||||||
|
```
|
||||||
|
|
||||||
|
### Method 4: Docker Compose
|
||||||
|
|
||||||
|
For full stack with optional services:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Standard deployment
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# With Tor support
|
||||||
|
docker-compose -f docker-compose.tor.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment Setup
|
||||||
|
|
||||||
|
### Create Environment File
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
### Essential Variables
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Server Configuration
|
||||||
|
PORT=3001
|
||||||
|
NODE_ENV=development
|
||||||
|
|
||||||
|
# API Keys (optional)
|
||||||
|
PLANTS_NET_API_KEY=your_api_key_here
|
||||||
|
|
||||||
|
# Privacy Options
|
||||||
|
TOR_ENABLED=false
|
||||||
|
LOCATION_PRIVACY=city # exact, fuzzy, city, country, hidden
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full Configuration
|
||||||
|
|
||||||
|
See [Configuration Guide](./configuration.md) for all available options.
|
||||||
|
|
||||||
|
## Database Setup
|
||||||
|
|
||||||
|
### Default: JSON File Storage
|
||||||
|
|
||||||
|
LocalGreenChain uses JSON file storage by default:
|
||||||
|
|
||||||
|
```
|
||||||
|
data/
|
||||||
|
├── plantchain.json # Main blockchain
|
||||||
|
├── transport.json # Transport events
|
||||||
|
└── users.json # User data
|
||||||
|
```
|
||||||
|
|
||||||
|
No additional setup required - files are created automatically.
|
||||||
|
|
||||||
|
### Optional: PostgreSQL
|
||||||
|
|
||||||
|
For production deployments with high volume:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install PostgreSQL
|
||||||
|
sudo apt install postgresql
|
||||||
|
|
||||||
|
# Create database
|
||||||
|
createdb localgreenchain
|
||||||
|
|
||||||
|
# Configure in .env
|
||||||
|
DATABASE_URL=postgresql://user:pass@localhost:5432/localgreenchain
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
### Check Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run tests
|
||||||
|
bun test
|
||||||
|
|
||||||
|
# Check build
|
||||||
|
bun run build
|
||||||
|
|
||||||
|
# Verify API
|
||||||
|
curl http://localhost:3001/api/plants/network
|
||||||
|
```
|
||||||
|
|
||||||
|
### Expected Output
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"totalPlants": 0,
|
||||||
|
"chainLength": 1,
|
||||||
|
"difficulty": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Platform-Specific Notes
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install Xcode Command Line Tools if needed
|
||||||
|
xcode-select --install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linux (Ubuntu/Debian)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install build essentials
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install build-essential
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows (WSL2)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Enable WSL2 first
|
||||||
|
wsl --install
|
||||||
|
|
||||||
|
# Then follow Linux instructions inside WSL
|
||||||
|
```
|
||||||
|
|
||||||
|
## Updating
|
||||||
|
|
||||||
|
### Update to Latest Version
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git pull origin main
|
||||||
|
bun install
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Migrate Data
|
||||||
|
|
||||||
|
Data migrations are automatic. Backup before updating:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp -r data/ data-backup/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Uninstallation
|
||||||
|
|
||||||
|
### Remove LocalGreenChain
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stop server
|
||||||
|
# Remove directory
|
||||||
|
rm -rf localgreenchain/
|
||||||
|
|
||||||
|
# Remove global Bun packages (if installed globally)
|
||||||
|
bun remove -g localgreenchain
|
||||||
|
```
|
||||||
|
|
||||||
|
### Keep Data
|
||||||
|
|
||||||
|
To preserve your blockchain data:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp -r data/ ~/localgreenchain-backup/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
#### Bun Installation Fails
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Try alternative installation
|
||||||
|
npm install -g bun
|
||||||
|
|
||||||
|
# Or download binary directly
|
||||||
|
curl -fsSL https://bun.sh/install | bash -s "bun-v1.0.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Port Conflict
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Find process using port
|
||||||
|
lsof -i :3001
|
||||||
|
|
||||||
|
# Kill process
|
||||||
|
kill -9 <PID>
|
||||||
|
|
||||||
|
# Or use different port
|
||||||
|
PORT=3002 bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Permission Denied
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Fix permissions
|
||||||
|
chmod +x node_modules/.bin/*
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Out of Memory
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Increase Node.js memory limit
|
||||||
|
export NODE_OPTIONS="--max-old-space-size=4096"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [Configuration Guide](./configuration.md) - Customize your setup
|
||||||
|
- [Quick Start](./quick-start.md) - Register your first plant
|
||||||
|
- [Grower Guide](./grower-guide.md) - Full grower workflow
|
||||||
149
docs/guides/quick-start.md
Normal file
149
docs/guides/quick-start.md
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
# Quick Start Guide
|
||||||
|
|
||||||
|
Get LocalGreenChain up and running in under 5 minutes.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Bun 1.0+** - Fast JavaScript runtime ([https://bun.sh](https://bun.sh))
|
||||||
|
|
||||||
|
### Installing Bun
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# macOS/Linux/WSL
|
||||||
|
curl -fsSL https://bun.sh/install | bash
|
||||||
|
|
||||||
|
# Or using npm
|
||||||
|
npm install -g bun
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### 1. Clone the Repository
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/yourusername/localgreenchain.git
|
||||||
|
cd localgreenchain
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Install Dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Start the Development Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Open Your Browser
|
||||||
|
|
||||||
|
Navigate to [http://localhost:3001](http://localhost:3001)
|
||||||
|
|
||||||
|
## Your First Plant Registration
|
||||||
|
|
||||||
|
### Step 1: Navigate to Register Page
|
||||||
|
|
||||||
|
Click "Register Plant" in the navigation menu or go directly to `/plants/register`.
|
||||||
|
|
||||||
|
### Step 2: Enter Plant Details
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Example plant data
|
||||||
|
{
|
||||||
|
commonName: "Tomato",
|
||||||
|
scientificName: "Solanum lycopersicum",
|
||||||
|
location: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060,
|
||||||
|
city: "New York",
|
||||||
|
country: "USA"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Submit and View Your Plant
|
||||||
|
|
||||||
|
After registration, you'll receive:
|
||||||
|
- A unique plant ID
|
||||||
|
- A blockchain transaction hash
|
||||||
|
- A QR code for tracking
|
||||||
|
|
||||||
|
## View Your Plant on the Network
|
||||||
|
|
||||||
|
### Check the Explorer
|
||||||
|
|
||||||
|
Navigate to `/plants/explore` to see:
|
||||||
|
- Your registered plants
|
||||||
|
- Network statistics
|
||||||
|
- Nearby plants from other growers
|
||||||
|
|
||||||
|
### View Plant Details
|
||||||
|
|
||||||
|
Click on any plant to see:
|
||||||
|
- Complete lineage history
|
||||||
|
- Transport events
|
||||||
|
- Environmental data
|
||||||
|
- QR code for scanning
|
||||||
|
|
||||||
|
## Quick API Test
|
||||||
|
|
||||||
|
Test the API directly:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Register a plant
|
||||||
|
curl -X POST http://localhost:3001/api/plants/register \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"commonName": "Basil",
|
||||||
|
"scientificName": "Ocimum basilicum",
|
||||||
|
"location": {
|
||||||
|
"latitude": 40.7128,
|
||||||
|
"longitude": -74.0060
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
|
||||||
|
# Get network stats
|
||||||
|
curl http://localhost:3001/api/plants/network
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [Installation Guide](./installation.md) - Detailed setup options
|
||||||
|
- [Configuration Guide](./configuration.md) - Environment variables and settings
|
||||||
|
- [Grower Guide](./grower-guide.md) - Complete workflow for growers
|
||||||
|
- [Consumer Guide](./consumer-guide.md) - How to use as a consumer
|
||||||
|
|
||||||
|
## Common Issues
|
||||||
|
|
||||||
|
### Port Already in Use
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Change port in .env
|
||||||
|
PORT=3002
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bun Not Found
|
||||||
|
|
||||||
|
Ensure Bun is in your PATH:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export BUN_INSTALL="$HOME/.bun"
|
||||||
|
export PATH="$BUN_INSTALL/bin:$PATH"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Reset
|
||||||
|
|
||||||
|
To start fresh:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -rf data/plantchain.json
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Time to complete**: ~5 minutes
|
||||||
|
|
||||||
|
**Support**: Open an issue on GitHub or check [Discussions](https://github.com/yourusername/localgreenchain/discussions)
|
||||||
426
docs/guides/transport-guide.md
Normal file
426
docs/guides/transport-guide.md
Normal file
|
|
@ -0,0 +1,426 @@
|
||||||
|
# Transport Guide
|
||||||
|
|
||||||
|
Complete guide to recording and tracking transport events in LocalGreenChain.
|
||||||
|
|
||||||
|
## Transport Event Types
|
||||||
|
|
||||||
|
LocalGreenChain tracks 9 types of transport events covering the complete seed-to-seed lifecycle:
|
||||||
|
|
||||||
|
| Event Type | Description | When to Use |
|
||||||
|
|------------|-------------|-------------|
|
||||||
|
| `seed_acquisition` | Receiving seeds from any source | Purchasing, trading, or harvesting seeds |
|
||||||
|
| `planting` | Planting seeds or transplanting | Starting new plants |
|
||||||
|
| `growing_transport` | Moving plants during growth | Transplanting, hardening off |
|
||||||
|
| `harvest` | Collecting produce from plants | Harvest day |
|
||||||
|
| `processing` | Processing harvested produce | Washing, cutting, packaging |
|
||||||
|
| `distribution` | Moving to distribution points | To markets, hubs, restaurants |
|
||||||
|
| `consumer_delivery` | Final delivery to consumer | Last mile delivery |
|
||||||
|
| `seed_saving` | Collecting seeds from plants | End of growing cycle |
|
||||||
|
| `seed_sharing` | Sharing seeds with others | Trading, gifting seeds |
|
||||||
|
|
||||||
|
## Recording Transport Events
|
||||||
|
|
||||||
|
### Seed Acquisition
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/transport/seed-acquisition
|
||||||
|
|
||||||
|
{
|
||||||
|
// Required fields
|
||||||
|
seedBatchId: "seeds-tomato-2024-001",
|
||||||
|
sourceType: "purchase", // seed_bank, previous_harvest, trade, purchase, wild_collected, gift
|
||||||
|
species: "Solanum lycopersicum",
|
||||||
|
quantity: 500,
|
||||||
|
quantityUnit: "seeds",
|
||||||
|
generation: 1,
|
||||||
|
|
||||||
|
// Location (from → to)
|
||||||
|
fromLocation: {
|
||||||
|
latitude: 38.9072,
|
||||||
|
longitude: -77.0369,
|
||||||
|
locationType: "seed_bank",
|
||||||
|
facilityName: "Heritage Seeds"
|
||||||
|
},
|
||||||
|
toLocation: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060,
|
||||||
|
locationType: "farm",
|
||||||
|
facilityName: "Green Valley Farm"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Transport details
|
||||||
|
transportMethod: "local_delivery",
|
||||||
|
durationMinutes: 120,
|
||||||
|
|
||||||
|
// Optional details
|
||||||
|
variety: "Cherokee Purple",
|
||||||
|
certifications: ["organic", "heirloom"],
|
||||||
|
germinationRate: 92,
|
||||||
|
harvestDate: "2023-10-15",
|
||||||
|
geneticLineageId: "lineage-abc123"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Planting Event
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/transport/planting
|
||||||
|
|
||||||
|
{
|
||||||
|
seedBatchId: "seeds-tomato-2024-001",
|
||||||
|
plantIds: ["plant-001", "plant-002"], // Can be auto-generated
|
||||||
|
quantityPlanted: 50,
|
||||||
|
plantingMethod: "transplant", // direct_sow, transplant, indoor_start, hydroponic, aeroponic
|
||||||
|
growingEnvironment: "greenhouse", // outdoor, greenhouse, indoor, vertical_farm
|
||||||
|
|
||||||
|
fromLocation: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060,
|
||||||
|
locationType: "greenhouse",
|
||||||
|
facilityName: "Seed Starting House"
|
||||||
|
},
|
||||||
|
toLocation: {
|
||||||
|
latitude: 40.7130,
|
||||||
|
longitude: -74.0065,
|
||||||
|
locationType: "greenhouse",
|
||||||
|
facilityName: "Growing Greenhouse"
|
||||||
|
},
|
||||||
|
|
||||||
|
expectedHarvestDate: "2024-08-15",
|
||||||
|
sowingDepth: 6, // mm
|
||||||
|
spacing: 60 // cm
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Growing Transport
|
||||||
|
|
||||||
|
For transplanting or moving plants:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/transport/growing
|
||||||
|
|
||||||
|
{
|
||||||
|
plantIds: ["plant-001", "plant-002"],
|
||||||
|
reason: "transplant", // transplant, relocation, hardening_off, seasonal_move, upgrade_facility
|
||||||
|
plantStage: "seedling", // seed, germinating, seedling, vegetative, flowering, fruiting, mature
|
||||||
|
handlingMethod: "potted", // bare_root, potted, root_ball, hydroponic_transfer
|
||||||
|
|
||||||
|
rootDisturbance: "minimal", // none, minimal, moderate, significant
|
||||||
|
acclimatizationRequired: true,
|
||||||
|
acclimatizationDays: 7,
|
||||||
|
|
||||||
|
fromLocation: { ... },
|
||||||
|
toLocation: { ... },
|
||||||
|
|
||||||
|
transportMethod: "walking",
|
||||||
|
environmentalConditions: {
|
||||||
|
temperatureMin: 15,
|
||||||
|
temperatureMax: 22,
|
||||||
|
temperatureAvg: 18,
|
||||||
|
humidityMin: 60,
|
||||||
|
humidityMax: 80,
|
||||||
|
humidityAvg: 70,
|
||||||
|
lightExposure: "ambient"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Harvest Event
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/transport/harvest
|
||||||
|
|
||||||
|
{
|
||||||
|
plantIds: ["plant-001", "plant-002"],
|
||||||
|
harvestBatchId: "harvest-2024-001",
|
||||||
|
harvestType: "full", // full, partial, continuous, selective
|
||||||
|
produceType: "tomatoes",
|
||||||
|
|
||||||
|
// Weights
|
||||||
|
grossWeight: 50,
|
||||||
|
netWeight: 47,
|
||||||
|
weightUnit: "kg",
|
||||||
|
itemCount: 200,
|
||||||
|
|
||||||
|
// Quality
|
||||||
|
qualityGrade: "A", // A, B, C, processing
|
||||||
|
qualityNotes: "Excellent color and firmness",
|
||||||
|
|
||||||
|
// Storage requirements
|
||||||
|
packagingType: "cardboard_flat",
|
||||||
|
temperatureRequired: {
|
||||||
|
min: 10,
|
||||||
|
max: 15,
|
||||||
|
optimal: 12,
|
||||||
|
unit: "celsius"
|
||||||
|
},
|
||||||
|
shelfLifeHours: 168,
|
||||||
|
|
||||||
|
// Seed saving
|
||||||
|
seedsSaved: true,
|
||||||
|
seedBatchIdCreated: "seeds-tomato-2024-002",
|
||||||
|
|
||||||
|
fromLocation: { ... },
|
||||||
|
toLocation: { ... }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Distribution Event
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/transport/distribution
|
||||||
|
|
||||||
|
{
|
||||||
|
batchIds: ["harvest-2024-001"],
|
||||||
|
destinationType: "market", // consumer, market, restaurant, processor, distributor, vertical_farm
|
||||||
|
customerType: "business", // individual, business, cooperative, institution
|
||||||
|
|
||||||
|
orderId: "order-456",
|
||||||
|
deliveryWindow: {
|
||||||
|
start: "2024-08-02T06:00:00Z",
|
||||||
|
end: "2024-08-02T08:00:00Z"
|
||||||
|
},
|
||||||
|
deliveryAttempts: 1,
|
||||||
|
handoffVerified: true,
|
||||||
|
recipientName: "Brooklyn Farmers Market",
|
||||||
|
|
||||||
|
transportMethod: "electric_vehicle",
|
||||||
|
fromLocation: { ... },
|
||||||
|
toLocation: { ... }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Seed Saving Event
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/transport/seed-saving
|
||||||
|
|
||||||
|
{
|
||||||
|
parentPlantIds: ["plant-001", "plant-005"],
|
||||||
|
newSeedBatchId: "seeds-tomato-2024-002",
|
||||||
|
|
||||||
|
// Collection details
|
||||||
|
collectionMethod: "wet_seed", // dry_seed, wet_seed, fermentation, threshing
|
||||||
|
seedCount: 250,
|
||||||
|
seedWeight: 15,
|
||||||
|
seedWeightUnit: "grams",
|
||||||
|
|
||||||
|
// Quality testing
|
||||||
|
viabilityTestDate: "2024-08-20",
|
||||||
|
germinationRate: 94,
|
||||||
|
purityPercentage: 98,
|
||||||
|
|
||||||
|
// Storage
|
||||||
|
storageConditions: {
|
||||||
|
temperature: 4,
|
||||||
|
humidity: 30,
|
||||||
|
lightExposure: "dark",
|
||||||
|
containerType: "vacuum_sealed",
|
||||||
|
desiccant: true,
|
||||||
|
estimatedViability: 5 // years
|
||||||
|
},
|
||||||
|
storageLocationId: "storage-vault-001",
|
||||||
|
|
||||||
|
// Lineage
|
||||||
|
newGenerationNumber: 2,
|
||||||
|
geneticNotes: "Selected for disease resistance and flavor",
|
||||||
|
|
||||||
|
// Sharing
|
||||||
|
availableForSharing: true,
|
||||||
|
sharingTerms: "trade"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Carbon Footprint Calculation
|
||||||
|
|
||||||
|
### Carbon Factors by Transport Method
|
||||||
|
|
||||||
|
| Method | kg CO2 per km per kg |
|
||||||
|
|--------|---------------------|
|
||||||
|
| walking | 0 |
|
||||||
|
| bicycle | 0 |
|
||||||
|
| electric_vehicle | 0.02 |
|
||||||
|
| hybrid_vehicle | 0.08 |
|
||||||
|
| gasoline_vehicle | 0.12 |
|
||||||
|
| diesel_truck | 0.15 |
|
||||||
|
| electric_truck | 0.03 |
|
||||||
|
| refrigerated_truck | 0.25 |
|
||||||
|
| rail | 0.01 |
|
||||||
|
| ship | 0.008 |
|
||||||
|
| air | 0.5 |
|
||||||
|
| drone | 0.01 |
|
||||||
|
| local_delivery | 0.05 |
|
||||||
|
| customer_pickup | 0.1 |
|
||||||
|
|
||||||
|
### Calculation Formula
|
||||||
|
|
||||||
|
```
|
||||||
|
Carbon (kg CO2) = Factor × Distance (km) × Weight (kg)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```
|
||||||
|
Tomatoes: 20 kg
|
||||||
|
Distance: 25 km
|
||||||
|
Method: electric_vehicle (factor: 0.02)
|
||||||
|
|
||||||
|
Carbon = 0.02 × 25 × 20 = 10 kg CO2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Querying Transport Data
|
||||||
|
|
||||||
|
### Get Plant Journey
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/transport/journey/plant-001
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"plantId": "plant-001",
|
||||||
|
"seedBatchOrigin": "seeds-tomato-2024-001",
|
||||||
|
"currentStage": "harvesting",
|
||||||
|
"events": [...],
|
||||||
|
"totalFoodMiles": 45,
|
||||||
|
"totalCarbonKg": 2.5,
|
||||||
|
"daysGrowing": 85,
|
||||||
|
"generation": 1,
|
||||||
|
"ancestorPlantIds": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Environmental Impact
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/transport/footprint/user-123
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"totalCarbonKg": 45.5,
|
||||||
|
"totalFoodMiles": 320,
|
||||||
|
"carbonPerKgProduce": 0.18,
|
||||||
|
"breakdownByMethod": {
|
||||||
|
"electric_vehicle": { "distance": 200, "carbon": 20 },
|
||||||
|
"walking": { "distance": 50, "carbon": 0 }
|
||||||
|
},
|
||||||
|
"comparisonToConventional": {
|
||||||
|
"carbonSaved": 580,
|
||||||
|
"milesSaved": 22500,
|
||||||
|
"percentageReduction": 93
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verify Block
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/transport/verify/abc123def456
|
||||||
|
```
|
||||||
|
|
||||||
|
## QR Code Integration
|
||||||
|
|
||||||
|
### Generate QR Data
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/transport/qr/plant-001
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"plantId": "plant-001",
|
||||||
|
"blockchainAddress": "0x1234...",
|
||||||
|
"quickLookupUrl": "https://localgreenchain.org/track/plant-001",
|
||||||
|
"lineageHash": "sha256...",
|
||||||
|
"currentCustodian": "grower-123",
|
||||||
|
"lastEventType": "harvest",
|
||||||
|
"verificationCode": "A1B2C3D4"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Flow Diagram
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ TRANSPORT DATA FLOW │
|
||||||
|
├─────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ ┌───────────┐ │
|
||||||
|
│ │ SEED │ seed_acquisition │
|
||||||
|
│ │ ACQUISITION│────────────┐ │
|
||||||
|
│ └───────────┘ │ │
|
||||||
|
│ │ ▼ │
|
||||||
|
│ │ ┌───────────────┐ │
|
||||||
|
│ │ │ TRANSPORT │ │
|
||||||
|
│ │ │ CHAIN │ │
|
||||||
|
│ │ │ BLOCKCHAIN │ │
|
||||||
|
│ │ └───────┬───────┘ │
|
||||||
|
│ ▼ │ │
|
||||||
|
│ ┌───────────┐ │ │
|
||||||
|
│ │ PLANTING │─────────────┤ planting │
|
||||||
|
│ └───────────┘ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ ▼ │ │
|
||||||
|
│ ┌───────────┐ │ │
|
||||||
|
│ │ GROWING │─────────────┤ growing_transport │
|
||||||
|
│ │ TRANSPORT │ │ │
|
||||||
|
│ └───────────┘ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ ▼ │ │
|
||||||
|
│ ┌───────────┐ │ │
|
||||||
|
│ │ HARVEST │─────────────┤ harvest │
|
||||||
|
│ └───────────┘ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ ├───────────────┐ │ │
|
||||||
|
│ ▼ ▼ │ │
|
||||||
|
│ ┌───────────┐ ┌─────────┐│ │
|
||||||
|
│ │DISTRIBUTE │ │ SEED ││ distribution / seed_saving │
|
||||||
|
│ │ │ │ SAVING ││─────────────────────────────────────────│
|
||||||
|
│ └───────────┘ └─────────┘│ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ ▼ ▼ │ │
|
||||||
|
│ ┌───────────┐ ┌─────────┐│ │
|
||||||
|
│ │ CONSUMER │ │ SEED ││ consumer_delivery / seed_sharing │
|
||||||
|
│ │ DELIVERY │ │ SHARING ││ │
|
||||||
|
│ └───────────┘ └─────────┘│ │
|
||||||
|
│ │ │ │
|
||||||
|
│ └─────┼──→ Next Generation │
|
||||||
|
│ │ │
|
||||||
|
└────────────────────────────┴─────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Recording Events
|
||||||
|
|
||||||
|
1. **Be Timely** - Record events as they happen
|
||||||
|
2. **Be Accurate** - Correct coordinates and weights
|
||||||
|
3. **Be Complete** - Include all optional fields when possible
|
||||||
|
4. **Verify Locations** - Double-check GPS coordinates
|
||||||
|
|
||||||
|
### Transport Methods
|
||||||
|
|
||||||
|
1. **Choose Low Carbon** - Electric and human-powered preferred
|
||||||
|
2. **Combine Trips** - Reduce total distance
|
||||||
|
3. **Optimize Routes** - Shortest path reduces footprint
|
||||||
|
4. **Use Local First** - Minimize distance overall
|
||||||
|
|
||||||
|
### Quality Assurance
|
||||||
|
|
||||||
|
1. **Track Conditions** - Temperature, humidity, handling
|
||||||
|
2. **Note Issues** - Record any problems immediately
|
||||||
|
3. **Grade Honestly** - Accurate quality ratings
|
||||||
|
4. **Verify Handoffs** - Confirm custody changes
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [Grower Guide](./grower-guide.md) - Complete grower workflow
|
||||||
|
- [Consumer Guide](./consumer-guide.md) - Consumer perspective
|
||||||
|
- [Vertical Farm Guide](./vertical-farm-guide.md) - Indoor growing
|
||||||
481
docs/guides/vertical-farm-guide.md
Normal file
481
docs/guides/vertical-farm-guide.md
Normal file
|
|
@ -0,0 +1,481 @@
|
||||||
|
# Vertical Farm Operator Guide
|
||||||
|
|
||||||
|
Complete guide for managing vertical farming operations with LocalGreenChain.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Register Your Farm
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/vertical-farm/register
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "Urban Greens VF",
|
||||||
|
ownerId: "owner-123",
|
||||||
|
|
||||||
|
location: {
|
||||||
|
latitude: 40.7128,
|
||||||
|
longitude: -74.0060,
|
||||||
|
address: "123 Industrial Blvd",
|
||||||
|
city: "Brooklyn",
|
||||||
|
country: "USA",
|
||||||
|
timezone: "America/New_York"
|
||||||
|
},
|
||||||
|
|
||||||
|
specs: {
|
||||||
|
totalAreaSqm: 500,
|
||||||
|
growingAreaSqm: 400,
|
||||||
|
numberOfLevels: 4,
|
||||||
|
ceilingHeightM: 4,
|
||||||
|
totalGrowingPositions: 5000,
|
||||||
|
powerCapacityKw: 150,
|
||||||
|
waterStorageL: 10000,
|
||||||
|
backupPowerHours: 24,
|
||||||
|
certifications: ["gap", "local_food_safety"],
|
||||||
|
buildingType: "warehouse",
|
||||||
|
insulation: "high_efficiency"
|
||||||
|
},
|
||||||
|
|
||||||
|
automationLevel: "semi_automated"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Zone Configuration
|
||||||
|
|
||||||
|
### Create Growing Zones
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/vertical-farm/{farmId}/zones
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "Zone A - Leafy Greens",
|
||||||
|
level: 1,
|
||||||
|
areaSqm: 100,
|
||||||
|
lengthM: 20,
|
||||||
|
widthM: 5,
|
||||||
|
growingMethod: "NFT", // NFT, DWC, ebb_flow, aeroponics, vertical_towers, rack_system
|
||||||
|
plantPositions: 1200,
|
||||||
|
|
||||||
|
environmentTargets: {
|
||||||
|
temperatureC: { min: 18, max: 24, target: 21 },
|
||||||
|
humidityPercent: { min: 55, max: 75, target: 65 },
|
||||||
|
co2Ppm: { min: 800, max: 1400, target: 1000 },
|
||||||
|
lightPpfd: { min: 200, max: 400, target: 300 },
|
||||||
|
lightHours: 16,
|
||||||
|
nutrientEc: { min: 1.2, max: 1.8, target: 1.5 },
|
||||||
|
nutrientPh: { min: 5.5, max: 6.5, target: 6.0 },
|
||||||
|
waterTempC: { min: 18, max: 22, target: 20 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Zone Growing Methods
|
||||||
|
|
||||||
|
| Method | Best For | Water Use | Complexity |
|
||||||
|
|--------|----------|-----------|------------|
|
||||||
|
| NFT | Leafy greens, herbs | Low | Medium |
|
||||||
|
| DWC | Lettuce, basil | Medium | Low |
|
||||||
|
| Aeroponics | High-value crops | Very Low | High |
|
||||||
|
| Vertical Towers | Microgreens, strawberries | Low | Medium |
|
||||||
|
| Rack System | Microgreens | Low | Low |
|
||||||
|
|
||||||
|
## Growing Recipes
|
||||||
|
|
||||||
|
### Available Default Recipes
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/vertical-farm/recipes
|
||||||
|
|
||||||
|
// Returns:
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: "recipe-lettuce-butterhead",
|
||||||
|
name: "Butterhead Lettuce - Fast Cycle",
|
||||||
|
expectedDays: 35,
|
||||||
|
expectedYieldGrams: 180,
|
||||||
|
expectedYieldPerSqm: 4000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "recipe-basil-genovese",
|
||||||
|
name: "Genovese Basil - Aromatic",
|
||||||
|
expectedDays: 42,
|
||||||
|
expectedYieldGrams: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "recipe-microgreens-mix",
|
||||||
|
name: "Microgreens Mix - Quick Turn",
|
||||||
|
expectedDays: 14,
|
||||||
|
expectedYieldGrams: 200
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Recipe Stages
|
||||||
|
|
||||||
|
Each recipe defines stages with specific environment targets:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Lettuce example stages
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: "Germination",
|
||||||
|
daysStart: 0,
|
||||||
|
daysEnd: 3,
|
||||||
|
temperature: { day: 20, night: 18 },
|
||||||
|
humidity: { day: 80, night: 85 },
|
||||||
|
co2Ppm: 800,
|
||||||
|
lightHours: 18,
|
||||||
|
lightPpfd: 150,
|
||||||
|
targetEc: 0.8,
|
||||||
|
targetPh: 6.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Seedling",
|
||||||
|
daysStart: 4,
|
||||||
|
daysEnd: 10,
|
||||||
|
temperature: { day: 21, night: 18 },
|
||||||
|
humidity: { day: 70, night: 75 },
|
||||||
|
lightPpfd: 200,
|
||||||
|
targetEc: 1.2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Vegetative Growth",
|
||||||
|
daysStart: 11,
|
||||||
|
daysEnd: 28,
|
||||||
|
lightPpfd: 300,
|
||||||
|
targetEc: 1.6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Finishing",
|
||||||
|
daysStart: 29,
|
||||||
|
daysEnd: 35,
|
||||||
|
lightPpfd: 250,
|
||||||
|
targetEc: 1.2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Batch Management
|
||||||
|
|
||||||
|
### Start a Crop Batch
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/vertical-farm/batch/start
|
||||||
|
|
||||||
|
{
|
||||||
|
farmId: "farm-123",
|
||||||
|
zoneId: "zone-a",
|
||||||
|
recipeId: "recipe-lettuce-butterhead",
|
||||||
|
seedBatchId: "seeds-lettuce-001",
|
||||||
|
plantCount: 200
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"batchId": "batch-abc123",
|
||||||
|
"plantingDate": "2024-06-01T08:00:00Z",
|
||||||
|
"expectedHarvestDate": "2024-07-06T08:00:00Z",
|
||||||
|
"expectedYieldKg": 36,
|
||||||
|
"plantIds": ["batch-abc123-plant-0", "..."]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Monitor Batch Progress
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/vertical-farm/batch/{batchId}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "batch-abc123",
|
||||||
|
"currentDay": 15,
|
||||||
|
"currentStage": "Vegetative Growth",
|
||||||
|
"healthScore": 95,
|
||||||
|
"status": "growing",
|
||||||
|
"expectedHarvestDate": "2024-07-06",
|
||||||
|
"issues": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Record Environment Readings
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
PUT /api/vertical-farm/batch/{batchId}/environment
|
||||||
|
|
||||||
|
{
|
||||||
|
timestamp: "2024-06-15T12:00:00Z",
|
||||||
|
temperatureC: 21.5,
|
||||||
|
humidityPercent: 68,
|
||||||
|
co2Ppm: 1050,
|
||||||
|
ppfd: 295,
|
||||||
|
dli: 17.0,
|
||||||
|
waterTempC: 19.5,
|
||||||
|
ec: 1.55,
|
||||||
|
ph: 6.1,
|
||||||
|
dissolvedOxygenPpm: 8.2,
|
||||||
|
airflowMs: 0.5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Complete Harvest
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/vertical-farm/batch/{batchId}/harvest
|
||||||
|
|
||||||
|
{
|
||||||
|
actualYieldKg: 38.5,
|
||||||
|
qualityGrade: "A",
|
||||||
|
notes: "Excellent crop, slight overperformance on yield"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment Monitoring
|
||||||
|
|
||||||
|
### Alert Types
|
||||||
|
|
||||||
|
| Alert Type | Trigger | Severity |
|
||||||
|
|------------|---------|----------|
|
||||||
|
| `low` | Below minimum target | Warning |
|
||||||
|
| `high` | Above maximum target | Warning |
|
||||||
|
| `critical_low` | >5 below minimum | Critical |
|
||||||
|
| `critical_high` | >5 above maximum | Critical |
|
||||||
|
| `sensor_fault` | Sensor malfunction | Critical |
|
||||||
|
|
||||||
|
### Alert Response
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ ENVIRONMENT ALERT │
|
||||||
|
├─────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ Parameter: Temperature │
|
||||||
|
│ Current: 28°C │
|
||||||
|
│ Target: 21°C (max: 24°C) │
|
||||||
|
│ Type: HIGH │
|
||||||
|
│ │
|
||||||
|
│ Recommended Actions: │
|
||||||
|
│ 1. Check HVAC system status │
|
||||||
|
│ 2. Verify ventilation is operational │
|
||||||
|
│ 3. Consider reducing light intensity │
|
||||||
|
│ 4. Check for blocked airflow │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health Score Impact
|
||||||
|
|
||||||
|
| Condition | Health Score Impact |
|
||||||
|
|-----------|---------------------|
|
||||||
|
| No alerts | No change |
|
||||||
|
| Minor alert | -1 point |
|
||||||
|
| Critical alert | -5 points |
|
||||||
|
| Extended critical | -10 points/day |
|
||||||
|
|
||||||
|
## Analytics
|
||||||
|
|
||||||
|
### View Farm Analytics
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/vertical-farm/{farmId}/analytics?period=30
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"farmId": "farm-123",
|
||||||
|
"period": "30 days",
|
||||||
|
|
||||||
|
"production": {
|
||||||
|
"totalYieldKg": 450,
|
||||||
|
"yieldPerSqmPerYear": 4100,
|
||||||
|
"cropCyclesCompleted": 12,
|
||||||
|
"averageCycleDays": 28
|
||||||
|
},
|
||||||
|
|
||||||
|
"quality": {
|
||||||
|
"averageQualityScore": 92,
|
||||||
|
"gradeAPercent": 85,
|
||||||
|
"wastagePercent": 4.5
|
||||||
|
},
|
||||||
|
|
||||||
|
"efficiency": {
|
||||||
|
"cropSuccessRate": 98,
|
||||||
|
"spaceUtilization": 88,
|
||||||
|
"laborHoursPerKg": 0.3
|
||||||
|
},
|
||||||
|
|
||||||
|
"financial": {
|
||||||
|
"revenueUsd": 9000,
|
||||||
|
"costUsd": 4500,
|
||||||
|
"profitMarginPercent": 50,
|
||||||
|
"revenuePerSqm": 22.50
|
||||||
|
},
|
||||||
|
|
||||||
|
"environmental": {
|
||||||
|
"carbonFootprintKgPerKg": 0.28,
|
||||||
|
"waterUseLPerKg": 4.5,
|
||||||
|
"energyUseKwhPerKg": 15
|
||||||
|
},
|
||||||
|
|
||||||
|
"topCrops": {
|
||||||
|
"byYield": ["lettuce", "basil", "microgreens"],
|
||||||
|
"byRevenue": ["basil", "lettuce", "microgreens"],
|
||||||
|
"byEfficiency": ["microgreens", "lettuce", "basil"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration with Demand
|
||||||
|
|
||||||
|
### Respond to Demand Signals
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Check regional demand
|
||||||
|
GET /api/demand/signal?lat=40.7128&lon=-74.0060&radius=25
|
||||||
|
|
||||||
|
// Find gaps you can fill
|
||||||
|
{
|
||||||
|
"demandItems": [
|
||||||
|
{
|
||||||
|
"produceType": "lettuce",
|
||||||
|
"gapKg": 50,
|
||||||
|
"urgency": "this_week"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start batch to fill demand
|
||||||
|
POST /api/vertical-farm/batch/start
|
||||||
|
{
|
||||||
|
recipeId: "recipe-lettuce-butterhead",
|
||||||
|
plantCount: 280 // To produce ~50kg
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Commit Supply
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/demand/supply
|
||||||
|
|
||||||
|
{
|
||||||
|
produceType: "lettuce",
|
||||||
|
variety: "butterhead",
|
||||||
|
committedQuantityKg: 50,
|
||||||
|
availableFrom: "2024-07-06",
|
||||||
|
freshnessGuaranteeHours: 24,
|
||||||
|
certifications: ["local_food_safety"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Blockchain Recording
|
||||||
|
|
||||||
|
Every batch creates transport events:
|
||||||
|
|
||||||
|
```
|
||||||
|
Seed Acquisition → Transport recorded
|
||||||
|
↓
|
||||||
|
Planting Event → Transport recorded
|
||||||
|
↓
|
||||||
|
Environment Logs → Stored with batch
|
||||||
|
↓
|
||||||
|
Harvest Event → Transport recorded
|
||||||
|
↓
|
||||||
|
Distribution → Transport recorded
|
||||||
|
```
|
||||||
|
|
||||||
|
Consumers can scan QR codes to see:
|
||||||
|
- Exact growing conditions
|
||||||
|
- Recipe used
|
||||||
|
- Environment history
|
||||||
|
- Seed lineage
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### For Operators
|
||||||
|
|
||||||
|
1. **Calibrate Regularly** - Sensors need weekly checks
|
||||||
|
2. **Follow Recipes** - Don't deviate without reason
|
||||||
|
3. **Log Everything** - Data enables optimization
|
||||||
|
4. **Respond to Alerts** - Quick action prevents losses
|
||||||
|
5. **Maintain Equipment** - Preventive > reactive
|
||||||
|
|
||||||
|
### For Efficiency
|
||||||
|
|
||||||
|
1. **Stagger Batches** - Continuous harvest flow
|
||||||
|
2. **Match Demand** - Check signals before planting
|
||||||
|
3. **Optimize Light** - Biggest energy cost
|
||||||
|
4. **Recirculate Water** - >95% reuse target
|
||||||
|
5. **Track KPIs** - What gets measured improves
|
||||||
|
|
||||||
|
### For Quality
|
||||||
|
|
||||||
|
1. **Start Clean** - Sanitize between batches
|
||||||
|
2. **Monitor Daily** - Catch issues early
|
||||||
|
3. **Harvest at Peak** - Don't over-mature
|
||||||
|
4. **Temperature Chain** - Maintain cold chain
|
||||||
|
5. **Grade Honestly** - Quality builds trust
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
| Issue | Possible Causes | Solutions |
|
||||||
|
|-------|-----------------|-----------|
|
||||||
|
| Low yield | Light too low, nutrients off | Check PPFD, EC levels |
|
||||||
|
| Tip burn | High EC, low calcium | Reduce nutrients, add CalMag |
|
||||||
|
| Bolting | Temperature too high | Reduce temp, increase airflow |
|
||||||
|
| Root rot | Low oxygen, warm water | Add air stones, cool reservoir |
|
||||||
|
| Slow growth | Low CO2, wrong temp | Check CO2 injection, adjust HVAC |
|
||||||
|
|
||||||
|
### Emergency Procedures
|
||||||
|
|
||||||
|
```
|
||||||
|
POWER FAILURE:
|
||||||
|
1. Backup power should engage automatically
|
||||||
|
2. Reduce light intensity if on battery
|
||||||
|
3. Maintain water circulation priority
|
||||||
|
4. Alert on-call technician
|
||||||
|
|
||||||
|
HVAC FAILURE:
|
||||||
|
1. Reduce light intensity immediately
|
||||||
|
2. Open vents for passive cooling
|
||||||
|
3. Mist plants if temperature rising
|
||||||
|
4. Call HVAC service
|
||||||
|
|
||||||
|
WATER LEAK:
|
||||||
|
1. Shut off main water supply
|
||||||
|
2. Isolate affected zone
|
||||||
|
3. Salvage plants if possible
|
||||||
|
4. Document for insurance
|
||||||
|
```
|
||||||
|
|
||||||
|
## Resource Efficiency
|
||||||
|
|
||||||
|
### Energy Optimization
|
||||||
|
|
||||||
|
| Component | % of Total | Optimization |
|
||||||
|
|-----------|------------|--------------|
|
||||||
|
| Lighting | 50-60% | LED efficacy, DLI optimization |
|
||||||
|
| HVAC | 20-30% | Heat pump, recovery systems |
|
||||||
|
| Pumps | 5-10% | Variable speed drives |
|
||||||
|
| Other | 5-10% | Automation, scheduling |
|
||||||
|
|
||||||
|
### Water Conservation
|
||||||
|
|
||||||
|
- Target: >95% water recirculation
|
||||||
|
- Condensate recovery from HVAC
|
||||||
|
- Rainwater collection if available
|
||||||
|
- RO reject water for non-crop use
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [Grower Guide](./grower-guide.md) - Traditional growing
|
||||||
|
- [Transport Guide](./transport-guide.md) - Tracking transport
|
||||||
|
- [Consumer Guide](./consumer-guide.md) - Consumer perspective
|
||||||
436
docs/vertical-farming/automation.md
Normal file
436
docs/vertical-farming/automation.md
Normal file
|
|
@ -0,0 +1,436 @@
|
||||||
|
# Automation Systems
|
||||||
|
|
||||||
|
Automating vertical farm operations for efficiency and consistency.
|
||||||
|
|
||||||
|
## Automation Levels
|
||||||
|
|
||||||
|
### Manual Operation
|
||||||
|
|
||||||
|
```
|
||||||
|
Human → Observe → Decide → Act → Monitor
|
||||||
|
|
||||||
|
Pros: Low cost, flexible
|
||||||
|
Cons: Labor intensive, inconsistent, human error
|
||||||
|
Best for: Small hobbyist operations
|
||||||
|
```
|
||||||
|
|
||||||
|
### Semi-Automated
|
||||||
|
|
||||||
|
```
|
||||||
|
Sensors → Alert → Human Decision → Automated Action
|
||||||
|
|
||||||
|
Pros: Reduced labor, consistent execution
|
||||||
|
Cons: Still requires monitoring, delayed response
|
||||||
|
Best for: Small-medium commercial operations
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fully Automated
|
||||||
|
|
||||||
|
```
|
||||||
|
Sensors → Controller → Algorithm → Action → Verify
|
||||||
|
|
||||||
|
Pros: 24/7 operation, optimal control, data-driven
|
||||||
|
Cons: High upfront cost, requires expertise
|
||||||
|
Best for: Commercial production facilities
|
||||||
|
```
|
||||||
|
|
||||||
|
## Control System Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ AUTOMATION ARCHITECTURE │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ LAYER 4: BUSINESS INTELLIGENCE │
|
||||||
|
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ Analytics │ Forecasting │ Optimization │ Reporting │ │
|
||||||
|
│ └──────────────────────────────────────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ LAYER 3: SUPERVISORY CONTROL │
|
||||||
|
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ Recipe Management │ Scheduling │ Alarm Management │ │
|
||||||
|
│ └──────────────────────────────────────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ LAYER 2: ZONE CONTROLLERS │
|
||||||
|
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
|
||||||
|
│ │ Zone A │ │ Zone B │ │ Zone C │ │ Zone D │ │
|
||||||
|
│ │ Controller │ │ Controller │ │ Controller │ │ Controller │ │
|
||||||
|
│ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ LAYER 1: FIELD DEVICES │
|
||||||
|
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ Sensors │ Actuators │ Valves │ Pumps │ Lights │ HVAC │ │
|
||||||
|
│ └──────────────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Automated Systems
|
||||||
|
|
||||||
|
### Lighting Automation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface LightingAutomation {
|
||||||
|
// Photoperiod control
|
||||||
|
schedule: {
|
||||||
|
onTime: string; // "06:00"
|
||||||
|
offTime: string; // "22:00"
|
||||||
|
rampUp: number; // minutes to full brightness
|
||||||
|
rampDown: number; // minutes to off
|
||||||
|
};
|
||||||
|
|
||||||
|
// Intensity control
|
||||||
|
intensity: {
|
||||||
|
mode: 'fixed' | 'dli_target' | 'adaptive';
|
||||||
|
targetDLI?: number;
|
||||||
|
maxPPFD: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Spectrum control (tunable LEDs)
|
||||||
|
spectrum: {
|
||||||
|
vegetative: { blue: 30, red: 60, farRed: 10 };
|
||||||
|
flowering: { blue: 20, red: 70, farRed: 10 };
|
||||||
|
auto_switch_day?: number; // Day to switch
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Irrigation Automation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IrrigationAutomation {
|
||||||
|
// Timing-based
|
||||||
|
schedule: {
|
||||||
|
intervalsPerDay: number;
|
||||||
|
duration: number; // seconds
|
||||||
|
times: string[]; // ["06:00", "12:00", "18:00"]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sensor-based triggers
|
||||||
|
triggers: {
|
||||||
|
minMoisturePercent?: number; // Start irrigation below this
|
||||||
|
maxMoisturePercent?: number; // Stop irrigation above this
|
||||||
|
ecThreshold?: number; // Flush if EC too high
|
||||||
|
};
|
||||||
|
|
||||||
|
// Flow control
|
||||||
|
flowRate: number; // L/min
|
||||||
|
maxDuration: number; // Safety limit
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nutrient Dosing Automation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface DosingAutomation {
|
||||||
|
targetEC: number;
|
||||||
|
targetPH: number;
|
||||||
|
|
||||||
|
// PID control parameters
|
||||||
|
ec_pid: { kp: 0.5, ki: 0.1, kd: 0.05 };
|
||||||
|
ph_pid: { kp: 0.3, ki: 0.05, kd: 0.02 };
|
||||||
|
|
||||||
|
// Dosing limits
|
||||||
|
maxDoseML: number; // Per adjustment
|
||||||
|
minDoseInterval: number; // Seconds between doses
|
||||||
|
mixTime: number; // Seconds to wait after dosing
|
||||||
|
|
||||||
|
// Stock solution mappings
|
||||||
|
ecUp: string[]; // ["nutrient_a", "nutrient_b"]
|
||||||
|
ecDown: string[]; // ["fresh_water"]
|
||||||
|
phUp: string; // "ph_up"
|
||||||
|
phDown: string; // "ph_down"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Climate Automation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ClimateAutomation {
|
||||||
|
// Temperature control
|
||||||
|
cooling: {
|
||||||
|
stage1_offset: 1; // First stage at target + 1°C
|
||||||
|
stage2_offset: 2;
|
||||||
|
stage3_offset: 3;
|
||||||
|
};
|
||||||
|
heating: {
|
||||||
|
stage1_offset: -1;
|
||||||
|
stage2_offset: -2;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Humidity control
|
||||||
|
humidify_below: number;
|
||||||
|
dehumidify_above: number;
|
||||||
|
|
||||||
|
// CO2 control
|
||||||
|
co2: {
|
||||||
|
inject_below: number;
|
||||||
|
stop_above: number;
|
||||||
|
only_when_lights_on: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ventilation
|
||||||
|
ventilation: {
|
||||||
|
outdoor_temp_min: number; // Don't vent if too cold
|
||||||
|
outdoor_temp_max: number; // Don't vent if too hot
|
||||||
|
humidity_threshold: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Recipe-Driven Automation
|
||||||
|
|
||||||
|
### How Recipes Control Automation
|
||||||
|
|
||||||
|
```
|
||||||
|
Recipe Definition
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────┐
|
||||||
|
│ Current Day │ ─────────→ Stage Lookup
|
||||||
|
│ of Crop Batch │
|
||||||
|
└─────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────┐
|
||||||
|
│ Stage Settings │
|
||||||
|
│ - Temperature │
|
||||||
|
│ - Humidity │
|
||||||
|
│ - Light PPFD │
|
||||||
|
│ - Light hours │
|
||||||
|
│ - EC target │
|
||||||
|
│ - pH target │
|
||||||
|
│ - CO2 level │
|
||||||
|
└────────┬────────┘
|
||||||
|
│
|
||||||
|
┌────────────┴────────────┐
|
||||||
|
▼ ▼
|
||||||
|
┌──────────────┐ ┌──────────────┐
|
||||||
|
│ Update Zone │ │ Update Zone │
|
||||||
|
│ Setpoints │ │ Light Schedule│
|
||||||
|
└──────────────┘ └──────────────┘
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
Controllers adjust Light timers
|
||||||
|
to new targets updated
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stage Transition Automation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function updateBatchStage(batch: CropBatch): void {
|
||||||
|
const recipe = getRecipe(batch.recipeId);
|
||||||
|
const currentDay = calculateDay(batch.plantingDate);
|
||||||
|
|
||||||
|
// Find current stage
|
||||||
|
const stage = recipe.stages.find(s =>
|
||||||
|
currentDay >= s.daysStart && currentDay <= s.daysEnd
|
||||||
|
);
|
||||||
|
|
||||||
|
if (stage && stage.name !== batch.currentStage) {
|
||||||
|
// Stage has changed!
|
||||||
|
batch.currentStage = stage.name;
|
||||||
|
|
||||||
|
// Update zone setpoints
|
||||||
|
updateZoneTargets(batch.zoneId, stage);
|
||||||
|
|
||||||
|
// Trigger any stage actions
|
||||||
|
executeStageActions(batch, stage, currentDay);
|
||||||
|
|
||||||
|
// Log transition
|
||||||
|
logEvent('stage_transition', batch.id, stage.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Robotics Integration
|
||||||
|
|
||||||
|
### Seeding Automation
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ SEEDING AUTOMATION │
|
||||||
|
├─────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ 1. Tray Loading │
|
||||||
|
│ Robot arm places empty trays on conveyor │
|
||||||
|
│ │
|
||||||
|
│ 2. Media Filling │
|
||||||
|
│ Automated hopper fills trays with growing media │
|
||||||
|
│ │
|
||||||
|
│ 3. Seed Placement │
|
||||||
|
│ Precision seeder places seeds at correct spacing │
|
||||||
|
│ Vision system verifies placement │
|
||||||
|
│ │
|
||||||
|
│ 4. Cover/Press │
|
||||||
|
│ Automated press firms seeds into media │
|
||||||
|
│ Vermiculite cover applied │
|
||||||
|
│ │
|
||||||
|
│ 5. Labeling │
|
||||||
|
│ QR code applied linking to blockchain record │
|
||||||
|
│ │
|
||||||
|
│ 6. Transport │
|
||||||
|
│ Automated cart moves to germination zone │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Transplanting Automation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface TransplantRobot {
|
||||||
|
type: 'robotic_arm' | 'gantry' | 'mobile';
|
||||||
|
|
||||||
|
capabilities: {
|
||||||
|
seedlingsPerHour: number;
|
||||||
|
success_rate: number; // 95%+
|
||||||
|
plant_spacing_accuracy: number; // ±2mm
|
||||||
|
};
|
||||||
|
|
||||||
|
integration: {
|
||||||
|
vision_system: boolean; // For plant detection
|
||||||
|
force_feedback: boolean; // Gentle handling
|
||||||
|
api_endpoint: string; // LocalGreenChain integration
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Harvesting Automation
|
||||||
|
|
||||||
|
| Crop Type | Automation Method | Speed | Accuracy |
|
||||||
|
|-----------|-------------------|-------|----------|
|
||||||
|
| Microgreens | Blade cut | Fast | High |
|
||||||
|
| Lettuce | Root cut + vacuum | Medium | High |
|
||||||
|
| Basil | Selective picking | Slow | Medium |
|
||||||
|
| Tomatoes | Vision + gripper | Slow | High |
|
||||||
|
|
||||||
|
## Scheduling System
|
||||||
|
|
||||||
|
### Batch Scheduling
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface BatchScheduler {
|
||||||
|
// Calculate optimal start dates
|
||||||
|
calculatePlantingDate(
|
||||||
|
recipe: GrowingRecipe,
|
||||||
|
targetHarvestDate: Date,
|
||||||
|
zoneAvailability: ZoneCalendar
|
||||||
|
): Date;
|
||||||
|
|
||||||
|
// Optimize zone utilization
|
||||||
|
optimizeZoneAssignment(
|
||||||
|
batches: CropBatch[],
|
||||||
|
zones: GrowingZone[]
|
||||||
|
): Assignment[];
|
||||||
|
|
||||||
|
// Handle conflicts
|
||||||
|
resolveConflicts(
|
||||||
|
pending: CropBatch[],
|
||||||
|
capacity: number
|
||||||
|
): Resolution;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Maintenance Scheduling
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const maintenanceSchedule = {
|
||||||
|
daily: [
|
||||||
|
{ task: 'sensor_check', duration: 15 },
|
||||||
|
{ task: 'visual_inspection', duration: 30 }
|
||||||
|
],
|
||||||
|
weekly: [
|
||||||
|
{ task: 'calibrate_ph', duration: 30 },
|
||||||
|
{ task: 'calibrate_ec', duration: 30 },
|
||||||
|
{ task: 'filter_check', duration: 15 }
|
||||||
|
],
|
||||||
|
monthly: [
|
||||||
|
{ task: 'deep_clean', duration: 240 },
|
||||||
|
{ task: 'sensor_calibration', duration: 60 },
|
||||||
|
{ task: 'equipment_service', duration: 120 }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data-Driven Optimization
|
||||||
|
|
||||||
|
### Machine Learning Integration
|
||||||
|
|
||||||
|
```
|
||||||
|
Historical Data
|
||||||
|
│
|
||||||
|
├── Environmental readings
|
||||||
|
├── Crop performance
|
||||||
|
├── Energy usage
|
||||||
|
└── Yield data
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ ML Models │
|
||||||
|
│ │
|
||||||
|
│ - Yield prediction │
|
||||||
|
│ - Recipe optimization│
|
||||||
|
│ - Anomaly detection │
|
||||||
|
│ - Energy optimization│
|
||||||
|
└─────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────┐
|
||||||
|
│ Recommendations │
|
||||||
|
│ │
|
||||||
|
│ - Adjust setpoints │
|
||||||
|
│ - Modify recipes │
|
||||||
|
│ - Predict issues │
|
||||||
|
└─────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Optimization Targets
|
||||||
|
|
||||||
|
| Metric | Optimization Method |
|
||||||
|
|--------|---------------------|
|
||||||
|
| Yield | Adjust PPFD, DLI, nutrients |
|
||||||
|
| Quality | Fine-tune environment |
|
||||||
|
| Energy | Shift operations off-peak |
|
||||||
|
| Water | Optimize irrigation timing |
|
||||||
|
| Labor | Batch scheduling |
|
||||||
|
|
||||||
|
## API Integration
|
||||||
|
|
||||||
|
### LocalGreenChain Integration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Automation system reports to LocalGreenChain
|
||||||
|
async function reportEnvironment(
|
||||||
|
batchId: string,
|
||||||
|
readings: EnvironmentReading
|
||||||
|
): Promise<void> {
|
||||||
|
await fetch('/api/vertical-farm/batch/{batchId}/environment', {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify(readings)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Automation receives commands from LocalGreenChain
|
||||||
|
async function fetchSetpoints(zoneId: string): Promise<Setpoints> {
|
||||||
|
const response = await fetch(`/api/vertical-farm/zone/${zoneId}/setpoints`);
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Reliability
|
||||||
|
|
||||||
|
1. **Redundancy** - Backup sensors, dual pumps
|
||||||
|
2. **Fail-safes** - Default to safe state on failure
|
||||||
|
3. **Monitoring** - 24/7 alerting
|
||||||
|
4. **Testing** - Regular system tests
|
||||||
|
5. **Documentation** - Keep procedures updated
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
1. **Access control** - Role-based permissions
|
||||||
|
2. **Audit logging** - Track all changes
|
||||||
|
3. **Network security** - Segmented OT network
|
||||||
|
4. **Updates** - Regular firmware patches
|
||||||
|
5. **Backups** - Configuration backups
|
||||||
404
docs/vertical-farming/environmental-control.md
Normal file
404
docs/vertical-farming/environmental-control.md
Normal file
|
|
@ -0,0 +1,404 @@
|
||||||
|
# Environmental Control Systems
|
||||||
|
|
||||||
|
Deep dive into vertical farm environmental management.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Environmental control is the heart of vertical farming. Unlike outdoor agriculture, every parameter is controllable and optimizable.
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ ENVIRONMENTAL CONTROL SYSTEM │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
|
||||||
|
│ │TEMPERATURE │ │ HUMIDITY │ │ CO2 │ │
|
||||||
|
│ │ Control │ │ Control │ │ Control │ │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ │ HVAC │ │ Humidifier │ │ Injection │ │
|
||||||
|
│ │ Heat Pump │ │ Dehumid. │ │ Generator │ │
|
||||||
|
│ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ └─────────────────┼─────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌─────▼─────┐ │
|
||||||
|
│ │ CENTRAL │ │
|
||||||
|
│ │ CONTROLLER│ │
|
||||||
|
│ └─────┬─────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌─────────────────┼─────────────────┐ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ ┌─────▼──────┐ ┌─────▼─────┐ ┌─────▼──────┐ │
|
||||||
|
│ │ LIGHTING │ │ WATER │ │ NUTRIENTS │ │
|
||||||
|
│ │ Control │ │ Control │ │ Control │ │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ │ LEDs │ │ Irrigation │ │ Dosing │ │
|
||||||
|
│ │ Spectrum │ │ pH adjust │ │ EC monitor │ │
|
||||||
|
│ └────────────┘ └────────────┘ └────────────┘ │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Temperature Control
|
||||||
|
|
||||||
|
### Target Ranges by Crop Type
|
||||||
|
|
||||||
|
| Crop Category | Day Temp (°C) | Night Temp (°C) | Differential |
|
||||||
|
|---------------|---------------|-----------------|--------------|
|
||||||
|
| Leafy Greens | 18-22 | 15-18 | 3-5°C |
|
||||||
|
| Herbs | 20-25 | 18-22 | 2-4°C |
|
||||||
|
| Fruiting | 22-28 | 18-22 | 4-6°C |
|
||||||
|
| Microgreens | 18-21 | 16-19 | 2-3°C |
|
||||||
|
|
||||||
|
### Control Strategies
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface TemperatureControl {
|
||||||
|
mode: 'manual' | 'scheduled' | 'adaptive' | 'ai_optimized';
|
||||||
|
|
||||||
|
// Setpoints
|
||||||
|
daySetpoint: number;
|
||||||
|
nightSetpoint: number;
|
||||||
|
|
||||||
|
// Deadband (prevent oscillation)
|
||||||
|
deadband: number; // ±1°C typical
|
||||||
|
|
||||||
|
// Control outputs
|
||||||
|
coolingStage: 0 | 1 | 2 | 3; // Multi-stage cooling
|
||||||
|
heatingStage: 0 | 1 | 2 | 3; // Multi-stage heating
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### HVAC Systems
|
||||||
|
|
||||||
|
| System Type | Pros | Cons | Best For |
|
||||||
|
|-------------|------|------|----------|
|
||||||
|
| Split AC | Low cost | Limited capacity | Small rooms |
|
||||||
|
| Mini-split | Zoned control | Moderate cost | Medium facilities |
|
||||||
|
| Heat Pump | Efficient, heat recovery | Higher upfront | Production facilities |
|
||||||
|
| Chilled Water | Scalable, precise | Complex, expensive | Large operations |
|
||||||
|
|
||||||
|
## Humidity Control
|
||||||
|
|
||||||
|
### Vapor Pressure Deficit (VPD)
|
||||||
|
|
||||||
|
VPD is the key metric for plant transpiration:
|
||||||
|
|
||||||
|
```
|
||||||
|
VPD = Saturation Pressure - Actual Vapor Pressure
|
||||||
|
|
||||||
|
Optimal VPD by Stage:
|
||||||
|
- Seedling: 0.4-0.8 kPa (high humidity)
|
||||||
|
- Vegetative: 0.8-1.2 kPa (moderate)
|
||||||
|
- Flowering: 1.0-1.5 kPa (lower humidity)
|
||||||
|
```
|
||||||
|
|
||||||
|
### VPD Calculation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function calculateVPD(tempC: number, humidityPercent: number): number {
|
||||||
|
// Saturation vapor pressure (Tetens equation)
|
||||||
|
const svp = 0.6108 * Math.exp((17.27 * tempC) / (tempC + 237.3));
|
||||||
|
|
||||||
|
// Actual vapor pressure
|
||||||
|
const avp = svp * (humidityPercent / 100);
|
||||||
|
|
||||||
|
// VPD in kPa
|
||||||
|
return svp - avp;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Humidification Methods
|
||||||
|
|
||||||
|
| Method | Droplet Size | Coverage | Energy | Best For |
|
||||||
|
|--------|-------------|----------|--------|----------|
|
||||||
|
| Misting | 20-50 µm | Wide | Low | Propagation |
|
||||||
|
| Ultrasonic | 1-5 µm | Targeted | Low | Small zones |
|
||||||
|
| Fog | 5-20 µm | Wide | Medium | Large areas |
|
||||||
|
| Evaporative | N/A | Wide | Low | Arid climates |
|
||||||
|
|
||||||
|
### Dehumidification
|
||||||
|
|
||||||
|
```
|
||||||
|
Sources of Humidity:
|
||||||
|
├── Plant transpiration: 95%+ of water uptake
|
||||||
|
├── Irrigation: Evaporation from growing media
|
||||||
|
├── Human activity: Breathing, sweating
|
||||||
|
└── Fresh air: Outdoor humidity
|
||||||
|
|
||||||
|
Removal Methods:
|
||||||
|
├── HVAC: Condenses on evaporator coil
|
||||||
|
├── Dedicated dehumidifier: Efficient for high loads
|
||||||
|
├── Desiccant: Continuous, no condensate
|
||||||
|
└── Ventilation: If outdoor humidity lower
|
||||||
|
```
|
||||||
|
|
||||||
|
## CO2 Enrichment
|
||||||
|
|
||||||
|
### Why Enrich?
|
||||||
|
|
||||||
|
```
|
||||||
|
Ambient CO2: ~420 ppm
|
||||||
|
Optimal Growth: 800-1200 ppm
|
||||||
|
Maximum Benefit: 1500 ppm
|
||||||
|
|
||||||
|
Photosynthesis increases ~30-50% with enrichment
|
||||||
|
```
|
||||||
|
|
||||||
|
### CO2 Sources
|
||||||
|
|
||||||
|
| Source | Cost | Control | Safety | Best For |
|
||||||
|
|--------|------|---------|--------|----------|
|
||||||
|
| Tank (compressed) | Medium | Excellent | Safe | Small/medium |
|
||||||
|
| Generator (propane) | Low | Good | Heat/humidity | Sealed rooms |
|
||||||
|
| Fermentation | Very low | Poor | Safe | Hobby |
|
||||||
|
| Air capture | High | Excellent | Safe | Large scale |
|
||||||
|
|
||||||
|
### Control Strategy
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface CO2Control {
|
||||||
|
targetPpm: number;
|
||||||
|
hysteresis: number; // ±50 ppm typical
|
||||||
|
|
||||||
|
// Only enrich when lights on
|
||||||
|
enrichDuringLightsOnly: boolean;
|
||||||
|
|
||||||
|
// Integration with ventilation
|
||||||
|
pauseDuringVentilation: boolean;
|
||||||
|
|
||||||
|
// Safety limits
|
||||||
|
maxPpm: 2000; // Worker safety
|
||||||
|
alarmPpm: 1800;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Lighting Systems
|
||||||
|
|
||||||
|
### Light Spectrum
|
||||||
|
|
||||||
|
```
|
||||||
|
Wavelength Ranges:
|
||||||
|
├── UV-A (315-400nm): Compact growth, secondary metabolites
|
||||||
|
├── Blue (400-500nm): Vegetative growth, compact structure
|
||||||
|
├── Green (500-565nm): Canopy penetration
|
||||||
|
├── Red (620-700nm): Photosynthesis, flowering
|
||||||
|
└── Far-Red (700-800nm): Shade avoidance, flowering
|
||||||
|
|
||||||
|
Optimal Ratios (general):
|
||||||
|
- Vegetative: Blue 30%, Red 60%, Other 10%
|
||||||
|
- Flowering: Blue 20%, Red 70%, Other 10%
|
||||||
|
```
|
||||||
|
|
||||||
|
### LED Fixture Types
|
||||||
|
|
||||||
|
| Type | Spectrum | Efficiency | Cost | Best For |
|
||||||
|
|------|----------|------------|------|----------|
|
||||||
|
| Full Spectrum | White + Red/Blue | Good | Low | General |
|
||||||
|
| Red/Blue | Optimized peaks | High | Medium | Leafy greens |
|
||||||
|
| Tunable | Adjustable | Good | High | Research, multi-crop |
|
||||||
|
| Sunlight Replica | Full PAR + UV | Excellent | Very High | Premium produce |
|
||||||
|
|
||||||
|
### Light Metrics
|
||||||
|
|
||||||
|
```
|
||||||
|
PPFD (µmol/m²/s): Instantaneous light intensity
|
||||||
|
DLI (mol/m²/day): Daily light integral = PPFD × hours × 3600 / 1,000,000
|
||||||
|
|
||||||
|
Targets by Crop:
|
||||||
|
├── Microgreens: DLI 8-12
|
||||||
|
├── Lettuce: DLI 12-17
|
||||||
|
├── Basil: DLI 15-20
|
||||||
|
├── Tomatoes: DLI 22-30
|
||||||
|
└── Cannabis: DLI 40-65
|
||||||
|
```
|
||||||
|
|
||||||
|
## Nutrient Delivery
|
||||||
|
|
||||||
|
### Solution Management
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface NutrientSolution {
|
||||||
|
// Primary monitoring
|
||||||
|
ec: number; // Electrical Conductivity (mS/cm)
|
||||||
|
ph: number; // Target 5.5-6.5
|
||||||
|
|
||||||
|
// Temperature
|
||||||
|
tempC: number; // Target 18-22°C
|
||||||
|
|
||||||
|
// Dissolved oxygen
|
||||||
|
doPpm: number; // Target >6 ppm
|
||||||
|
|
||||||
|
// Macro nutrients (ppm)
|
||||||
|
nitrogen: number; // 150-250
|
||||||
|
phosphorus: number; // 30-60
|
||||||
|
potassium: number; // 150-300
|
||||||
|
calcium: number; // 150-250
|
||||||
|
magnesium: number; // 40-80
|
||||||
|
sulfur: number; // 50-100
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dosing Systems
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ DOSING SYSTEM │
|
||||||
|
├─────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ Stock Solutions │
|
||||||
|
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
|
||||||
|
│ │ A │ │ B │ │CalMag│ │pH Up│ │pH Dn│ │Sili │ │
|
||||||
|
│ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ ▼ ▼ ▼ ▼ ▼ ▼ │
|
||||||
|
│ ┌────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ DOSING PUMPS │ │
|
||||||
|
│ │ Peristaltic pumps: Precise, low maintenance │ │
|
||||||
|
│ └────────────────────────────────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ▼ │
|
||||||
|
│ ┌────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ MIXING TANK │ │
|
||||||
|
│ │ - EC sensor │ │
|
||||||
|
│ │ - pH sensor │ │
|
||||||
|
│ │ - Temperature sensor │ │
|
||||||
|
│ │ - Level sensor │ │
|
||||||
|
│ └────────────────────────────────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ▼ │
|
||||||
|
│ ┌────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ GROWING ZONES │ │
|
||||||
|
│ └────────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Air Circulation
|
||||||
|
|
||||||
|
### Airflow Requirements
|
||||||
|
|
||||||
|
```
|
||||||
|
Purposes:
|
||||||
|
├── Temperature uniformity
|
||||||
|
├── Humidity distribution
|
||||||
|
├── CO2 distribution
|
||||||
|
├── Plant strengthening (thigmomorphogenesis)
|
||||||
|
└── Disease prevention
|
||||||
|
|
||||||
|
Velocity Targets:
|
||||||
|
├── At canopy: 0.3-0.5 m/s
|
||||||
|
├── Avoid dead spots
|
||||||
|
├── Avoid excessive wind stress
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fan Types
|
||||||
|
|
||||||
|
| Fan Type | Use | Placement |
|
||||||
|
|----------|-----|-----------|
|
||||||
|
| Circulation | Air mixing | Throughout canopy |
|
||||||
|
| Oscillating | Variable airflow | Above canopy |
|
||||||
|
| Exhaust | Heat/humidity removal | High in room |
|
||||||
|
| Intake | Fresh air, CO2 dilution | Low in room |
|
||||||
|
|
||||||
|
## Sensor Networks
|
||||||
|
|
||||||
|
### Sensor Placement
|
||||||
|
|
||||||
|
```
|
||||||
|
Zone Layout with Sensors:
|
||||||
|
|
||||||
|
┌─────────────────────────────────┐
|
||||||
|
│ [T/H] [T/H] │ [T/H] = Temp/Humidity
|
||||||
|
│ ●───────────────● │
|
||||||
|
│ │ [CO2] │ │ [CO2] = CO2 sensor
|
||||||
|
│ │ ● │ │
|
||||||
|
│ ┌───┴───────────────┴───┐ │ [PAR] = Light sensor
|
||||||
|
│ │ [PAR] [PAR] │ │
|
||||||
|
│ │ ● ● │ Zone │ [EC] = EC sensor
|
||||||
|
│ │ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │ │
|
||||||
|
│ │ ▓▓ Plants ▓▓▓▓ │ │ [pH] = pH sensor
|
||||||
|
│ │ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │ │
|
||||||
|
│ │ [EC] [pH] │ │
|
||||||
|
│ │ ● ● (reservoir)│ │
|
||||||
|
│ └───────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────┘
|
||||||
|
|
||||||
|
Recommended Density:
|
||||||
|
- T/H: 1 per 20-50 m²
|
||||||
|
- CO2: 1 per zone (at plant height)
|
||||||
|
- PAR: 2-4 per zone (canopy level)
|
||||||
|
- EC/pH: At each reservoir
|
||||||
|
```
|
||||||
|
|
||||||
|
### Calibration Schedule
|
||||||
|
|
||||||
|
| Sensor | Frequency | Method |
|
||||||
|
|--------|-----------|--------|
|
||||||
|
| Temperature | Monthly | Reference thermometer |
|
||||||
|
| Humidity | Monthly | Saturated salt test |
|
||||||
|
| CO2 | Quarterly | Cal gas (fresh air ref) |
|
||||||
|
| PAR | Annually | Reference meter |
|
||||||
|
| EC | Weekly | Cal solution |
|
||||||
|
| pH | Weekly | pH 4.0, 7.0 buffers |
|
||||||
|
|
||||||
|
## Alert System
|
||||||
|
|
||||||
|
### Alert Thresholds
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface AlertThresholds {
|
||||||
|
temperature: {
|
||||||
|
warning: { low: targetMin - 2, high: targetMax + 2 };
|
||||||
|
critical: { low: targetMin - 5, high: targetMax + 5 };
|
||||||
|
};
|
||||||
|
humidity: {
|
||||||
|
warning: { low: 50, high: 80 };
|
||||||
|
critical: { low: 40, high: 90 };
|
||||||
|
};
|
||||||
|
co2: {
|
||||||
|
warning: { low: 600, high: 1600 };
|
||||||
|
critical: { high: 2000 }; // Safety
|
||||||
|
};
|
||||||
|
ec: {
|
||||||
|
warning: { low: targetEc - 0.3, high: targetEc + 0.3 };
|
||||||
|
critical: { low: targetEc - 0.5, high: targetEc + 0.5 };
|
||||||
|
};
|
||||||
|
ph: {
|
||||||
|
warning: { low: 5.0, high: 7.0 };
|
||||||
|
critical: { low: 4.5, high: 7.5 };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alert Escalation
|
||||||
|
|
||||||
|
```
|
||||||
|
Level 1: In-app notification
|
||||||
|
↓ (no response 5 min)
|
||||||
|
Level 2: SMS/Push notification
|
||||||
|
↓ (no response 15 min)
|
||||||
|
Level 3: Phone call
|
||||||
|
↓ (no response 30 min)
|
||||||
|
Level 4: Emergency contact
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Daily Operations
|
||||||
|
|
||||||
|
1. **Check sensors** - Verify readings match reality
|
||||||
|
2. **Inspect plants** - Catch issues before sensors
|
||||||
|
3. **Review logs** - Look for trends
|
||||||
|
4. **Maintain equipment** - Filters, pumps, fans
|
||||||
|
|
||||||
|
### Preventive Maintenance
|
||||||
|
|
||||||
|
| Equipment | Weekly | Monthly | Quarterly |
|
||||||
|
|-----------|--------|---------|-----------|
|
||||||
|
| Sensors | Visual check | Calibrate | Replace if needed |
|
||||||
|
| Filters | Replace/clean | Deep clean | - |
|
||||||
|
| Pumps | Check flow | Lubricate | Service |
|
||||||
|
| HVAC | Check operation | Filter | Coil cleaning |
|
||||||
|
| LEDs | Wipe | Check spectrum | Power audit |
|
||||||
457
docs/vertical-farming/integration.md
Normal file
457
docs/vertical-farming/integration.md
Normal file
|
|
@ -0,0 +1,457 @@
|
||||||
|
# Vertical Farm Integration Guide
|
||||||
|
|
||||||
|
How to integrate your vertical farm with LocalGreenChain.
|
||||||
|
|
||||||
|
## Integration Overview
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ INTEGRATION ARCHITECTURE │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ YOUR VERTICAL FARM LOCALGREENCHAIN │
|
||||||
|
│ ───────────────── ────────────────── │
|
||||||
|
│ │
|
||||||
|
│ ┌──────────────┐ ┌──────────────────┐ │
|
||||||
|
│ │ Control │───Register───→│ /api/vertical- │ │
|
||||||
|
│ │ System │ │ farm/register │ │
|
||||||
|
│ └──────────────┘ └──────────────────┘ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ ▼ │
|
||||||
|
│ ┌──────────────┐ ┌──────────────────┐ │
|
||||||
|
│ │ Sensors │───Readings───→│ /api/vertical- │ │
|
||||||
|
│ │ │ │ farm/batch/ │ │
|
||||||
|
│ │ │ │ {id}/environ │ │
|
||||||
|
│ └──────────────┘ └──────────────────┘ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ ▼ │
|
||||||
|
│ ┌──────────────┐ ┌──────────────────┐ │
|
||||||
|
│ │ Harvest │───Complete───→│ Transport Chain │ │
|
||||||
|
│ │ Station │ │ (Blockchain) │ │
|
||||||
|
│ └──────────────┘ └──────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ▼ │
|
||||||
|
│ ┌──────────────────┐ │
|
||||||
|
│ │ Consumer QR │ │
|
||||||
|
│ │ Scan → History │ │
|
||||||
|
│ └──────────────────┘ │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 1: Register Your Farm
|
||||||
|
|
||||||
|
### API Call
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/vertical-farm/register
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Your Farm Name",
|
||||||
|
"ownerId": "your-user-id",
|
||||||
|
|
||||||
|
"location": {
|
||||||
|
"latitude": 40.7128,
|
||||||
|
"longitude": -74.0060,
|
||||||
|
"address": "123 Main Street",
|
||||||
|
"city": "Brooklyn",
|
||||||
|
"country": "USA",
|
||||||
|
"timezone": "America/New_York"
|
||||||
|
},
|
||||||
|
|
||||||
|
"specs": {
|
||||||
|
"totalAreaSqm": 500,
|
||||||
|
"growingAreaSqm": 400,
|
||||||
|
"numberOfLevels": 4,
|
||||||
|
"ceilingHeightM": 4,
|
||||||
|
"totalGrowingPositions": 5000,
|
||||||
|
"powerCapacityKw": 150,
|
||||||
|
"waterStorageL": 10000,
|
||||||
|
"certifications": ["gap"],
|
||||||
|
"buildingType": "warehouse"
|
||||||
|
},
|
||||||
|
|
||||||
|
"automationLevel": "semi_automated"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"id": "farm-abc123",
|
||||||
|
"name": "Your Farm Name",
|
||||||
|
"status": "operational",
|
||||||
|
"apiKey": "vf_key_xxxxx" // For automation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 2: Configure Zones
|
||||||
|
|
||||||
|
### Create Zones
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/vertical-farm/{farmId}/zones
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Zone A - Lettuce",
|
||||||
|
"level": 1,
|
||||||
|
"areaSqm": 100,
|
||||||
|
"growingMethod": "NFT",
|
||||||
|
"plantPositions": 1200,
|
||||||
|
"environmentTargets": {
|
||||||
|
"temperatureC": { "min": 18, "max": 24, "target": 21 },
|
||||||
|
"humidityPercent": { "min": 55, "max": 75, "target": 65 },
|
||||||
|
"co2Ppm": { "min": 800, "max": 1400, "target": 1000 },
|
||||||
|
"lightPpfd": { "min": 200, "max": 400, "target": 300 },
|
||||||
|
"lightHours": 16,
|
||||||
|
"nutrientEc": { "min": 1.2, "max": 1.8, "target": 1.5 },
|
||||||
|
"nutrientPh": { "min": 5.5, "max": 6.5, "target": 6.0 },
|
||||||
|
"waterTempC": { "min": 18, "max": 22, "target": 20 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 3: Integrate Sensors
|
||||||
|
|
||||||
|
### Environment Reporting
|
||||||
|
|
||||||
|
Set up your control system to report environment data:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Every 5 minutes, send readings
|
||||||
|
async function reportEnvironment(batchId: string): Promise<void> {
|
||||||
|
const readings = await collectSensorData();
|
||||||
|
|
||||||
|
await fetch(`/api/vertical-farm/batch/${batchId}/environment`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${API_KEY}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
temperatureC: readings.temperature,
|
||||||
|
humidityPercent: readings.humidity,
|
||||||
|
co2Ppm: readings.co2,
|
||||||
|
ppfd: readings.light,
|
||||||
|
dli: readings.dli,
|
||||||
|
waterTempC: readings.waterTemp,
|
||||||
|
ec: readings.ec,
|
||||||
|
ph: readings.ph,
|
||||||
|
dissolvedOxygenPpm: readings.do,
|
||||||
|
airflowMs: readings.airflow
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule reporting
|
||||||
|
setInterval(() => reportEnvironment(currentBatchId), 5 * 60 * 1000);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Handle Alerts
|
||||||
|
|
||||||
|
Process alerts returned from the API:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const response = await reportEnvironment(batchId);
|
||||||
|
const { alerts } = await response.json();
|
||||||
|
|
||||||
|
for (const alert of alerts) {
|
||||||
|
if (alert.type.includes('critical')) {
|
||||||
|
// Trigger immediate action
|
||||||
|
handleCriticalAlert(alert);
|
||||||
|
} else {
|
||||||
|
// Log and notify
|
||||||
|
logAlert(alert);
|
||||||
|
notifyOperator(alert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 4: Manage Crop Batches
|
||||||
|
|
||||||
|
### Start a Batch
|
||||||
|
|
||||||
|
When planting a new crop:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/vertical-farm/batch/start
|
||||||
|
|
||||||
|
{
|
||||||
|
"farmId": "farm-abc123",
|
||||||
|
"zoneId": "zone-xyz789",
|
||||||
|
"recipeId": "recipe-lettuce-butterhead",
|
||||||
|
"seedBatchId": "seeds-lettuce-2024-001", // Links to transport chain
|
||||||
|
"plantCount": 200
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates:
|
||||||
|
1. A new batch record
|
||||||
|
2. Links to the seed source (transport chain)
|
||||||
|
3. Generates plant IDs for tracking
|
||||||
|
4. Sets initial stage and targets
|
||||||
|
|
||||||
|
### Track Progress
|
||||||
|
|
||||||
|
The system automatically tracks:
|
||||||
|
- Current day and stage
|
||||||
|
- Health score based on environment
|
||||||
|
- Expected vs actual timeline
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/vertical-farm/batch/{batchId}
|
||||||
|
|
||||||
|
// Response
|
||||||
|
{
|
||||||
|
"id": "batch-abc123",
|
||||||
|
"currentDay": 15,
|
||||||
|
"currentStage": "Vegetative Growth",
|
||||||
|
"healthScore": 95,
|
||||||
|
"status": "growing",
|
||||||
|
"expectedHarvestDate": "2024-07-06",
|
||||||
|
"alerts": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Complete Harvest
|
||||||
|
|
||||||
|
When harvesting:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/vertical-farm/batch/{batchId}/harvest
|
||||||
|
|
||||||
|
{
|
||||||
|
"actualYieldKg": 38.5,
|
||||||
|
"qualityGrade": "A",
|
||||||
|
"notes": "Excellent crop"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This automatically:
|
||||||
|
1. Records harvest in transport chain
|
||||||
|
2. Updates batch status
|
||||||
|
3. Frees zone for next batch
|
||||||
|
4. Links to distribution
|
||||||
|
|
||||||
|
## Step 5: Connect to Demand
|
||||||
|
|
||||||
|
### Check Demand Signals
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
GET /api/demand/signal?lat=40.7128&lon=-74.0060&radius=25&season=summer
|
||||||
|
|
||||||
|
// Response shows gaps you can fill
|
||||||
|
{
|
||||||
|
"demandItems": [
|
||||||
|
{
|
||||||
|
"produceType": "lettuce",
|
||||||
|
"gapKg": 120,
|
||||||
|
"urgency": "this_week"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Commit Supply
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/demand/supply
|
||||||
|
|
||||||
|
{
|
||||||
|
"produceType": "lettuce",
|
||||||
|
"variety": "butterhead",
|
||||||
|
"committedQuantityKg": 50,
|
||||||
|
"availableFrom": "2024-07-06",
|
||||||
|
"pricePerKg": 5.00,
|
||||||
|
"certifications": ["local_food_safety"],
|
||||||
|
"deliveryRadiusKm": 25
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration Patterns
|
||||||
|
|
||||||
|
### Pattern 1: Periodic Reporting
|
||||||
|
|
||||||
|
Simple integration for basic operations:
|
||||||
|
|
||||||
|
```
|
||||||
|
Every 5 min: Report environment
|
||||||
|
Every 1 hour: Check for alerts
|
||||||
|
Daily: Update batch progress
|
||||||
|
On harvest: Report completion
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 2: Event-Driven
|
||||||
|
|
||||||
|
Real-time integration for advanced operations:
|
||||||
|
|
||||||
|
```
|
||||||
|
On sensor change: Report if significant
|
||||||
|
On alert trigger: Immediate notification
|
||||||
|
On stage change: Update setpoints
|
||||||
|
On harvest complete: Full chain update
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 3: Full Automation
|
||||||
|
|
||||||
|
Complete integration with automated response:
|
||||||
|
|
||||||
|
```
|
||||||
|
LocalGreenChain ←→ Control System ←→ Equipment
|
||||||
|
|
||||||
|
Demand signal → Start batch automatically
|
||||||
|
Recipe stage → Update setpoints automatically
|
||||||
|
Alert → Automated response
|
||||||
|
Harvest ready → Schedule harvest automation
|
||||||
|
```
|
||||||
|
|
||||||
|
## Webhook Integration
|
||||||
|
|
||||||
|
### Register Webhooks
|
||||||
|
|
||||||
|
Receive real-time events:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
POST /api/webhooks
|
||||||
|
|
||||||
|
{
|
||||||
|
"url": "https://your-farm.com/webhook",
|
||||||
|
"events": [
|
||||||
|
"batch.stage_changed",
|
||||||
|
"batch.alert_triggered",
|
||||||
|
"demand.signal_generated"
|
||||||
|
],
|
||||||
|
"secret": "your-webhook-secret"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Handle Webhooks
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
app.post('/webhook', (req, res) => {
|
||||||
|
// Verify signature
|
||||||
|
const signature = req.headers['x-lgc-signature'];
|
||||||
|
if (!verifySignature(req.body, signature)) {
|
||||||
|
return res.status(401).send('Invalid signature');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { event, data } = req.body;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case 'batch.stage_changed':
|
||||||
|
updateControllerSetpoints(data.zoneId, data.newStage);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'batch.alert_triggered':
|
||||||
|
handleAlert(data.alert);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'demand.signal_generated':
|
||||||
|
evaluateOpportunity(data.signal);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).send('OK');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Flow Example
|
||||||
|
|
||||||
|
### Complete Cycle
|
||||||
|
|
||||||
|
```
|
||||||
|
1. SEED ACQUISITION
|
||||||
|
- Source seeds → Record transport event
|
||||||
|
- seedBatchId: "seeds-001"
|
||||||
|
|
||||||
|
2. START BATCH
|
||||||
|
- Create batch with seedBatchId
|
||||||
|
- System links to seed origin
|
||||||
|
|
||||||
|
3. GROWING
|
||||||
|
- Report environment every 5 min
|
||||||
|
- System tracks against recipe
|
||||||
|
- Alerts if out of range
|
||||||
|
|
||||||
|
4. STAGE TRANSITIONS
|
||||||
|
- System detects day changes
|
||||||
|
- Updates stage, setpoints
|
||||||
|
- Webhook notifies control system
|
||||||
|
|
||||||
|
5. HARVEST
|
||||||
|
- Complete harvest API call
|
||||||
|
- Creates transport event
|
||||||
|
- Links to seed origin (full chain)
|
||||||
|
|
||||||
|
6. DISTRIBUTION
|
||||||
|
- Record distribution transport
|
||||||
|
- Generate QR code
|
||||||
|
- Consumer can scan for full history
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing Integration
|
||||||
|
|
||||||
|
### Test Checklist
|
||||||
|
|
||||||
|
1. [ ] Farm registration successful
|
||||||
|
2. [ ] Zone creation successful
|
||||||
|
3. [ ] Environment reporting working
|
||||||
|
4. [ ] Alerts generated correctly
|
||||||
|
5. [ ] Batch creation working
|
||||||
|
6. [ ] Harvest recording working
|
||||||
|
7. [ ] Transport chain links correct
|
||||||
|
8. [ ] QR code shows full history
|
||||||
|
9. [ ] Webhooks received
|
||||||
|
10. [ ] Analytics accurate
|
||||||
|
|
||||||
|
### Test Environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Use development API
|
||||||
|
API_BASE=http://localhost:3001/api
|
||||||
|
|
||||||
|
# Test registration
|
||||||
|
curl -X POST $API_BASE/vertical-farm/register \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"name": "Test Farm", ...}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
| Issue | Cause | Solution |
|
||||||
|
|-------|-------|----------|
|
||||||
|
| 401 Unauthorized | Invalid API key | Check API key |
|
||||||
|
| Missing alerts | Readings within range | Check thresholds |
|
||||||
|
| Wrong stage | Day calculation | Check planting date |
|
||||||
|
| No transport link | Missing seedBatchId | Include in batch start |
|
||||||
|
|
||||||
|
### Debug Mode
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Enable detailed logging
|
||||||
|
const response = await fetch(url, {
|
||||||
|
headers: {
|
||||||
|
'X-Debug': 'true'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Response includes debug info
|
||||||
|
const { data, _debug } = await response.json();
|
||||||
|
console.log(_debug);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Consistent reporting** - Don't skip readings
|
||||||
|
2. **Accurate timestamps** - Use server time or sync
|
||||||
|
3. **Complete data** - Include all sensor values
|
||||||
|
4. **Handle errors** - Retry on failure
|
||||||
|
5. **Monitor health** - Track batch health scores
|
||||||
|
6. **Link everything** - Use seedBatchId to connect chains
|
||||||
Loading…
Reference in a new issue