Spaces:
Running
Running
| <html> | |
| <head> | |
| <title>AgriChain Backend Documentation</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style> | |
| pre { | |
| background-color: #f8f8f8; | |
| border-radius: 5px; | |
| padding: 15px; | |
| overflow-x: auto; | |
| } | |
| .endpoint { | |
| border-left: 4px solid #10b981; | |
| padding-left: 1rem; | |
| margin-bottom: 2rem; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 p-8"> | |
| <div class="max-w-6xl mx-auto bg-white rounded-lg shadow-lg p-8"> | |
| <div class="flex items-center mb-8"> | |
| <i class="fas fa-leaf text-emerald-500 text-3xl mr-3"></i> | |
| <h1 class="text-3xl font-bold text-gray-800">AgriChain Backend API</h1> | |
| </div> | |
| <div class="mb-8"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">System Overview</h2> | |
| <p class="text-gray-600 mb-4"> | |
| The AgriChain backend provides RESTful APIs for the smart farming dashboard, handling IoT device data, | |
| blockchain transactions, AI predictions, and user management. | |
| </p> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6"> | |
| <div class="bg-emerald-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-emerald-800 mb-2">Tech Stack</h3> | |
| <ul class="text-sm text-gray-700 space-y-1"> | |
| <li>Node.js v18+</li> | |
| <li>Express.js</li> | |
| <li>MongoDB (with Mongoose)</li> | |
| <li>JWT Authentication</li> | |
| <li>Web3.js for blockchain</li> | |
| <li>TensorFlow.js for AI</li> | |
| </ul> | |
| </div> | |
| <div class="bg-blue-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-blue-800 mb-2">Key Features</h3> | |
| <ul class="text-sm text-gray-700 space-y-1"> | |
| <li>Real-time IoT data processing</li> | |
| <li>Blockchain data integrity</li> | |
| <li>AI prediction models</li> | |
| <li>User authentication</li> | |
| <li>Cloud integration</li> | |
| </ul> | |
| </div> | |
| <div class="bg-purple-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-purple-800 mb-2">Deployment</h3> | |
| <ul class="text-sm text-gray-700 space-y-1"> | |
| <li>Docker containerization</li> | |
| <li>Kubernetes for orchestration</li> | |
| <li>AWS ECS/EKS</li> | |
| <li>CI/CD with GitHub Actions</li> | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mb-8"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Installation</h2> | |
| <pre><code class="language-bash"> | |
| # Clone the repository | |
| git clone https://github.com/agrichain/backend.git | |
| cd backend | |
| # Install dependencies | |
| npm install | |
| # Set up environment variables | |
| cp .env.example .env | |
| # Edit .env with your configuration | |
| # Start the development server | |
| npm run dev | |
| # For production | |
| npm run build | |
| npm start | |
| </code></pre> | |
| </div> | |
| <div class="mb-8"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">API Endpoints</h2> | |
| <div class="endpoint"> | |
| <h3 class="text-lg font-medium text-gray-800 mb-2">Authentication</h3> | |
| <div class="mb-4"> | |
| <span class="bg-green-100 text-green-800 text-xs font-medium px-2.5 py-0.5 rounded">POST</span> | |
| <span class="ml-2 font-mono">/api/auth/register</span> | |
| </div> | |
| <pre><code class="language-javascript"> | |
| // Request Body | |
| { | |
| "name": "John Farmer", | |
| "email": "john@example.com", | |
| "password": "securepassword123", | |
| "farmName": "Green Valley Farms" | |
| } | |
| // Response | |
| { | |
| "success": true, | |
| "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", | |
| "user": { | |
| "id": "507f1f77bcf86cd799439011", | |
| "name": "John Farmer", | |
| "email": "john@example.com", | |
| "farmName": "Green Valley Farms" | |
| } | |
| } | |
| </code></pre> | |
| <div class="mb-4 mt-6"> | |
| <span class="bg-green-100 text-green-800 text-xs font-medium px-2.5 py-0.5 rounded">POST</span> | |
| <span class="ml-2 font-mono">/api/auth/login</span> | |
| </div> | |
| <pre><code class="language-javascript"> | |
| // Request Body | |
| { | |
| "email": "john@example.com", | |
| "password": "securepassword123" | |
| } | |
| // Response (same structure as register) | |
| </code></pre> | |
| </div> | |
| <div class="endpoint"> | |
| <h3 class="text-lg font-medium text-gray-800 mb-2">IoT Device Management</h3> | |
| <div class="mb-4"> | |
| <span class="bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded">GET</span> | |
| <span class="ml-2 font-mono">/api/iot/devices</span> | |
| </div> | |
| <pre><code class="language-javascript"> | |
| // Response | |
| { | |
| "success": true, | |
| "devices": [ | |
| { | |
| "id": "60d5ec9cfb9d8b3a48fe9a12", | |
| "name": "Soil Moisture Sensor - Field A", | |
| "type": "moisture", | |
| "status": "online", | |
| "batteryLevel": 78, | |
| "signalStrength": 92, | |
| "lastReading": { | |
| "value": 72, | |
| "timestamp": "2023-06-15T08:30:45.000Z" | |
| }, | |
| "location": { | |
| "field": "A", | |
| "coordinates": [34.0522, -118.2437] | |
| } | |
| }, | |
| // ... more devices | |
| ] | |
| } | |
| </code></pre> | |
| <div class="mb-4 mt-6"> | |
| <span class="bg-yellow-100 text-yellow-800 text-xs font-medium px-2.5 py-0.5 rounded">POST</span> | |
| <span class="ml-2 font-mono">/api/iot/data</span> | |
| <span class="text-sm text-gray-500 ml-2">(for IoT devices to send data)</span> | |
| </div> | |
| <pre><code class="language-javascript"> | |
| // Request Body | |
| { | |
| "deviceId": "60d5ec9cfb9d8b3a48fe9a12", | |
| "secretKey": "device-secret-key", | |
| "readings": [ | |
| { | |
| "type": "moisture", | |
| "value": 72, | |
| "timestamp": "2023-06-15T08:30:45.000Z" | |
| } | |
| ] | |
| } | |
| // Response | |
| { | |
| "success": true, | |
| "message": "Data received and stored", | |
| "blockchainHash": "a3f8e2d4b5c71f9e8a0b6d5c4f3e2a1b" | |
| } | |
| </code></pre> | |
| </div> | |
| <div class="endpoint"> | |
| <h3 class="text-lg font-medium text-gray-800 mb-2">Blockchain</h3> | |
| <div class="mb-4"> | |
| <span class="bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded">GET</span> | |
| <span class="ml-2 font-mono">/api/blockchain/blocks</span> | |
| </div> | |
| <pre><code class="language-javascript"> | |
| // Response | |
| { | |
| "success": true, | |
| "blocks": [ | |
| { | |
| "index": 4892, | |
| "timestamp": "2023-06-15T08:30:45.000Z", | |
| "data": { | |
| "deviceId": "60d5ec9cfb9d8b3a48fe9a12", | |
| "readingType": "moisture", | |
| "value": 72, | |
| "field": "A" | |
| }, | |
| "previousHash": "b5c71f9e8a0b6d5c4f3e2a1ba3f8e2d", | |
| "hash": "a3f8e2d4b5c71f9e8a0b6d5c4f3e2a1b" | |
| }, | |
| // ... more blocks | |
| ] | |
| } | |
| </code></pre> | |
| <div class="mb-4 mt-6"> | |
| <span class="bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded">GET</span> | |
| <span class="ml-2 font-mono">/api/blockchain/validate</span> | |
| </div> | |
| <pre><code class="language-javascript"> | |
| // Response | |
| { | |
| "success": true, | |
| "valid": true, | |
| "invalidBlocks": [], | |
| "message": "Blockchain integrity verified" | |
| } | |
| </code></pre> | |
| </div> | |
| <div class="endpoint"> | |
| <h3 class="text-lg font-medium text-gray-800 mb-2">AI Predictions</h3> | |
| <div class="mb-4"> | |
| <span class="bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded">GET</span> | |
| <span class="ml-2 font-mono">/api/ai/predictions</span> | |
| </div> | |
| <pre><code class="language-javascript"> | |
| // Response | |
| { | |
| "success": true, | |
| "predictions": [ | |
| { | |
| "type": "irrigation", | |
| "field": "A", | |
| "prediction": "Next irrigation in 8 hours", | |
| "confidence": 0.92, | |
| "recommendation": "Delay watering until evening to reduce evaporation" | |
| }, | |
| { | |
| "type": "pest", | |
| "field": "B", | |
| "prediction": "Low pest risk (15%)", | |
| "confidence": 0.87, | |
| "recommendation": "Monitor for corn borer, no treatment needed yet" | |
| }, | |
| { | |
| "type": "harvest", | |
| "field": "C", | |
| "prediction": "Optimal harvest window: July 15-18", | |
| "confidence": 0.85, | |
| "recommendation": "Prepare workforce and storage for peak yield" | |
| } | |
| ] | |
| } | |
| </code></pre> | |
| <div class="mb-4 mt-6"> | |
| <span class="bg-yellow-100 text-yellow-800 text-xs font-medium px-2.5 py-0.5 rounded">POST</span> | |
| <span class="ml-2 font-mono">/api/ai/train</span> | |
| <span class="text-sm text-gray-500 ml-2">(Admin only - retrain models)</span> | |
| </div> | |
| <pre><code class="language-javascript"> | |
| // Response | |
| { | |
| "success": true, | |
| "message": "AI models retrained successfully", | |
| "newAccuracy": { | |
| "irrigation": 0.93, | |
| "pest": 0.88, | |
| "harvest": 0.86 | |
| } | |
| } | |
| </code></pre> | |
| </div> | |
| <div class="endpoint"> | |
| <h3 class="text-lg font-medium text-gray-800 mb-2">Cloud Integration</h3> | |
| <div class="mb-4"> | |
| <span class="bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded">GET</span> | |
| <span class="ml-2 font-mono">/api/cloud/status</span> | |
| </div> | |
| <pre><code class="language-javascript"> | |
| // Response | |
| { | |
| "success": true, | |
| "services": [ | |
| { | |
| "provider": "AWS IoT", | |
| "status": "connected", | |
| "metrics": { | |
| "messages": 1248, | |
| "storage": 2.8, | |
| "rulesProcessed": 56 | |
| } | |
| }, | |
| { | |
| "provider": "Azure Data Lake", | |
| "status": "syncing", | |
| "metrics": { | |
| "dataStored": 4.2, | |
| "lastSync": "2023-06-15T08:28:12.000Z", | |
| "analyticsJobs": 12 | |
| } | |
| }, | |
| { | |
| "provider": "Google BigQuery", | |
| "status": "processing", | |
| "metrics": { | |
| "queries": 84, | |
| "mlModels": 3, | |
| "storage": 1.5 | |
| } | |
| } | |
| ] | |
| } | |
| </code></pre> | |
| </div> | |
| </div> | |
| <div class="mb-8"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Database Schema</h2> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-gray-800 mb-2">User</h3> | |
| <pre><code class="language-javascript"> | |
| { | |
| name: String, | |
| email: { type: String, unique: true }, | |
| password: String, | |
| farmName: String, | |
| role: { type: String, enum: ['user', 'admin'], default: 'user' }, | |
| createdAt: { type: Date, default: Date.now } | |
| } | |
| </code></pre> | |
| </div> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-gray-800 mb-2">Device</h3> | |
| <pre><code class="language-javascript"> | |
| { | |
| name: String, | |
| type: { type: String, enum: ['moisture', 'temperature', 'humidity', 'light', 'ph', 'co2'] }, | |
| status: { type: String, enum: ['online', 'offline', 'maintenance'] }, | |
| batteryLevel: Number, | |
| signalStrength: Number, | |
| secretKey: String, // For authentication | |
| userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, | |
| location: { | |
| field: String, | |
| coordinates: [Number] // [longitude, latitude] | |
| } | |
| } | |
| </code></pre> | |
| </div> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-gray-800 mb-2">Reading</h3> | |
| <pre><code class="language-javascript"> | |
| { | |
| deviceId: { type: mongoose.Schema.Types.ObjectId, ref: 'Device' }, | |
| type: String, | |
| value: Number, | |
| timestamp: { type: Date, default: Date.now }, | |
| field: String, | |
| blockchainHash: String | |
| } | |
| </code></pre> | |
| </div> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-gray-800 mb-2">Block</h3> | |
| <pre><code class="language-javascript"> | |
| { | |
| index: Number, | |
| timestamp: { type: Date, default: Date.now }, | |
| data: { | |
| deviceId: { type: mongoose.Schema.Types.ObjectId, ref: 'Device' }, | |
| readingType: String, | |
| value: Number, | |
| field: String | |
| }, | |
| previousHash: String, | |
| hash: String | |
| } | |
| </code></pre> | |
| </div> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-gray-800 mb-2">Prediction</h3> | |
| <pre><code class="language-javascript"> | |
| { | |
| type: { type: String, enum: ['irrigation', 'pest', 'harvest'] }, | |
| field: String, | |
| prediction: String, | |
| confidence: Number, | |
| recommendation: String, | |
| userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, | |
| createdAt: { type: Date, default: Date.now } | |
| } | |
| </code></pre> | |
| </div> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <h3 class="font-medium text-gray-800 mb-2">CloudService</h3> | |
| <pre><code class="language-javascript"> | |
| { | |
| provider: { type: String, enum: ['aws', 'azure', 'google'] }, | |
| status: String, | |
| metrics: { | |
| messages: Number, | |
| storage: Number, | |
| rulesProcessed: Number, | |
| // ... other metrics | |
| }, | |
| lastSync: Date, | |
| userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } | |
| } | |
| </code></pre> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mb-8"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Example Server Code</h2> | |
| <div class="mb-6"> | |
| <h3 class="font-medium text-gray-800 mb-2">app.js (Main Server File)</h3> | |
| <pre><code class="language-javascript"> | |
| require('dotenv').config(); | |
| const express = require('express'); | |
| const mongoose = require('mongoose'); | |
| const cors = require('cors'); | |
| const helmet = require('helmet'); | |
| const rateLimit = require('express-rate-limit'); | |
| const { Web3 } = require('web3'); | |
| const tf = require('@tensorflow/tfjs-node'); | |
| const app = express(); | |
| // Database connection | |
| mongoose.connect(process.env.MONGODB_URI, { | |
| useNewUrlParser: true, | |
| useUnifiedTopology: true | |
| }) | |
| .then(() => console.log('Connected to MongoDB')) | |
| .catch(err => console.error('MongoDB connection error:', err)); | |
| // Middleware | |
| app.use(cors()); | |
| app.use(helmet()); | |
| app.use(express.json()); | |
| // Rate limiting | |
| const limiter = rateLimit({ | |
| windowMs: 15 * 60 * 1000, // 15 minutes | |
| max: 100 // limit each IP to 100 requests per windowMs | |
| }); | |
| app.use(limiter); | |
| // Blockchain setup | |
| const web3 = new Web3(process.env.BLOCKCHAIN_NODE_URL); | |
| const contract = new web3.eth.Contract( | |
| JSON.parse(process.env.CONTRACT_ABI), | |
| process.env.CONTRACT_ADDRESS | |
| ); | |
| // Routes | |
| app.use('/api/auth', require('./routes/auth')); | |
| app.use('/api/iot', require('./routes/iot')); | |
| app.use('/api/blockchain', require('./routes/blockchain')); | |
| app.use('/api/ai', require('./routes/ai')); | |
| app.use('/api/cloud', require('./routes/cloud')); | |
| // Error handling | |
| app.use((err, req, res, next) => { | |
| console.error(err.stack); | |
| res.status(500).json({ | |
| success: false, | |
| message: 'Internal server error' | |
| }); | |
| }); | |
| const PORT = process.env.PORT || 5000; | |
| app.listen(PORT, () => { | |
| console.log(`Server running on port ${PORT}`); | |
| }); | |
| module.exports = app; | |
| </code></pre> | |
| </div> | |
| <div class="mb-6"> | |
| <h3 class="font-medium text-gray-800 mb-2">routes/iot.js (Example Route)</h3> | |
| <pre><code class="language-javascript"> | |
| const express = require('express'); | |
| const router = express.Router(); | |
| const auth = require('../middleware/auth'); | |
| const Device = require('../models/Device'); | |
| const Reading = require('../models/Reading'); | |
| const { addBlock } = require('../utils/blockchain'); | |
| // @route GET api/iot/devices | |
| // @desc Get all user's IoT devices | |
| // @access Private | |
| router.get('/devices', auth, async (req, res) => { | |
| try { | |
| const devices = await Device.find({ userId: req.user.id }); | |
| // Get latest readings for each device | |
| const devicesWithReadings = await Promise.all(devices.map(async device => { | |
| const latestReading = await Reading.findOne({ deviceId: device._id }) | |
| .sort({ timestamp: -1 }) | |
| .limit(1); | |
| return { | |
| ...device.toObject(), | |
| lastReading: latestReading || null | |
| }; | |
| })); | |
| res.json({ success: true, devices: devicesWithReadings }); | |
| } catch (err) { | |
| console.error(err.message); | |
| res.status(500).json({ success: false, message: 'Server error' }); | |
| } | |
| }); | |
| // @route POST api/iot/data | |
| // @desc Receive data from IoT device | |
| // @access Private (using device secret key) | |
| router.post('/data', async (req, res) => { | |
| const { deviceId, secretKey, readings } = req.body; | |
| try { | |
| // Verify device | |
| const device = await Device.findOne({ _id: deviceId, secretKey }); | |
| if (!device) { | |
| return res.status(401).json({ | |
| success: false, | |
| message: 'Invalid device credentials' | |
| }); | |
| } | |
| // Save readings | |
| const savedReadings = await Promise.all(readings.map(async reading => { | |
| const newReading = new Reading({ | |
| deviceId, | |
| type: reading.type, | |
| value: reading.value, | |
| timestamp: reading.timestamp || Date.now(), | |
| field: device.location.field | |
| }); | |
| // Add to blockchain | |
| const blockData = { | |
| deviceId, | |
| readingType: reading.type, | |
| value: reading.value, | |
| field: device.location.field | |
| }; | |
| const hash = await addBlock(blockData); | |
| newReading.blockchainHash = hash; | |
| return await newReading.save(); | |
| })); | |
| // Update device status and battery if provided | |
| if (readings[0].batteryLevel) { | |
| device.batteryLevel = readings[0].batteryLevel; | |
| await device.save(); | |
| } | |
| res.json({ | |
| success: true, | |
| message: 'Data received and stored', | |
| blockchainHash: savedReadings[0].blockchainHash | |
| }); | |
| } catch (err) { | |
| console.error(err.message); | |
| res.status(500).json({ success: false, message: 'Server error' }); | |
| } | |
| }); | |
| module.exports = router; | |
| </code></pre> | |
| </div> | |
| <div class="mb-6"> | |
| <h3 class="font-medium text-gray-800 mb-2">utils/blockchain.js</h3> | |
| <pre><code class="language-javascript"> | |
| const Block = require('../models/Block'); | |
| const crypto = require('crypto'); | |
| // Simple blockchain implementation (in production would use Ethereum or similar) | |
| class Blockchain { | |
| constructor() { | |
| this.chain = []; | |
| this.initializeChain(); | |
| } | |
| async initializeChain() { | |
| // Load existing chain from database | |
| const blocks = await Block.find().sort({ index: 1 }); | |
| this.chain = blocks; | |
| // If no blocks, create genesis block | |
| if (this.chain.length === 0) { | |
| await this.createGenesisBlock(); | |
| } | |
| } | |
| async createGenesisBlock() { | |
| const genesisBlock = new Block({ | |
| index: 0, | |
| timestamp: Date.now(), | |
| data: { message: "Genesis block" }, | |
| previousHash: "0", | |
| hash: this.calculateHash(0, "0", Date.now(), { message: "Genesis block" }) | |
| }); | |
| await genesisBlock.save(); | |
| this.chain.push(genesisBlock); | |
| } | |
| calculateHash(index, previousHash, timestamp, data) { | |
| return crypto | |
| .createHash('sha256') | |
| .update(index + previousHash + timestamp + JSON.stringify(data)) | |
| .digest('hex'); | |
| } | |
| async addBlock(data) { | |
| const previousBlock = this.chain[this.chain.length - 1]; | |
| const newIndex = previousBlock.index + 1; | |
| const newTimestamp = Date.now(); | |
| const newHash = this.calculateHash(newIndex, previousBlock.hash, newTimestamp, data); | |
| const newBlock = new Block({ | |
| index: newIndex, | |
| timestamp: newTimestamp, | |
| data, | |
| previousHash: previousBlock.hash, | |
| hash: newHash | |
| }); | |
| await newBlock.save(); | |
| this.chain.push(newBlock); | |
| return newHash; | |
| } | |
| async validateChain() { | |
| for (let i = 1; i < this.chain.length; i++) { | |
| const currentBlock = this.chain[i]; | |
| const previousBlock = this.chain[i - 1]; | |
| // Check hash | |
| if (currentBlock.hash !== this.calculateHash( | |
| currentBlock.index, | |
| currentBlock.previousHash, | |
| currentBlock.timestamp, | |
| currentBlock.data | |
| )) { | |
| return false; | |
| } | |
| // Check previous hash | |
| if (currentBlock.previousHash !== previousBlock.hash) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| } | |
| const blockchain = new Blockchain(); | |
| // Public functions | |
| const addBlock = async (data) => { | |
| return await blockchain.addBlock(data); | |
| }; | |
| const validateChain = async () => { | |
| return await blockchain.validateChain(); | |
| }; | |
| const getBlocks = async () => { | |
| return blockchain.chain; | |
| }; | |
| module.exports = { | |
| addBlock, | |
| validateChain, | |
| getBlocks | |
| }; | |
| </code></pre> | |
| </div> | |
| </div> | |
| <div class="mb-8"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Deployment</h2> | |
| <div class="mb-6"> | |
| <h3 class="font-medium text-gray-800 mb-2">Dockerfile</h3> | |
| <pre><code class="language-dockerfile"> | |
| # Use official Node.js image | |
| FROM node:18-alpine | |
| # Create app directory | |
| WORKDIR /usr/src/app | |
| # Install app dependencies | |
| COPY package*.json ./ | |
| RUN npm install | |
| # Bundle app source | |
| COPY . . | |
| # Build the app | |
| RUN npm run build | |
| # Expose the app port | |
| EXPOSE 5000 | |
| # Start the app | |
| CMD ["npm", "start"] | |
| </code></pre> | |
| </div> | |
| <div class="mb-6"> | |
| <h3 class="font-medium text-gray-800 mb-2">docker-compose.yml</h3> | |
| <pre><code class="language-yaml"> | |
| version: '3.8' | |
| services: | |
| app: | |
| build: . | |
| ports: | |
| - "5000:5000" | |
| environment: | |
| - NODE_ENV=production | |
| - MONGODB_URI=mongodb://mongo:27017/agrichain | |
| - JWT_SECRET=your_jwt_secret | |
| depends_on: | |
| - mongo | |
| restart: unless-stopped | |
| mongo: | |
| image: mongo:6.0 | |
| ports: | |
| - "27017:27017" | |
| volumes: | |
| - mongodb_data:/data/db | |
| environment: | |
| - MONGO_INITDB_ROOT_USERNAME=root | |
| - MONGO_INITDB_ROOT_PASSWORD=example | |
| volumes: | |
| mongodb_data: | |
| </code></pre> | |
| </div> | |
| <div class="mb-6"> | |
| <h3 class="font-medium text-gray-800 mb-2">Kubernetes Deployment</h3> | |
| <pre><code class="language-yaml"> | |
| apiVersion: apps/v1 | |
| kind: Deployment | |
| metadata: | |
| name: agrichain-backend | |
| spec: | |
| replicas: 3 | |
| selector: | |
| matchLabels: | |
| app: agrichain-backend | |
| template: | |
| metadata: | |
| labels: | |
| app: agrichain-backend | |
| spec: | |
| containers: | |
| - name: app | |
| image: your-registry/agrichain-backend:latest | |
| ports: | |
| - containerPort: 5000 | |
| env: | |
| - name: NODE_ENV | |
| value: production | |
| - name: MONGODB_URI | |
| value: "mongodb://agrichain-mongo:27017/agrichain" | |
| - name: JWT_SECRET | |
| valueFrom: | |
| secretKeyRef: | |
| name: agrichain-secrets | |
| key: jwt-secret | |
| - name: mongo | |
| image: mongo:6.0 | |
| ports: | |
| - containerPort: 27017 | |
| env: | |
| - name: MONGO_INITDB_ROOT_USERNAME | |
| valueFrom: | |
| secretKeyRef: | |
| name: agrichain-secrets | |
| key: mongo-root-username | |
| - name: MONGO_INITDB_ROOT_PASSWORD | |
| valueFrom: | |
| secretKeyRef: | |
| name: agrichain-secrets | |
| key: mongo-root-password | |
| volumeMounts: | |
| - name: mongodb-data | |
| mountPath: /data/db | |
| volumes: | |
| - name: mongodb-data | |
| persistentVolumeClaim: | |
| claimName: mongodb-pvc | |
| --- | |
| apiVersion: v1 | |
| kind: Service | |
| metadata: | |
| name: agrichain-service | |
| spec: | |
| selector: | |
| app: agrichain-backend | |
| ports: | |
| - protocol: TCP | |
| port: 80 | |
| targetPort: 5000 | |
| type: LoadBalancer | |
| </code></pre> | |
| </div> | |
| </div> | |
| <div class="bg-emerald-50 p-4 rounded-lg"> | |
| <h2 class="text-lg font-medium text-emerald-800 mb-2">Next Steps</h2> | |
| <ul class="list-disc pl-5 text-gray-700 space-y-1"> | |
| <li>Set up CI/CD pipeline with GitHub Actions</li> | |
| <li>Configure monitoring with Prometheus and Grafana</li> | |
| <li>Implement WebSocket for real-time updates to frontend</li> | |
| <li>Add more AI models for different crop types</li> | |
| <li>Integrate with weather APIs for enhanced predictions</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Abder004/smartfarming" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |