// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model User { id String @id @default(cuid()) email String @unique phone String? name String role UserRole isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer? buyer Buyer? administrator Administrator? notifications NotificationRecipient[] @@map("users") } model Farmer { id String @id @default(cuid()) userId String @unique farmerCode String @unique name String phone String? email String? dateOfBirth DateTime? gender Gender? maritalStatus MaritalStatus? spouseName String? numberOfChildren Int? @default(0) religionId String? religion Religion? @relation(fields: [religionId], references: [id]) nationalityId String? @default("indonesia") nationality Country? @relation("FarmerNationality", fields: [nationalityId], references: [id]) address String? village String? district String? province String? postalCode String? countryId String? @default("indonesia") country Country? @relation("FarmerCountry", fields: [countryId], references: [id]) // Location data latitude Float? longitude Float? addressGeoJson Json? // GeoJSON point for precise location // Identity information identityType IdentityType? identityNumber String? identityExpiry DateTime? // Banking information bankAccount String? bankName String? accountHolderName String? // Photos and attachments profilePhotoUrl String? idCardFrontUrl String? idCardBackUrl String? // Verification status isVerified Boolean @default(false) verificationDate DateTime? verifiedBy String? // admin ID who verified verificationNotes String? // Farming experience farmingExperience Int? // years of experience educationLevelId String? educationLevel EducationLevel? @relation(fields: [educationLevelId], references: [id]) occupation String? // primary occupation if not full-time farmer monthlyIncome Decimal? // estimated monthly income landOwnership LandOwnership? primaryCrop String? farmingMethods String[] // organic, conventional, etc. hasVehicle Boolean? // for transportation vehicleType String? // motorcycle, car, truck, etc. hasSmartphone Boolean? @default(true) internetAccess Boolean? @default(true) // Emergency contact emergencyContactName String? emergencyContactPhone String? emergencyContactRelation String? // Status and metadata status FarmerStatus @default(ACTIVE) notes String? joinedAt DateTime @default(now()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) farms Farm[] trainings FarmerTraining[] certifications FarmerCertification[] procurements Procurement[] harvests Harvest[] attachments FarmerAttachment[] workers FarmWorker[] laborRecords LaborRecord[] laborSchedules LaborSchedule[] equipment Equipment[] assets Asset[] financialRecords FinancialRecord[] reviews BuyerReview[] contracts Contract[] seasonHarvests SeasonHarvest[] @@map("farmers") } model Buyer { id String @id @default(cuid()) userId String @unique buyerCode String @unique name String company String? phone String? email String? address String? // Enhanced buyer details buyerType BuyerType? businessLicense String? taxNumber String? contactPerson String? contactPersonPhone String? paymentTerms Int? // days creditLimit Decimal? preferredProducts String[] qualityRequirements String? // Location and logistics warehouseAddress String? deliveryPreference String? operatingRadius Decimal? // km // Business details businessSize BusinessSize? yearEstablished Int? annualVolume Decimal? // estimated annual purchase volume employeeCount Int? website String? // Financial information bankAccount String? bankName String? accountHolderName String? // Verification and status isVerified Boolean @default(false) verificationDate DateTime? verifiedBy String? // admin ID who verified verificationNotes String? status BuyerStatus @default(ACTIVE) // Photos and documents profilePhotoUrl String? businessLicenseUrl String? taxCertificateUrl String? // Preferences preferredPickupDays String[] // Mon, Tue, Wed, etc. preferredPickupTime String? minimumOrderQuantity Decimal? maximumOrderQuantity Decimal? notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) procurements Procurement[] reviews BuyerReview[] contracts Contract[] @@map("buyers") } model Administrator { id String @id @default(cuid()) userId String @unique adminCode String @unique name String phone String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@map("administrators") } model Farm { id String @id @default(cuid()) farmerId String farmCode String @unique name String address String? village String? district String? province String? postalCode String? area Decimal? // in hectares // Location data latitude Float? longitude Float? boundaries Json? // GeoJSON polygon for farm boundaries elevation Float? // meters above sea level // Farm characteristics soilType String? soilPH Float? waterSource WaterSource? irrigationType IrrigationType? slope SlopeType? climate ClimateType? // Infrastructure hasElectricity Boolean? @default(false) hasWaterAccess Boolean? @default(false) hasStorageFacility Boolean? @default(false) hasProcessingUnit Boolean? @default(false) accessRoadType RoadType? // Photos and documentation mainPhotoUrl String? aerialPhotoUrl String? soilPhotoUrl String? // Ownership and legal ownershipType FarmOwnership? landCertificateNumber String? landCertificateUrl String? // Agricultural details establishedYear Int? totalInvestment Decimal? annualProduction Decimal? // estimated kg per year mainCrops String[] // primary crops grown farmingSystem FarmingSystem? organicCertified Boolean? @default(false) description String? notes String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer @relation(fields: [farmerId], references: [id], onDelete: Cascade) plots Plot[] harvests Harvest[] attachments FarmAttachment[] weatherData WeatherData[] weatherForecasts WeatherForecast[] inputs FarmInput[] inputSchedules InputSchedule[] laborRecords LaborRecord[] laborSchedules LaborSchedule[] equipmentUsage EquipmentUsage[] pestDiseaseRecords PestDiseaseRecord[] financialRecords FinancialRecord[] soilTests SoilTest[] @@map("farms") } model Plot { id String @id @default(cuid()) farmId String name String area Decimal? // in hectares productId String? variantId String? plantedDate DateTime? boundaries Json? // GeoJSON polygon for plot boundaries description String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farm Farm @relation(fields: [farmId], references: [id], onDelete: Cascade) product Product? @relation(fields: [productId], references: [id]) variant ProductVariant? @relation(fields: [variantId], references: [id]) harvests Harvest[] weatherData WeatherData[] weatherForecasts WeatherForecast[] inputs FarmInput[] inputSchedules InputSchedule[] laborRecords LaborRecord[] laborSchedules LaborSchedule[] equipmentUsage EquipmentUsage[] pestDiseaseRecords PestDiseaseRecord[] financialRecords FinancialRecord[] soilTests SoilTest[] seasons PlotSeason[] @@map("plots") } model Harvest { id String @id @default(cuid()) farmerId String farmId String plotId String? variantId String quantity Decimal // in kg harvestDate DateTime qualityGrade QualityGrade waterContent Decimal? // percentage density Decimal? // kg/m3 notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer @relation(fields: [farmerId], references: [id]) farm Farm @relation(fields: [farmId], references: [id]) plot Plot? @relation(fields: [plotId], references: [id]) variant ProductVariant @relation(fields: [variantId], references: [id]) procurement Procurement? modifiers HarvestModifier[] @@map("harvests") } model Procurement { id String @id @default(cuid()) procurementCode String @unique farmerId String buyerId String? harvestId String @unique variantId String // Quantity and quality details quantity Decimal // in kg qualityGrade QualityGrade waterContent Decimal? // percentage density Decimal? // kg/m3 // Pricing details basePrice Decimal // price per kg premiumRate Decimal @default(0) // percentage totalPrice Decimal transportCost Decimal? @default(0) processingCost Decimal? @default(0) finalAmount Decimal // total amount to be paid // Location and logistics pickupLocation String? deliveryLocation String? pickupDate DateTime? deliveryDate DateTime? transportMethod String? // truck, motorcycle, etc. // Quality assessment assessedBy String? // quality assessor ID assessmentDate DateTime? assessmentNotes String? rejectedQuantity Decimal? @default(0) rejectionReason String? // Payment details paymentMethod PaymentMethod? paymentReference String? bankAccount String? // Status and tracking status ProcurementStatus @default(PENDING) procurementDate DateTime @default(now()) approvedDate DateTime? approvedBy String? // admin ID who approved paymentDate DateTime? completedDate DateTime? // Documentation contractId String? // link to formal contract contractNumber String? invoiceNumber String? receiptNumber String? notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer @relation(fields: [farmerId], references: [id]) buyer Buyer? @relation(fields: [buyerId], references: [id]) harvest Harvest @relation(fields: [harvestId], references: [id]) variant ProductVariant @relation(fields: [variantId], references: [id]) contract Contract? @relation(fields: [contractId], references: [id]) attachments ProcurementAttachment[] @@map("procurements") } model HarvestModifier { id String @id @default(cuid()) harvestId String modifierId String value String // actual value applied adjustment Decimal? // calculated price adjustment createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations harvest Harvest @relation(fields: [harvestId], references: [id], onDelete: Cascade) modifier ProductModifier @relation(fields: [modifierId], references: [id]) @@unique([harvestId, modifierId]) @@map("harvest_modifiers") } model FarmerAttachment { id String @id @default(cuid()) farmerId String type AttachmentType title String description String? fileUrl String fileName String fileSize Int? // in bytes mimeType String? uploadedBy String? // user ID who uploaded isVerified Boolean @default(false) verifiedBy String? // admin ID who verified verifiedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer @relation(fields: [farmerId], references: [id], onDelete: Cascade) @@map("farmer_attachments") } model FarmAttachment { id String @id @default(cuid()) farmId String type FarmAttachmentType title String description String? fileUrl String fileName String fileSize Int? // in bytes mimeType String? uploadedBy String? // user ID who uploaded takenDate DateTime? // when photo was taken gpsLocation Json? // GeoJSON point where photo was taken isVerified Boolean @default(false) verifiedBy String? // admin ID who verified verifiedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farm Farm @relation(fields: [farmId], references: [id], onDelete: Cascade) @@map("farm_attachments") } model ProcurementAttachment { id String @id @default(cuid()) procurementId String type ProcurementAttachmentType title String description String? fileUrl String fileName String fileSize Int? // in bytes mimeType String? uploadedBy String? // user ID who uploaded takenDate DateTime? // when photo was taken gpsLocation Json? // GeoJSON point where photo was taken isVerified Boolean @default(false) verifiedBy String? // admin ID who verified verifiedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations procurement Procurement @relation(fields: [procurementId], references: [id], onDelete: Cascade) @@map("procurement_attachments") } model Training { id String @id @default(cuid()) title String description String? content String? category String duration Int? // in minutes level String? // beginner, intermediate, advanced isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmerTrainings FarmerTraining[] @@map("trainings") } model FarmerTraining { id String @id @default(cuid()) farmerId String trainingId String status TrainingStatus @default(ENROLLED) progress Int @default(0) // percentage score Float? completedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer @relation(fields: [farmerId], references: [id], onDelete: Cascade) training Training @relation(fields: [trainingId], references: [id], onDelete: Cascade) @@unique([farmerId, trainingId]) @@map("farmer_trainings") } model Certification { id String @id @default(cuid()) name String description String? validityPeriod Int? // in months requirements String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmerCertifications FarmerCertification[] @@map("certifications") } model FarmerCertification { id String @id @default(cuid()) farmerId String certificationId String status CertificationStatus @default(PENDING) issuedDate DateTime? expiryDate DateTime? certificateNumber String? notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer @relation(fields: [farmerId], references: [id], onDelete: Cascade) certification Certification @relation(fields: [certificationId], references: [id], onDelete: Cascade) @@unique([farmerId, certificationId]) @@map("farmer_certifications") } model Article { id String @id @default(cuid()) title String content String excerpt String? category String tags String[] author String? status ArticleStatus @default(DRAFT) views BigInt @default(0) publishedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("articles") } model Product { id String @id @default(cuid()) name String // e.g., "Pepper" code String @unique description String? category String unit String @default("kg") // kg, ton, etc isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations plots Plot[] variants ProductVariant[] modifiers ProductModifier[] contracts Contract[] priceHistory PriceHistory[] marketPrices MarketPrice[] marketDemand MarketDemand[] plotSeasons PlotSeason[] seasonHarvests SeasonHarvest[] @@map("products") } model ProductVariant { id String @id @default(cuid()) productId String name String // e.g., "Black Pepper", "White Pepper" code String @unique description String? basePrice Decimal? // default base price isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations product Product @relation(fields: [productId], references: [id], onDelete: Cascade) plots Plot[] harvests Harvest[] procurements Procurement[] contracts Contract[] priceHistory PriceHistory[] marketPrices MarketPrice[] marketDemand MarketDemand[] plotSeasons PlotSeason[] seasonHarvests SeasonHarvest[] @@map("product_variants") } model ProductModifier { id String @id @default(cuid()) productId String name String // e.g., "Water Content", "Density" code String description String? selectionType ModifierSelectionType @default(INPUT) nominalType NominalType @default(NOMINAL) options String[] // For dropdown selections minimum Decimal? maximum Decimal? unit String? // %, kg/m3, etc isRequired Boolean @default(false) isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations product Product @relation(fields: [productId], references: [id], onDelete: Cascade) rules ProductModifierRule[] harvestModifiers HarvestModifier[] @@unique([productId, code]) @@map("product_modifiers") } model ProductModifierRule { id String @id @default(cuid()) modifierId String condition RuleCondition priceAdjustment Decimal // amount to adjust price value String? // For equals condition minValue Decimal? // For lessThan or between conditions maxValue Decimal? // For greaterThan or between conditions description String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations modifier ProductModifier @relation(fields: [modifierId], references: [id], onDelete: Cascade) @@map("product_modifier_rules") } model PriceHistory { id String @id @default(cuid()) productId String? variantId String? qualityGrade QualityGrade basePrice Decimal marketPrice Decimal? premiumRate Decimal @default(0) effectiveDate DateTime region String? notes String? createdAt DateTime @default(now()) // Relations product Product? @relation(fields: [productId], references: [id]) variant ProductVariant? @relation(fields: [variantId], references: [id]) @@map("price_history") } model WeatherData { id String @id @default(cuid()) farmId String? plotId String? latitude Float longitude Float date DateTime temperature Float? // celsius humidity Float? // percentage rainfall Float? // mm windSpeed Float? // km/h windDirection String? // N, NE, E, SE, S, SW, W, NW pressure Float? // hPa uvIndex Float? visibility Float? // km weatherCondition String? // sunny, cloudy, rainy, etc. dataSource String? // manual, weather_station, api createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farm Farm? @relation(fields: [farmId], references: [id]) plot Plot? @relation(fields: [plotId], references: [id]) @@map("weather_data") } model WeatherForecast { id String @id @default(cuid()) farmId String? plotId String? latitude Float longitude Float forecastDate DateTime minTemperature Float? maxTemperature Float? humidity Float? rainfall Float? windSpeed Float? weatherCondition String? confidence Float? // percentage source String createdAt DateTime @default(now()) // Relations farm Farm? @relation(fields: [farmId], references: [id]) plot Plot? @relation(fields: [plotId], references: [id]) @@map("weather_forecasts") } model FarmInput { id String @id @default(cuid()) farmId String plotId String? inputType InputType productName String brand String? quantity Decimal unit String cost Decimal supplier String? supplierContact String? batchNumber String? expiryDate DateTime? applicationDate DateTime? applicationMethod String? applicationRate String? // per hectare or per plant activeIngredient String? // for pesticides/fertilizers concentration Decimal? // percentage notes String? invoiceNumber String? receiptUrl String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farm Farm @relation(fields: [farmId], references: [id]) plot Plot? @relation(fields: [plotId], references: [id]) @@map("farm_inputs") } model InputSchedule { id String @id @default(cuid()) farmId String plotId String? inputType InputType productName String scheduledDate DateTime quantity Decimal unit String method String? status ScheduleStatus @default(PENDING) appliedDate DateTime? appliedBy String? actualQuantity Decimal? notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farm Farm @relation(fields: [farmId], references: [id]) plot Plot? @relation(fields: [plotId], references: [id]) @@map("input_schedules") } model Supplier { id String @id @default(cuid()) name String contactPerson String? phone String? email String? address String? supplierType SupplierType paymentTerms String? deliveryTerms String? qualityCertifications String[] isActive Boolean @default(true) notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("suppliers") } model FarmWorker { id String @id @default(cuid()) farmerId String workerCode String @unique name String phone String? email String? address String? identityNumber String? role WorkerRole skillLevel SkillLevel? dailyWage Decimal? monthlyWage Decimal? paymentMethod PaymentMethod? bankAccount String? emergencyContact String? emergencyPhone String? hireDate DateTime? contractType ContractType? contractEnd DateTime? isActive Boolean @default(true) notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer @relation(fields: [farmerId], references: [id]) laborRecords LaborRecord[] laborSchedules LaborSchedule[] @@map("farm_workers") } model LaborRecord { id String @id @default(cuid()) farmerId String farmId String workerId String? plotId String? workType WorkType hoursWorked Decimal wages Decimal workDate DateTime startTime DateTime? endTime DateTime? description String? supervisor String? // supervisor name or ID qualityRating Decimal? // 1-5 rating weather String? notes String? approved Boolean @default(false) approvedBy String? approvedDate DateTime? paymentStatus PaymentStatus @default(PENDING) paidDate DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer @relation(fields: [farmerId], references: [id]) farm Farm @relation(fields: [farmId], references: [id]) worker FarmWorker? @relation(fields: [workerId], references: [id]) plot Plot? @relation(fields: [plotId], references: [id]) @@map("labor_records") } model LaborSchedule { id String @id @default(cuid()) farmerId String farmId String workerId String? plotId String? workType WorkType scheduledDate DateTime estimatedHours Decimal estimatedWage Decimal? status ScheduleStatus @default(PENDING) assignedBy String? notes String? actualRecord String? // reference to LaborRecord ID createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer @relation(fields: [farmerId], references: [id]) farm Farm @relation(fields: [farmId], references: [id]) worker FarmWorker? @relation(fields: [workerId], references: [id]) plot Plot? @relation(fields: [plotId], references: [id]) @@map("labor_schedules") } model Equipment { id String @id @default(cuid()) farmerId String equipmentCode String @unique name String type EquipmentType brand String? model String? serialNumber String? purchaseDate DateTime? purchasePrice Decimal? currentValue Decimal? condition EquipmentCondition status EquipmentStatus @default(ACTIVE) location String? // where equipment is stored fuelType String? // diesel, petrol, electric, manual capacity String? // engine capacity, load capacity powerRating String? // horsepower, wattage yearManufactured Int? warranty String? insurancePolicy String? insuranceExpiry DateTime? lastMaintenance DateTime? nextMaintenance DateTime? maintenanceCost Decimal? operatingHours Decimal? // total operating hours isActive Boolean @default(true) notes String? photoUrl String? manualUrl String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer @relation(fields: [farmerId], references: [id]) maintenanceRecords MaintenanceRecord[] usageRecords EquipmentUsage[] @@map("equipment") } model MaintenanceRecord { id String @id @default(cuid()) equipmentId String maintenanceType MaintenanceType description String cost Decimal serviceProvider String? serviceDate DateTime nextServiceDue DateTime? partsReplaced String[] laborHours Decimal? invoiceNumber String? receiptUrl String? performedBy String? notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations equipment Equipment @relation(fields: [equipmentId], references: [id]) @@map("maintenance_records") } model EquipmentUsage { id String @id @default(cuid()) equipmentId String farmId String? plotId String? operatorName String? usageDate DateTime startTime DateTime? endTime DateTime? hoursUsed Decimal fuelConsumed Decimal? workType WorkType? description String? meterReading Decimal? // odometer, hour meter reading notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations equipment Equipment @relation(fields: [equipmentId], references: [id]) farm Farm? @relation(fields: [farmId], references: [id]) plot Plot? @relation(fields: [plotId], references: [id]) @@map("equipment_usage") } model Asset { id String @id @default(cuid()) farmerId String assetCode String @unique name String type AssetType category String? // building, land improvement, infrastructure description String? purchaseDate DateTime? purchasePrice Decimal? currentValue Decimal? depreciation Decimal? // annual depreciation rate condition AssetCondition location String? size String? // dimensions, area material String? // construction material lifespan Int? // expected lifespan in years warrantyExpiry DateTime? insurancePolicy String? insuranceExpiry DateTime? photoUrls String[] documentUrls String[] isActive Boolean @default(true) notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer @relation(fields: [farmerId], references: [id]) @@map("assets") } model BuyerReview { id String @id @default(cuid()) buyerId String farmerId String rating Decimal // 1-5 rating comment String? reviewType ReviewType procurementId String? // reference to procurement if applicable isAnonymous Boolean @default(false) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations buyer Buyer @relation(fields: [buyerId], references: [id]) farmer Farmer @relation(fields: [farmerId], references: [id]) @@map("buyer_reviews") } model PestDiseaseRecord { id String @id @default(cuid()) farmId String plotId String? type PestDiseaseType name String scientificName String? severity SeverityLevel affectedArea Decimal? // percentage or hectares identifiedDate DateTime identifiedBy String? // farmer, expert, etc. symptoms String? treatmentApplied String? treatmentDate DateTime? treatmentCost Decimal? treatmentMethod String? preventionTaken String? resolved Boolean @default(false) resolvedDate DateTime? recurrence Boolean @default(false) photos String[] // photo URLs notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farm Farm @relation(fields: [farmId], references: [id]) plot Plot? @relation(fields: [plotId], references: [id]) @@map("pest_disease_records") } model FinancialRecord { id String @id @default(cuid()) farmerId String farmId String? plotId String? type TransactionType category String subcategory String? amount Decimal currencyId String @default("idr") currency Currency @relation(fields: [currencyId], references: [id]) description String transactionDate DateTime paymentMethod PaymentMethod? receiptNumber String? invoiceNumber String? referenceNumber String? taxAmount Decimal? @default(0) bankAccount String? payee String? // who received payment approvedBy String? // admin who approved status TransactionStatus @default(PENDING) notes String? attachmentUrls String[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer @relation(fields: [farmerId], references: [id]) farm Farm? @relation(fields: [farmId], references: [id]) plot Plot? @relation(fields: [plotId], references: [id]) @@map("financial_records") } model SoilTest { id String @id @default(cuid()) farmId String plotId String? testCode String @unique testDate DateTime sampleDepth Decimal? // cm sampleLocation String? gpsCoordinates Json? // GeoJSON point // Basic soil properties pH Decimal? organicMatter Decimal? // percentage soilTexture String? // clay, sand, loam, etc. bulkDensity Decimal? // g/cm³ porosity Decimal? // percentage // Nutrients (ppm) nitrogen Decimal? phosphorus Decimal? potassium Decimal? calcium Decimal? magnesium Decimal? sulfur Decimal? // Micronutrients (ppm) zinc Decimal? iron Decimal? manganese Decimal? copper Decimal? boron Decimal? // Other properties conductivity Decimal? // dS/m cationExchangeCapacity Decimal? // cmol/kg baseStaturation Decimal? // percentage carbonNitrogenRatio Decimal? // Analysis details recommendations String? testLaboratory String? technicianName String? testCost Decimal? reportUrl String? notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farm Farm @relation(fields: [farmId], references: [id]) plot Plot? @relation(fields: [plotId], references: [id]) @@map("soil_tests") } model EducationLevel { id String @id @default(cuid()) name String @unique level Int // 0=No formal, 1=Elementary, etc. description String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmers Farmer[] @@map("education_levels") } model Currency { id String @id // ISO currency code like "idr", "usd" name String @unique code String @unique // ISO 4217 currency code symbol String // €, $, Rp, etc. isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations financialRecords FinancialRecord[] @@map("currencies") } model Country { id String @id // ISO country code like "indonesia", "malaysia" name String @unique code String @unique // ISO 3166-1 alpha-2 code region String? continent String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmerNationalities Farmer[] @relation("FarmerNationality") farmerCountries Farmer[] @relation("FarmerCountry") @@map("countries") } model Religion { id String @id @default(cuid()) name String @unique description String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmers Farmer[] @@map("religions") } model Message { id String @id @default(cuid()) senderId String receiverId String? groupId String? subject String? content String messageType MessageType priority Priority @default(NORMAL) isRead Boolean @default(false) readAt DateTime? attachments String[] // file URLs deliveryStatus MessageStatus @default(SENT) sentAt DateTime @default(now()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("messages") } model MarketPrice { id String @id @default(cuid()) productId String variantId String? market String region String price Decimal unit String @default("kg") qualityGrade QualityGrade priceDate DateTime source String? // where price data came from volume Decimal? // trading volume trend PriceTrend? verified Boolean @default(false) verifiedBy String? notes String? createdAt DateTime @default(now()) // Relations product Product @relation(fields: [productId], references: [id]) variant ProductVariant? @relation(fields: [variantId], references: [id]) @@map("market_prices") } model Contract { id String @id @default(cuid()) contractNumber String @unique farmerId String buyerId String productId String? variantId String? // Contract terms title String description String? contractType AgreementType @default(PURCHASE_AGREEMENT) // Pricing and quantity agreedPrice Decimal // price per unit minimumQuantity Decimal? maximumQuantity Decimal? totalValue Decimal? unit String @default("kg") // Quality specifications qualityGrade QualityGrade? qualityRequirements String? // Timeline startDate DateTime endDate DateTime deliverySchedule String? // delivery frequency/schedule // Payment terms paymentTerms String? // payment conditions paymentMethod PaymentMethod? advancePayment Decimal? @default(0) advancePercentage Decimal? @default(0) // Legal and compliance terms String? // full terms and conditions penalties String? // penalty clauses forcemajeure String? // force majeure clause governingLaw String? // applicable law // Status and tracking status ContractStatus @default(DRAFT) signedDate DateTime? signedByFarmer Boolean @default(false) signedByBuyer Boolean @default(false) farmerSignature String? // signature data or URL buyerSignature String? // signature data or URL witnessName String? witnessSignature String? // Performance tracking totalDelivered Decimal? @default(0) totalPaid Decimal? @default(0) deliveryCount Int @default(0) // Renewal and amendments renewalDate DateTime? amendmentCount Int @default(0) parentContractId String? // for contract renewals // Documentation documentUrl String? // contract document attachmentUrls String[] // supporting documents notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations farmer Farmer @relation(fields: [farmerId], references: [id]) buyer Buyer @relation(fields: [buyerId], references: [id]) product Product? @relation(fields: [productId], references: [id]) variant ProductVariant? @relation(fields: [variantId], references: [id]) parentContract Contract? @relation("ContractRenewal", fields: [parentContractId], references: [id]) renewalContracts Contract[] @relation("ContractRenewal") procurements Procurement[] // deliveries under this contract @@map("contracts") } model Notification { id String @id @default(cuid()) title String message String type NotificationType category NotificationCategory @default(GENERAL) priority Priority @default(NORMAL) // Recipients recipientId String? // specific user ID recipientType UserRole? // or broadcast to user type recipientIds String[] // multiple specific users // Targeting farmerIds String[] // specific farmers buyerIds String[] // specific buyers region String? // geographic targeting productIds String[] // product-specific notifications // Content and media content String? // detailed content/body imageUrl String? actionUrl String? // deep link or action URL actionLabel String? // button text // Scheduling scheduledAt DateTime? // for scheduled notifications expiresAt DateTime? // expiration date // Status tracking status NotificationStatus @default(PENDING) sentAt DateTime? deliveredCount Int @default(0) readCount Int @default(0) clickCount Int @default(0) // Metadata source String? // system, admin, automated, etc. sourceId String? // reference to source entity tags String[] // for categorization metadata Json? // additional data // Tracking isRead Boolean @default(false) readAt DateTime? isClicked Boolean @default(false) clickedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations recipients NotificationRecipient[] @@map("notifications") } model NotificationRecipient { id String @id @default(cuid()) notificationId String userId String isRead Boolean @default(false) readAt DateTime? isClicked Boolean @default(false) clickedAt DateTime? isDelivered Boolean @default(false) deliveredAt DateTime? createdAt DateTime @default(now()) // Relations notification Notification @relation(fields: [notificationId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([notificationId, userId]) @@map("notification_recipients") } model Season { id String @id @default(cuid()) name String // e.g., "Wet Season 2024", "Dry Season 2024" seasonType SeasonType year Int // Timeline startDate DateTime endDate DateTime // Weather characteristics avgRainfall Decimal? // mm avgTemperature Float? // celsius avgHumidity Decimal? // percentage // Agricultural phases plantingStart DateTime? plantingEnd DateTime? growingStart DateTime? growingEnd DateTime? harvestStart DateTime? harvestEnd DateTime? // Region and scope region String? province String? country String @default("Indonesia") // Crop recommendations recommendedCrops String[] // suitable crops for this season notRecommendedCrops String[] // crops to avoid // Market expectations expectedDemand DemandLevel? priceOutlook PriceTrend? marketNotes String? // Agricultural activities activities Json? // structured data for farming activities // Status isActive Boolean @default(true) isCurrent Boolean @default(false) description String? notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations plots PlotSeason[] harvests SeasonHarvest[] weatherData SeasonWeather[] @@unique([seasonType, year, region]) @@map("seasons") } model PlotSeason { id String @id @default(cuid()) plotId String seasonId String productId String? variantId String? // Planting details plantedDate DateTime? plantedArea Decimal? // hectares actually planted seedVariety String? // Expected outcomes expectedYield Decimal? // kg per hectare expectedHarvest Decimal? // total kg expected expectedHarvestDate DateTime? // Actual outcomes actualYield Decimal? // kg per hectare actualHarvest Decimal? // total kg harvested actualHarvestDate DateTime? status PlantingStatus @default(PLANNED) notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations plot Plot @relation(fields: [plotId], references: [id]) season Season @relation(fields: [seasonId], references: [id]) product Product? @relation(fields: [productId], references: [id]) variant ProductVariant? @relation(fields: [variantId], references: [id]) @@unique([plotId, seasonId]) @@map("plot_seasons") } model SeasonHarvest { id String @id @default(cuid()) seasonId String farmerId String productId String variantId String? totalQuantity Decimal averageQuality QualityGrade totalValue Decimal harvestCount Int @default(1) firstHarvest DateTime lastHarvest DateTime? notes String? createdAt DateTime @default(now()) // Relations season Season @relation(fields: [seasonId], references: [id]) farmer Farmer @relation(fields: [farmerId], references: [id]) product Product @relation(fields: [productId], references: [id]) variant ProductVariant? @relation(fields: [variantId], references: [id]) @@map("season_harvests") } model SeasonWeather { id String @id @default(cuid()) seasonId String region String // Aggregated weather data totalRainfall Decimal? // mm avgTemperature Float? // celsius minTemperature Float? // celsius maxTemperature Float? // celsius avgHumidity Decimal? // percentage // Extreme events droughtDays Int? @default(0) floodDays Int? @default(0) stormCount Int? @default(0) // Impact assessment cropDamage Decimal? // percentage yieldImpact Decimal? // percentage change notes String? createdAt DateTime @default(now()) // Relations season Season @relation(fields: [seasonId], references: [id]) @@unique([seasonId, region]) @@map("season_weather") } model MarketDemand { id String @id @default(cuid()) productId String variantId String? region String demandLevel DemandLevel estimatedVolume Decimal? priceRange String? season String? factors String[] // factors affecting demand forecastDate DateTime forecastBy String? accuracy Decimal? // percentage notes String? createdAt DateTime @default(now()) // Relations product Product @relation(fields: [productId], references: [id]) variant ProductVariant? @relation(fields: [variantId], references: [id]) @@map("market_demand") } // Enums enum UserRole { FARMER BUYER ADMINISTRATOR } enum QualityGrade { A B C } enum ProcurementStatus { PENDING QUALITY_ASSESSMENT APPROVED REJECTED IN_TRANSIT DELIVERED INVOICED PAID COMPLETED CANCELLED PARTIALLY_REJECTED } enum TrainingStatus { ENROLLED IN_PROGRESS COMPLETED DROPPED } enum CertificationStatus { PENDING APPROVED REJECTED EXPIRED } enum ArticleStatus { DRAFT PUBLISHED ARCHIVED } enum ModifierSelectionType { DROPDOWN INPUT } enum NominalType { NOMINAL PERCENTAGE } enum RuleCondition { EQUALS LESS_THAN GREATER_THAN BETWEEN } enum Gender { MALE FEMALE OTHER } enum IdentityType { KTP // Indonesian ID Card PASSPORT DRIVING_LICENSE OTHER } // EducationLevel enum converted to table above enum FarmerStatus { ACTIVE INACTIVE SUSPENDED PENDING_VERIFICATION BLACKLISTED } enum AttachmentType { PROFILE_PHOTO ID_CARD_FRONT ID_CARD_BACK FARMING_LICENSE LAND_CERTIFICATE BANK_STATEMENT CONTRACT CERTIFICATE OTHER_DOCUMENT } enum MaritalStatus { SINGLE MARRIED DIVORCED WIDOWED SEPARATED } // Religion enum converted to table above enum LandOwnership { OWNER TENANT SHARECROPPER COOPERATIVE_MEMBER GOVERNMENT_LEASE FAMILY_LAND OTHER } enum WaterSource { RAIN_FED IRRIGATION_CANAL WELL RIVER POND GROUNDWATER SPRING MIXED } enum IrrigationType { FLOOD SPRINKLER DRIP FURROW MANUAL NONE } enum SlopeType { FLAT GENTLE MODERATE STEEP VERY_STEEP } enum ClimateType { TROPICAL_WET TROPICAL_DRY SUBTROPICAL TEMPERATE HIGHLAND } enum RoadType { PAVED GRAVEL DIRT FOOTPATH NO_ACCESS } enum FarmOwnership { PRIVATE_OWNED LEASED SHARECROPPED COOPERATIVE GOVERNMENT COMMUNAL FAMILY_INHERITED } enum FarmingSystem { MONOCULTURE POLYCULTURE MIXED_FARMING ORGANIC CONVENTIONAL INTEGRATED PERMACULTURE AGROFORESTRY } enum FarmAttachmentType { MAIN_PHOTO AERIAL_PHOTO SOIL_PHOTO CROP_PHOTO INFRASTRUCTURE_PHOTO LAND_CERTIFICATE SURVEY_MAP WATER_SOURCE_PHOTO ENTRANCE_PHOTO BOUNDARY_PHOTO EQUIPMENT_PHOTO STORAGE_PHOTO OTHER_DOCUMENT } enum PaymentMethod { CASH BANK_TRANSFER MOBILE_MONEY CHECK DIGITAL_WALLET CREDIT BARTER INSTALLMENT } enum ProcurementAttachmentType { PRODUCT_PHOTO QUALITY_ASSESSMENT_PHOTO WEIGHING_PHOTO PACKAGING_PHOTO LOADING_PHOTO DELIVERY_PHOTO CONTRACT_DOCUMENT INVOICE RECEIPT PAYMENT_PROOF QUALITY_CERTIFICATE TRANSPORT_DOCUMENT REJECTION_PHOTO SIGNATURE_DOCUMENT OTHER_DOCUMENT } // Input Management Enums enum InputType { SEED FERTILIZER PESTICIDE HERBICIDE FUNGICIDE INSECTICIDE EQUIPMENT_RENTAL FUEL IRRIGATION_WATER MULCH COMPOST LIME OTHER } enum ScheduleStatus { PENDING SCHEDULED IN_PROGRESS COMPLETED CANCELLED OVERDUE } enum SupplierType { SEED_SUPPLIER FERTILIZER_SUPPLIER PESTICIDE_SUPPLIER EQUIPMENT_SUPPLIER GENERAL_SUPPLIER COOPERATIVE GOVERNMENT_AGENCY } // Labor Management Enums enum WorkerRole { PERMANENT SEASONAL DAILY CONTRACTOR SUPERVISOR FOREMAN SPECIALIST } enum SkillLevel { BEGINNER INTERMEDIATE ADVANCED EXPERT } enum ContractType { PERMANENT TEMPORARY SEASONAL PROJECT_BASED DAILY } enum WorkType { PLANTING WEEDING FERTILIZING HARVESTING IRRIGATION PEST_CONTROL SOIL_PREPARATION PRUNING GENERAL_MAINTENANCE EQUIPMENT_OPERATION PROCESSING PACKAGING TRANSPORT } enum PaymentStatus { PENDING APPROVED PAID OVERDUE CANCELLED } // Equipment & Asset Enums enum EquipmentType { TRACTOR HARVESTER PLANTER CULTIVATOR IRRIGATION_SYSTEM SPRAYER THRESHER MOWER TOOLS VEHICLE PROCESSING_EQUIPMENT STORAGE_EQUIPMENT } enum EquipmentCondition { EXCELLENT GOOD FAIR POOR NEEDS_REPAIR OUT_OF_ORDER } enum EquipmentStatus { ACTIVE INACTIVE MAINTENANCE REPAIR RETIRED } enum MaintenanceType { PREVENTIVE CORRECTIVE EMERGENCY OVERHAUL INSPECTION CALIBRATION } enum AssetType { BUILDING LAND_IMPROVEMENT INFRASTRUCTURE VEHICLE MACHINERY FURNITURE TECHNOLOGY OTHER } enum AssetCondition { NEW EXCELLENT GOOD FAIR POOR DAMAGED } // Buyer Enums enum BuyerType { INDIVIDUAL WHOLESALER RETAILER PROCESSOR EXPORTER COOPERATIVE GOVERNMENT RESTAURANT HOTEL } enum BusinessSize { MICRO SMALL MEDIUM LARGE ENTERPRISE } enum BuyerStatus { ACTIVE INACTIVE SUSPENDED PENDING_VERIFICATION BLACKLISTED } enum ReviewType { PAYMENT_TIMELINESS QUALITY_REQUIREMENTS COMMUNICATION OVERALL_EXPERIENCE PRICE_FAIRNESS } // Pest & Disease Enums enum PestDiseaseType { PEST DISEASE WEED NUTRIENT_DEFICIENCY VIRUS FUNGUS BACTERIA } enum SeverityLevel { LOW MEDIUM HIGH CRITICAL CATASTROPHIC } // Financial Enums enum TransactionType { INCOME EXPENSE INVESTMENT LOAN LOAN_PAYMENT INSURANCE_PAYMENT TAX_PAYMENT GRANT SUBSIDY REFUND } enum TransactionStatus { PENDING APPROVED COMPLETED REJECTED CANCELLED FAILED } // Notification Enums enum NotificationType { SYSTEM ANNOUNCEMENT ALERT REMINDER PROMOTION UPDATE WARNING INFO SUCCESS ERROR } enum NotificationCategory { GENERAL PROCUREMENT PAYMENT QUALITY WEATHER PRICE_ALERT TRAINING CERTIFICATION MAINTENANCE HARVEST PLANTING MARKET CONTRACT COMPLIANCE } enum NotificationStatus { PENDING SCHEDULED SENT DELIVERED FAILED CANCELLED EXPIRED } // Communication Enums enum MessageType { PERSONAL BROADCAST NOTIFICATION ALERT SYSTEM ANNOUNCEMENT } enum Priority { LOW NORMAL HIGH URGENT CRITICAL } enum MessageStatus { SENT DELIVERED READ FAILED PENDING } // Contract Enums enum AgreementType { PURCHASE_AGREEMENT SUPPLY_CONTRACT EXCLUSIVE_SUPPLY SEASONAL_CONTRACT FORWARD_CONTRACT SPOT_CONTRACT CONSIGNMENT PARTNERSHIP } enum ContractStatus { DRAFT PENDING_REVIEW PENDING_SIGNATURE ACTIVE FULFILLED EXPIRED TERMINATED CANCELLED BREACH RENEWED } // Season Enums enum SeasonType { WET_SEASON DRY_SEASON TRANSITION YEAR_ROUND SPRING SUMMER FALL WINTER } enum PlantingStatus { PLANNED PLANTED GROWING FLOWERING FRUITING HARVESTING HARVESTED FAILED ABANDONED } // Market Intelligence Enums enum PriceTrend { RISING FALLING STABLE VOLATILE } enum DemandLevel { VERY_LOW LOW MODERATE HIGH VERY_HIGH EXCESSIVE }