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