- Add guides: quick-start, installation, configuration, grower, consumer, transport, vertical-farm - Add API references: REST, demand, vertical-farming - Add concepts: blockchain, seasonal-planning, carbon-footprint - Add architecture: data-flow, transport-tracking - Add vertical-farming: environmental-control, automation, integration - Add examples: seed-to-harvest, demand-driven-planting, vertical-farm-setup Completes Agent_5 documentation tasks from AGENT_REPORT.md
15 KiB
15 KiB
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
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:
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
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
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
function calculateCarbon(
method: TransportMethod,
distanceKm: number,
weightKg: number
): number {
const factor = CARBON_FACTORS[method] || 0.1;
return factor * distanceKm * weightKg;
}
Journey Reconstruction
Algorithm
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
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
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
{
"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
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
// 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