localgreenchain/docs/DATABASE.md
Claude 3d2ccdc29a
feat(db): implement PostgreSQL database integration with Prisma ORM
Agent 2 - Database Integration (P0 Critical):

- Add Prisma ORM with PostgreSQL for persistent data storage
- Create comprehensive database schema with 20+ models:
  - User & authentication models
  - Plant & lineage tracking
  - Transport events & supply chain
  - Vertical farming (farms, zones, batches, recipes)
  - Demand & market matching
  - Audit logging & blockchain storage

- Implement complete database service layer (lib/db/):
  - users.ts: User CRUD with search and stats
  - plants.ts: Plant operations with lineage tracking
  - transport.ts: Transport events and carbon tracking
  - farms.ts: Vertical farm and crop batch management
  - demand.ts: Consumer preferences and market matching
  - audit.ts: Audit logging and blockchain integrity

- Add PlantChainDB for database-backed blockchain
- Create development seed script with sample data
- Add database documentation (docs/DATABASE.md)
- Update package.json with Prisma dependencies and scripts

This provides the foundation for all other agents to build upon
with persistent, scalable data storage.
2025-11-23 03:56:40 +00:00

8.4 KiB

LocalGreenChain Database Integration

This document describes the PostgreSQL database integration for LocalGreenChain, implemented as part of Agent 2's deployment.

Overview

The database layer provides persistent storage for all LocalGreenChain entities using PostgreSQL and Prisma ORM. This replaces the previous file-based JSON storage with a robust, scalable database solution.

Quick Start

1. Install Dependencies

bun install

2. Configure Database

Copy the environment template and configure your database connection:

cp .env.example .env

Edit .env and set your PostgreSQL connection string:

DATABASE_URL="postgresql://user:password@localhost:5432/localgreenchain?schema=public"

3. Generate Prisma Client

bun run db:generate

4. Run Migrations

For development:

bun run db:migrate

For production:

bun run db:migrate:prod

5. Seed Database (Optional)

bun run db:seed

Database Schema

The schema includes the following main entities:

Core Entities

Entity Description
User User accounts with authentication and profiles
Plant Plant records with lineage tracking
TransportEvent Supply chain transport events
SeedBatch Seed batch tracking
HarvestBatch Harvest batch records

Vertical Farming

Entity Description
VerticalFarm Vertical farm facilities
GrowingZone Individual growing zones
CropBatch Active crop batches
GrowingRecipe Growing recipes/protocols
ResourceUsage Energy and resource tracking
FarmAnalytics Farm performance analytics

Demand & Market

Entity Description
ConsumerPreference Consumer food preferences
DemandSignal Aggregated demand signals
SupplyCommitment Grower supply commitments
MarketMatch Matched supply and demand
SeasonalPlan Grower seasonal plans
DemandForecast Demand predictions
PlantingRecommendation Planting recommendations

Audit & Blockchain

Entity Description
AuditLog System audit trail
BlockchainBlock Blockchain block storage

Usage

Importing the Database Layer

import * as db from '@/lib/db';
// or import specific functions
import { createPlant, getPlantById, getPlantLineage } from '@/lib/db';

Common Operations

Users

// Create a user
const user = await db.createUser({
  email: 'grower@example.com',
  name: 'John Farmer',
  userType: 'GROWER',
  city: 'San Francisco',
  country: 'USA',
});

// Get user by email
const user = await db.getUserByEmail('grower@example.com');

// Get user with their plants
const userWithPlants = await db.getUserWithPlants(userId);

Plants

// Create a plant
const plant = await db.createPlant({
  commonName: 'Cherry Tomato',
  scientificName: 'Solanum lycopersicum',
  plantedDate: new Date(),
  latitude: 37.7749,
  longitude: -122.4194,
  ownerId: userId,
});

// Clone a plant
const clone = await db.clonePlant(parentId, newOwnerId, 'CLONE');

// Get plant lineage
const lineage = await db.getPlantLineage(plantId);
// Returns: { plant, ancestors, descendants, siblings }

// Find nearby plants
const nearby = await db.getNearbyPlants({
  latitude: 37.7749,
  longitude: -122.4194,
  radiusKm: 10,
});

Transport Events

// Create a transport event
const event = await db.createTransportEvent({
  eventType: 'DISTRIBUTION',
  fromLatitude: 37.8044,
  fromLongitude: -122.2712,
  fromLocationType: 'VERTICAL_FARM',
  toLatitude: 37.7849,
  toLongitude: -122.4094,
  toLocationType: 'MARKET',
  durationMinutes: 25,
  transportMethod: 'ELECTRIC_TRUCK',
  senderId: farmerId,
  receiverId: distributorId,
});

// Get plant journey
const journey = await db.getPlantJourney(plantId);

// Get environmental impact
const impact = await db.getEnvironmentalImpact({ userId });

Vertical Farms

// Create a farm
const farm = await db.createVerticalFarm({
  name: 'Urban Greens',
  ownerId: userId,
  latitude: 37.8044,
  longitude: -122.2712,
  address: '123 Farm St',
  city: 'Oakland',
  country: 'USA',
  specs: { totalAreaSqm: 500, numberOfLevels: 5 },
});

// Create a growing zone
const zone = await db.createGrowingZone({
  name: 'Zone A',
  farmId: farm.id,
  level: 1,
  areaSqm: 80,
  growingMethod: 'NFT',
  plantPositions: 400,
});

// Create a crop batch
const batch = await db.createCropBatch({
  farmId: farm.id,
  zoneId: zone.id,
  cropType: 'Lettuce',
  plantCount: 400,
  plantingDate: new Date(),
  expectedHarvestDate: new Date(Date.now() + 28 * 24 * 60 * 60 * 1000),
  expectedYieldKg: 60,
});

Demand & Market

// Set consumer preferences
await db.upsertConsumerPreference({
  consumerId: userId,
  latitude: 37.7849,
  longitude: -122.4094,
  preferredCategories: ['leafy_greens', 'herbs'],
  certificationPreferences: ['organic', 'local'],
});

// Create supply commitment
const commitment = await db.createSupplyCommitment({
  growerId: farmerId,
  produceType: 'Butterhead Lettuce',
  committedQuantityKg: 60,
  availableFrom: new Date(),
  availableUntil: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
  pricePerKg: 8.5,
  deliveryRadiusKm: 25,
  deliveryMethods: ['grower_delivery', 'customer_pickup'],
});

// Find matching supply
const matches = await db.findMatchingSupply(
  'Lettuce',
  { latitude: 37.7849, longitude: -122.4094, radiusKm: 20 },
  new Date()
);

Using the Database-Backed Blockchain

The database layer includes a PlantChainDB class that provides blockchain functionality with PostgreSQL persistence:

import { getBlockchainDB } from '@/lib/blockchain/manager';

// Get the database-backed blockchain
const chain = await getBlockchainDB();

// Register a plant (creates both DB record and blockchain block)
const { plant, block } = await chain.registerPlant({
  commonName: 'Tomato',
  latitude: 37.7749,
  longitude: -122.4194,
  ownerId: userId,
});

// Clone a plant
const { plant: clone, block: cloneBlock } = await chain.clonePlant(
  parentId,
  newOwnerId,
  'CLONE'
);

// Verify blockchain integrity
const isValid = await chain.isChainValid();

NPM Scripts

Script Description
bun run db:generate Generate Prisma client
bun run db:push Push schema to database (dev)
bun run db:migrate Create and run migration (dev)
bun run db:migrate:prod Run migrations (production)
bun run db:seed Seed database with test data
bun run db:studio Open Prisma Studio GUI

Architecture

lib/db/
├── prisma.ts      # Prisma client singleton
├── types.ts       # Type definitions and utilities
├── users.ts       # User CRUD operations
├── plants.ts      # Plant operations with lineage
├── transport.ts   # Transport event operations
├── farms.ts       # Vertical farm operations
├── demand.ts      # Demand and market operations
├── audit.ts       # Audit logging and blockchain
└── index.ts       # Central exports

prisma/
├── schema.prisma  # Database schema
└── seed.ts        # Seed script

Migration from File Storage

If you have existing data in JSON files, you can migrate to the database:

  1. Ensure database is configured and migrations are run
  2. Load existing JSON data
  3. Use the database service layer to insert records
  4. Verify data integrity
  5. Remove old JSON files

Performance Considerations

  • The schema includes strategic indexes on frequently queried fields
  • Pagination is supported for large result sets
  • Location-based queries use in-memory filtering (consider PostGIS for large scale)
  • Blockchain integrity verification scans all blocks (cache results for performance)

Troubleshooting

Connection Issues

# Test database connection
bunx prisma db pull

Migration Issues

# Reset database (WARNING: deletes all data)
bunx prisma migrate reset

# Generate new migration
bunx prisma migrate dev --name your_migration_name

Type Issues

# Regenerate Prisma client
bun run db:generate

Security Notes

  • Never commit .env files with real credentials
  • Use environment variables for all sensitive configuration
  • Database user should have minimal required permissions
  • Enable SSL for production database connections

Implemented by Agent 2 - Database Integration