localgreenchain/lib/blockchain/manager.ts
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

132 lines
3.4 KiB
TypeScript

/**
* Blockchain Manager
* Singleton to manage the global plant blockchain instance
*
* Supports two modes:
* 1. File-based (legacy): Uses JSON file storage
* 2. Database-backed: Uses PostgreSQL via Prisma (recommended)
*/
import { PlantChain } from './PlantChain';
import { PlantChainDB, getPlantChain as getDBPlantChain } from './PlantChainDB';
import fs from 'fs';
import path from 'path';
const BLOCKCHAIN_FILE = path.join(process.cwd(), 'data', 'plantchain.json');
// Flag to determine storage mode
const USE_DATABASE = process.env.DATABASE_URL ? true : false;
class BlockchainManager {
private static instance: BlockchainManager;
private plantChain: PlantChain;
private autoSaveInterval: NodeJS.Timeout | null = null;
private constructor() {
this.plantChain = this.loadBlockchain();
this.startAutoSave();
}
public static getInstance(): BlockchainManager {
if (!BlockchainManager.instance) {
BlockchainManager.instance = new BlockchainManager();
}
return BlockchainManager.instance;
}
public getChain(): PlantChain {
return this.plantChain;
}
/**
* Load blockchain from file or create new one
*/
private loadBlockchain(): PlantChain {
try {
// Ensure data directory exists
const dataDir = path.join(process.cwd(), 'data');
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true });
}
if (fs.existsSync(BLOCKCHAIN_FILE)) {
const data = fs.readFileSync(BLOCKCHAIN_FILE, 'utf-8');
const chainData = JSON.parse(data);
console.log('✓ Loaded existing blockchain with', chainData.chain.length, 'blocks');
return PlantChain.fromJSON(chainData);
}
} catch (error) {
console.error('Error loading blockchain:', error);
}
console.log('✓ Created new blockchain');
return new PlantChain(4); // difficulty of 4
}
/**
* Save blockchain to file
*/
public saveBlockchain(): void {
try {
const dataDir = path.join(process.cwd(), 'data');
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true });
}
const data = JSON.stringify(this.plantChain.toJSON(), null, 2);
fs.writeFileSync(BLOCKCHAIN_FILE, data, 'utf-8');
console.log('✓ Blockchain saved');
} catch (error) {
console.error('Error saving blockchain:', error);
}
}
/**
* Auto-save blockchain every 5 minutes
*/
private startAutoSave(): void {
if (this.autoSaveInterval) {
clearInterval(this.autoSaveInterval);
}
this.autoSaveInterval = setInterval(() => {
this.saveBlockchain();
}, 5 * 60 * 1000); // 5 minutes
}
/**
* Stop auto-save
*/
public stopAutoSave(): void {
if (this.autoSaveInterval) {
clearInterval(this.autoSaveInterval);
this.autoSaveInterval = null;
}
}
}
export function getBlockchain(): PlantChain {
return BlockchainManager.getInstance().getChain();
}
export function saveBlockchain(): void {
BlockchainManager.getInstance().saveBlockchain();
}
/**
* Get the database-backed blockchain instance
* Use this for production applications with PostgreSQL
*/
export async function getBlockchainDB(): Promise<PlantChainDB> {
return getDBPlantChain();
}
/**
* Check if using database storage
*/
export function isUsingDatabase(): boolean {
return USE_DATABASE;
}
// Export the DB class for type usage
export { PlantChainDB };