Cultivos
Los cultivos (crops) representan lotes de plantas en proceso de crecimiento. Esta API permite gestionar el ciclo completo de cultivo, desde la siembra hasta la cosecha, incluyendo cambios de etapa, registro de actividades y seguimiento de progreso.
La API de Cultivos es actualmente una implementacion mocked. Todas las operaciones funcionan correctamente pero no persisten datos en un backend real.
El modelo de Cultivo
El modelo de cultivo contiene informacion completa sobre el lote de plantas, su estado actual, historial y configuracion.
Propiedades
- Name
id- Type
- string
- Description
Identificador unico del cultivo.
- Name
name- Type
- string
- Description
Nombre descriptivo del cultivo.
- Name
strain- Type
- object
- Description
Cepa asociada al cultivo.
- Name
id- Type
- string
- Description
ID de la cepa.
- Name
name- Type
- string
- Description
Nombre de la cepa.
- Name
status- Type
- CropStatus
- Description
Estado actual del cultivo. Campo principal que reemplaza al legacy
stage.
- Name
plantedAt- Type
- timestamp
- Description
Fecha de siembra/inicio.
- Name
expectedHarvestDate- Type
- timestamp
- Description
Fecha estimada de cosecha.
- Name
expectedYield- Type
- number
- Description
Rendimiento esperado en gramos.
- Name
plants- Type
- array
- Description
IDs de plantas individuales.
- Name
spaces- Type
- Space[]
- Description
Espacios donde se encuentra el cultivo.
- Name
lights- Type
- Light[]
- Description
Luces asignadas al cultivo.
- Name
pot- Type
- Pot
- Description
Configuracion de maceta.
- Name
milliliters- Type
- number
- Description
Capacidad en ml.
- Name
substrate- Type
- array
- Description
Sustratos y porcentajes.
- Name
timeline- Type
- PlantInteractionLog[]
- Description
Historial de actividades del cultivo.
- Name
statusHistory- Type
- array
- Description
Historial de estados con fechas de inicio y fin.
- Name
seed- Type
- object
- Description
Semilla origen del cultivo.
- Name
createdAt- Type
- timestamp
- Description
Fecha de creacion del registro.
- Name
updatedAt- Type
- timestamp
- Description
Ultima actualizacion.
Ejemplo de cultivo
{
"id": "crop-001",
"name": "Blue Dream Indoor Batch A",
"strain": {
"id": "strain_blue_dream",
"name": "Blue Dream"
},
"status": "FLOWERING",
"plantedAt": "2024-06-15T00:00:00Z",
"expectedHarvestDate": "2024-09-15T00:00:00Z",
"expectedYield": 500,
"plants": ["plant-001", "plant-002", "plant-003"],
"spaces": [
{
"id": "space-001",
"name": "Sala de Floracion A"
}
],
"lights": [
{
"id": "light-001",
"name": "LED 600W",
"type": "LED"
}
],
"pot": {
"milliliters": 20000,
"substrate": [
{ "type": "COCO", "percentage": 70 },
{ "type": "PERLITE", "percentage": 30 }
]
},
"timeline": [...],
"statusHistory": [
{ "status": "PROPAGATING", "start": "2024-06-15", "end": "2024-06-25" },
{ "status": "VEGETATING", "start": "2024-06-25", "end": "2024-08-01" },
{ "status": "FLOWERING", "start": "2024-08-01", "end": "" }
],
"createdAt": "2024-06-15T10:00:00Z",
"updatedAt": "2024-10-01T14:30:00Z"
}
Estados del Cultivo (CropStatus)
El cultivo pasa por diferentes estados durante su ciclo de vida. El campo status es el campo principal y requerido.
El campo legacy stage (con 11 valores) está deprecado. Usar status con los 9 valores descritos a continuación.
Enum CropStatus
| Estado | Descripcion | Duracion Tipica |
|---|---|---|
IDEATING | Planificación del cultivo | Variable |
PROPAGATING | Germinación o clonación | 1-2 semanas |
VEGETATING | Fase vegetativa | 4-8 semanas |
FLOWERING | Fase de floración | 8-12 semanas |
HARVESTING | Cosecha en curso | 1-3 dias |
DRYING | Secado post-cosecha | 7-14 dias |
MANICURING | Manicurado/trimming | 1-3 dias |
CURING | Curado | 2-8 semanas |
FINISHED | Cultivo finalizado | - |
Diagrama de Flujo de Estados
Tipos de Interaccion (PlantInteraction)
Las actividades que se pueden registrar en el timeline del cultivo.
| Tipo | Descripcion | Datos Asociados |
|---|---|---|
PLANTING | Siembra inicial | - |
WATERING | Riego | pH, EC, cantidad |
FERTILIZATION | Fertilizacion | nutrientes, dosis |
TRANSPLANT | Trasplante | maceta origen/destino |
PRUNING | Poda | tecnica utilizada |
TRAINING | Entrenamiento | tecnica (LST, HST, etc.) |
LIGHT_SCHEDULE | Cambio de luz | horario on/off |
HEALTH | Estado de salud | observaciones |
OBSERVATION | Observacion general | notas |
HARVESTING | Cosecha | peso humedo |
Listar cultivos
Este endpoint permite obtener una lista filtrada de cultivos.
Parametros de Consulta
- Name
status- Type
- CropStatus
- Description
Filtrar por estado actual.
- Name
strain- Type
- string
- Description
Filtrar por ID de cepa.
- Name
spaceId- Type
- string
- Description
Filtrar por espacio.
- Name
search- Type
- string
- Description
Busqueda por nombre.
Request
curl -G https://api.cannahub.tech/api/crops \
-H "Authorization: Bearer {token}" \
-d status=FLOWERING \
-d search=blue
Response
{
"crops": [
{
"id": "crop-001",
"name": "Blue Dream Indoor Batch A",
"strain": { "id": "strain_blue_dream", "name": "Blue Dream" },
"status": "FLOWERING",
"plantedAt": "2024-06-15T00:00:00Z"
}
],
"count": 1,
"filters": {
"status": "FLOWERING",
"search": "blue"
}
}
Crear cultivo
Este endpoint permite crear un nuevo cultivo.
Campos Requeridos
- Name
name- Type
- string
- Description
Nombre del cultivo.
- Name
strain- Type
- string
- Description
ID de la cepa.
- Name
status- Type
- CropStatus
- Description
Estado inicial (default:
IDEATING).
Campos Opcionales
- Name
plantedAt- Type
- timestamp
- Description
Fecha de siembra.
- Name
expectedYield- Type
- number
- Description
Rendimiento esperado.
- Name
expectedHarvestDate- Type
- timestamp
- Description
Fecha estimada de cosecha.
- Name
pot- Type
- Pot
- Description
Configuracion de maceta.
- Name
plants- Type
- array
- Description
IDs de plantas.
- Name
seed- Type
- string
- Description
ID de semilla origen.
Request
curl -X POST https://api.cannahub.tech/api/crops \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"name": "OG Kush Lote 2024-B",
"strain": "strain_og_kush",
"strainName": "OG Kush",
"status": "IDEATING",
"expectedYield": 400,
"pot": {
"milliliters": 15000,
"substrate": [
{ "type": "SOIL", "percentage": 100 }
]
}
}'
Response (201)
{
"crop": {
"id": "crop-1698765432100",
"name": "OG Kush Lote 2024-B",
"strain": {
"id": "strain_og_kush",
"name": "OG Kush"
},
"status": "IDEATING",
"plantedAt": "2024-10-31T10:00:00Z",
"expectedYield": 400,
"createdAt": "2024-10-31T10:00:00Z"
}
}
Obtener cultivo
Este endpoint retorna los detalles de un cultivo especifico.
Request
curl https://api.cannahub.tech/api/crops/crop-001 \
-H "Authorization: Bearer {token}"
Response
{
"crop": {
"id": "crop-001",
"name": "Blue Dream Indoor Batch A",
"strain": { "id": "strain_blue_dream", "name": "Blue Dream" },
"status": "FLOWERING",
"timeline": [...],
"statusHistory": [...]
}
}
Actualizar cultivo
Este endpoint permite actualizar los datos de un cultivo.
Para cambiar el estado del cultivo, usa el endpoint /api/crops/:id/status que valida las transiciones permitidas.
Request
curl -X PATCH https://api.cannahub.tech/api/crops/crop-001 \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"expectedYield": 550,
"expectedHarvestDate": "2024-09-20T00:00:00Z"
}'
Response
{
"crop": {
"id": "crop-001",
"expectedYield": 550,
"expectedHarvestDate": "2024-09-20T00:00:00Z",
"updatedAt": "2024-10-31T10:00:00Z"
}
}
Eliminar cultivo
Este endpoint elimina un cultivo del sistema.
La eliminacion es permanente. Considera archivar cultivos en lugar de eliminarlos.
Request
curl -X DELETE https://api.cannahub.tech/api/crops/crop-001 \
-H "Authorization: Bearer {token}"
Response
{
"success": true
}
BFF: Cultivo Completo
Esta ruta BFF retorna el cultivo con todos sus datos relacionados en una sola llamada.
Datos Incluidos
- Cultivo completo con espacios expandidos
- Cepa con informacion completa
- Cosechas relacionadas
- Estadisticas calculadas
Response
- Name
crop- Type
- Crop
- Description
Cultivo completo con espacios expandidos.
- Name
strain- Type
- Strain
- Description
Informacion completa de la cepa.
- Name
harvests- Type
- array
- Description
Cosechas relacionadas.
- Name
stats- Type
- object
- Description
Estadisticas calculadas.
- Name
daysInCurrentStatus- Type
- number
- Description
Dias en el estado actual.
- Name
totalDaysFromSeed- Type
- number
- Description
Dias totales desde siembra.
- Name
totalTimelineEntries- Type
- number
- Description
Total de entradas en timeline.
- Name
wateringCount- Type
- number
- Description
Cantidad de riegos.
- Name
fertilizationCount- Type
- number
- Description
Cantidad de fertilizaciones.
- Name
totalHarvests- Type
- number
- Description
Cosechas totales.
- Name
totalDryWeight- Type
- number
- Description
Peso seco total cosechado.
Request
curl https://api.cannahub.tech/api/crops/crop-001/complete \
-H "Authorization: Bearer {token}"
Response
{
"crop": {
"id": "crop-001",
"name": "Blue Dream Indoor Batch A",
"status": "FLOWERING",
"spaces": [
{
"id": "space-001",
"name": "Sala de Floracion A",
"squareMeters": 20,
"status": "ACTIVE"
}
]
},
"strain": {
"id": "strain_blue_dream",
"name": "Blue Dream",
"type": "hybrid",
"cannabinoids": { "thc": 21, "cbd": 0.1 }
},
"harvests": [
{
"id": "harvest-001",
"name": "Blue Dream Lote #1",
"status": "STOCKED",
"dryWeight": 280
}
],
"stats": {
"daysInCurrentStatus": 45,
"totalDaysFromSeed": 120,
"totalTimelineEntries": 87,
"wateringCount": 45,
"fertilizationCount": 30,
"totalHarvests": 1,
"totalDryWeight": 280
}
}
BFF: Cambiar Estado
Esta ruta BFF permite cambiar el estado del cultivo con validacion de transiciones.
Transiciones Validas
Solo se permiten transiciones logicas entre estados. Por ejemplo:
VEGETATINGpuede ir aFLOWERINGFLOWERINGsolo puede ir aHARVESTINGFINISHEDes un estado terminal
Request
- Name
newStatus- Type
- CropStatus
- Description
Nuevo estado del cultivo.
- Name
notes- Type
- string
- Description
Notas sobre el cambio.
- Name
author- Type
- object
- Description
Usuario que realiza el cambio.
Request
curl -X POST https://api.cannahub.tech/api/crops/crop-001/status \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"newStatus": "HARVESTING",
"notes": "Tricomas ambar al 30%, listo para cosecha"
}'
Response
{
"crop": {
"id": "crop-001",
"status": "HARVESTING",
"statusHistory": [
{ "status": "FLOWERING", "start": "2024-08-01", "end": "2024-10-15" },
{ "status": "HARVESTING", "start": "2024-10-15", "end": "" }
]
},
"transition": {
"from": "FLOWERING",
"to": "HARVESTING",
"timestamp": "2024-10-15T10:00:00Z"
}
}
Error - Transicion Invalida
{
"error": "Invalid status transition from FLOWERING to VEGETATING. Valid transitions: HARVESTING",
"currentStatus": "FLOWERING",
"validTransitions": ["HARVESTING"]
}
BFF: Agregar Actividad
Esta ruta permite agregar una entrada al timeline del cultivo.
Request
- Name
type- Type
- PlantInteraction
- Description
Tipo de interaccion.
- Name
notes- Type
- string
- Description
Notas o comentarios.
- Name
data- Type
- object
- Description
Datos especificos segun el tipo.
- Name
evidences- Type
- array
- Description
URLs de fotos/videos.
- Name
author- Type
- object
- Description
Usuario que registra la actividad.
- Name
date- Type
- timestamp
- Description
Fecha de la actividad (default: ahora).
Datos por Tipo
WATERING:
{ "amount": 2000, "unit": "ml", "pH": 6.2, "EC": 1.4 }
FERTILIZATION:
[
{ "name": "Bio Grow", "nutrients": ["NITROGEN"], "amount": 4, "unit": "ml" }
]
Request
curl -X POST https://api.cannahub.tech/api/crops/crop-001/timeline \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"type": "WATERING",
"data": {
"amount": 2000,
"unit": "ml",
"pH": 6.2,
"EC": 1.4
},
"notes": "Riego matutino con nutrientes"
}'
Response (201)
{
"entry": {
"type": "WATERING",
"date": "2024-10-31T10:00:00Z",
"data": {
"amount": 2000,
"unit": "ml",
"pH": 6.2,
"EC": 1.4
},
"notes": "Riego matutino con nutrientes"
},
"crop": {
"id": "crop-001",
"timeline": [...]
}
}
Listar plantas del cultivo
Retorna las plantas individuales asociadas a un cultivo.
Request
curl https://api.cannahub.tech/api/crops/crop-001/plants \
-H "Authorization: Bearer {token}"
Response
{
"plants": [
{
"id": "plant-001",
"code": "BD-001",
"status": "ACTIVE",
"cropId": "crop-001"
}
],
"count": 3
}
Crear plantas en lote
Crea multiples plantas para un cultivo en una sola operacion.
Request
- Name
count- Type
- number
- Description
Cantidad de plantas a crear (debe ser positivo).
- Name
prefix- Type
- string
- Description
Prefijo para los codigos de planta.
- Name
status- Type
- string
- Description
Estado inicial de las plantas.
- Name
startCode- Type
- number
- Description
Numero inicial para la secuencia de codigos.
No se pueden crear plantas en cultivos con estado congelado (frozen).
Request
curl -X POST https://api.cannahub.tech/api/crops/crop-001/plants \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"count": 5,
"prefix": "BD",
"status": "ACTIVE"
}'
Response (201)
{
"plants": [...],
"count": 5
}
Cosechas del cultivo
Retorna las cosechas asociadas a un cultivo.
Request
curl https://api.cannahub.tech/api/crops/crop-001/harvest \
-H "Authorization: Bearer {token}"
Response
{
"harvests": [
{
"id": "harvest-001",
"name": "Blue Dream Lote #1",
"status": "DRYING",
"wetWeight": 500,
"dryWeight": null,
"quality": "A",
"batchNumber": "BLUEDREAM-2024-001"
}
],
"count": 1,
"crop": {
"id": "crop-001",
"name": "Blue Dream Indoor Batch A",
"status": "HARVESTING"
}
}
Crear cosecha
Crea una cosecha a partir de un cultivo. El cultivo debe estar en estado FLOWERING o HARVESTING.
Request
- Name
wetWeight- Type
- number
- Description
Peso humedo en gramos (debe ser positivo).
- Name
quality- Type
- string
- Description
Calidad de la cosecha (A, B, C).
- Name
notes- Type
- string
- Description
Notas sobre la cosecha.
- Name
name- Type
- string
- Description
Nombre personalizado para la cosecha.
- Name
storageLocation- Type
- string
- Description
Ubicacion de almacenamiento.
- Name
continueFlowering- Type
- boolean
- Description
Si es
true, el cultivo permanece en FLOWERING en lugar de pasar a DRYING.
Request
curl -X POST https://api.cannahub.tech/api/crops/crop-001/harvest \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"wetWeight": 500,
"quality": "A",
"notes": "Tricomas 30% ambar",
"continueFlowering": false
}'
Response (201)
{
"harvest": {
"id": "harvest-002",
"name": "Blue Dream Lote #2",
"status": "DRYING",
"wetWeight": 500,
"moisture": 75,
"batchNumber": "BLUEDREAM-2024-002"
},
"crop": {
"id": "crop-001",
"status": "DRYING"
},
"message": "Cosecha creada exitosamente"
}
Obtener estado del cultivo
Retorna el estado actual del cultivo, transiciones validas, y el historial de estados.
Request
curl https://api.cannahub.tech/api/crops/crop-001/status \
-H "Authorization: Bearer {token}"
Response
{
"currentStatus": "FLOWERING",
"validTransitions": ["HARVESTING"],
"allStatuses": ["IDEATING", "PROPAGATING", "VEGETATING", "FLOWERING", "HARVESTING", "DRYING", "MANICURING", "CURING", "FINISHED"],
"statusHistory": [...],
"isFrozen": false
}
React Query Hooks
Cannahub provee hooks de React Query para gestionar cultivos.
Query Keys
export const cropKeys = {
all: ['crops'] as const,
lists: () => [...cropKeys.all, 'list'] as const,
list: (filters?: CropFilters) => [...cropKeys.lists(), filters] as const,
details: () => [...cropKeys.all, 'detail'] as const,
detail: (id: string) => [...cropKeys.details(), id] as const,
complete: (id: string) => [...cropKeys.detail(id), 'complete'] as const,
timeline: (id: string) => [...cropKeys.detail(id), 'timeline'] as const,
}
Queries
import { useCropsQuery, useCropQuery, useCropCompleteQuery } from '@/features/Club/Crops/hooks'
// Listar cultivos con filtros
const { data } = useCropsQuery({ status: 'FLOWERING' })
// Obtener cultivo individual
const { data: crop } = useCropQuery('crop-001')
// Obtener cultivo completo con BFF
const { data: complete } = useCropCompleteQuery('crop-001')
Mutations
import {
useCreateCropMutation,
useUpdateCropMutation,
useDeleteCropMutation,
useChangeCropStatusMutation,
useAddTimelineEntryMutation
} from '@/features/Club/Crops/hooks'
// Crear cultivo
const { mutate: createCrop } = useCreateCropMutation()
createCrop({ name: 'Nuevo Cultivo', strain: 'strain_001', status: 'IDEATING' })
// Cambiar estado
const { mutate: changeStatus } = useChangeCropStatusMutation()
changeStatus({ cropId: 'crop-001', newStatus: 'FLOWERING' })
// Agregar actividad
const { mutate: addEntry } = useAddTimelineEntryMutation()
addEntry({ cropId: 'crop-001', type: 'WATERING', data: { amount: 2000 } })