Skip to content

Base de Datos — Mush2 ​

Motor ​

PostgreSQL 16, ORM Sequelize 6.

Entidades y Relaciones ​

Device ──1:N── Sensor
  ├──1:N── Actuator
  ├──1:N── Telemetry
  ├──1:1── ApiKey
  └──1:N── Event

User ──1:N── AuditLog
  ├──1:N── Subscription        ← modelo basado en capacidades (ADR-016)
  ├──1:1── UserPreference
  └──N:M── Chamber (via UserChamberAccess)

Recipe ──1:N── CultivationCycle
                  └──1:N── CycleState

Chamber ──1:N── Device

Modelos ​

Device ​

CampoTipoDescripción
idUUID PK—
deviceIdVARCHAR(50) UNIQUEID del dispositivo (ej: mush2_A0F262E55CBC)
macAddressVARCHAR(17)MAC del ESP32-S3
userIdUUID FK(user)Propietario (nullable = legacy)
chamberNameVARCHAR(100)Nombre de la cámara
chamberLocationVARCHAR(200)Ubicación
firmwareVersionVARCHAR(20)Versión actual
statusENUM(ONLINE,OFFLINE,ERROR)Estado
lastSeenTIMESTAMPÚltima conexión
thingSpeakChannelIdVARCHAR(64)Channel ID ThingSpeak
thingSpeakReadKeyTEXTRead key cifrada (AES-256-GCM)

Sensor ​

CampoTipoDescripción
idUUID PK—
deviceIdUUID FK(device)Dispositivo padre
typeENUM(TEMPERATURE,HUMIDITY,CO2,VOC)Tipo de sensor

Actuator ​

CampoTipoDescripción
idUUID PK—
deviceIdUUID FK(device)Dispositivo padre
channelINTEGERCanal SSR (1-4)
stateENUM(ON,OFF)Estado actual
modeENUM(LOCAL,REMOTE,OFF)Modo de control
lastCommandVARCHAR(50)Último cmdId
lastSeenTIMESTAMPÚltima actualización
lastAckVARCHAR(20)Último estado ACK

Telemetry ​

CampoTipoDescripción
idUUID PK—
deviceIdUUID FK(device)Dispositivo
sensorIdUUID FK(sensor)Sensor
valueDECIMAL(8,2)Valor leído
sensorTypeENUM(TEMPERATURE,HUMIDITY,CO2,VOC)Tipo
unitVARCHAR(10)°C, %, ppm, ppb
timestampTIMESTAMPMomento de la lectura

Event ​

CampoTipoDescripción
idUUID PK—
deviceIdUUID FK(device)Dispositivo
typeVARCHAR(50)boot, alarm, ack
payloadJSONBDatos del evento
timestampTIMESTAMP—

ApiKey ​

CampoTipoDescripción
idUUID PK—
deviceIdUUID FK(device)Dispositivo asociado
keyVARCHAR(64)API key única
prefixVARCHAR(10)Prefijo visible (ej: mush2_)
isActiveBOOLEANKey activa/revocada
createdAtTIMESTAMP—

Recipe ​

CampoTipoDescripción
idUUID PK—
userIdUUID FK(user)Creador (nullable = públicas)
nameVARCHAR(100)Nombre
speciesVARCHAR(100)Especie de hongo
incubationTempMin/MaxDECIMAL(5,2)Rango incubación
incubationHumMin/MaxDECIMAL(5,2)Rango humedad incubación
incubationCo2MaxINTEGERCO₂ max incubación
incubationDurationINTEGERDuración en días
fruitingTempMin/MaxDECIMAL(5,2)Rango fructificación
fruitingHumMin/MaxDECIMAL(5,2)Rango humedad fructificación
fruitingCo2MaxINTEGERCO₂ max fructificación
fruitingDurationINTEGERDuración en días
maintenanceTempMin/MaxDECIMAL(5,2)Rango mantenimiento
maintenanceHumMin/MaxDECIMAL(5,2)Rango humedad mantenimiento
maintenanceCo2MaxINTEGERCO₂ max mantenimiento
faeIntervalINTEGERIntervalo ventilación (min)
faeLevelENUM(LOW,MEDIUM,HIGH)Nivel de intercambio de aire
lightCycleHoursINTEGERHoras de luz por día

CultivationCycle ​

CampoTipoDescripción
idUUID PK—
userIdUUID FK(user)Creador
recipeIdUUID FK(recipe)Receta aplicada
deviceIdUUID FK(device)Dispositivo asociado
statusENUM(PLANNED,ACTIVE,COMPLETED,ABORTED)Estado
currentPhaseENUM(INCUBATION,PRIMORDIA,FRUITING,HARVESTING)Fase
startDateDATEInicio
estimatedEndDateDATEFin estimado

CycleState ​

CampoTipoDescripción
idUUID PK—
cycleIdUUID FK(cultivation_cycle)Ciclo padre
phaseENUMFase al momento del snapshot
temperatureDECIMAL(5,2)Temp promedio
humidityDECIMAL(5,2)HR promedio
co2INTEGERCO₂ promedio
statusVARCHAR(20)Estado del snapshot
snapshotDateDATEFecha del snapshot

User ​

CampoTipoDescripción
idUUID PK—
usernameVARCHAR(50) UNIQUENombre de usuario
emailVARCHAR(255) UNIQUEEmail
passwordVARCHAR(255)bcrypt hash
roleENUM(SUPER_ADMIN,ADMIN,OPERATOR,VIEWER)Rol
isActiveBOOLEANCuenta activa
lastLoginAtTIMESTAMPÚltimo login

AuditLog ​

CampoTipoDescripción
idUUID PK—
userIdUUID FK(user)Usuario
actionVARCHAR(50)Acción realizada
resourceVARCHAR(50)Tipo de recurso
resourceIdUUIDID del recurso
detailsJSONBDetalles adicionales
createdAtTIMESTAMP—

Subscription ​

CampoTipoDescripción
idINTEGER PKautoincrement
userIdUUID FK(user)Titular de la suscripción
planENUM(FREE,BASIC,PREMIUM)Plan actual (default: FREE)
statusENUM(ACTIVE,CANCELED,PAST_DUE)Estado (default: ACTIVE)
apiCallsPerMonthINTEGERLímite de requests según plan (1k/10k/100k)
apiCallsUsedThisMonthINTEGERContador de uso en el período actual
dataRetentionDaysINTEGERDías de retención según plan (30/90/365)
currentPeriodStartDATEInicio del período facturado (default: now())
currentPeriodEndDATEFin del período facturado (default: now() + 1 mes)
canceledAtDATENullable; fecha de solicitud de cancelación

Reglas de negocio:

  • apiCallsPerMonth y dataRetentionDays se copian del plan al crear/upgrade (no se resuelven dinámicamente del plan para evitar cambios retroactivos)
  • apiCallsUsedThisMonth se resetea al renovar el período
  • status se marca CANCELED cuando el usuario solicita baja; canceledAt registra la fecha
  • Un job diario (subscriptionExpiration.js) maneja la expiración al final del período
  • No hay período de gracia: al expirar se degrada a FREE (o se purga según disposición de capacidades)

UserChamberAccess ​

CampoTipoDescripción
idUUID PK—
userIdUUID FK(user)Usuario con acceso
deviceIdUUID FK(device)Dispositivo compartido
roleVARCHAR(20)Rol de acceso

Sincronización ​

En desarrollo: sequelize.sync({ alter: true }) al iniciar. En producción: migraciones versionadas (ADR-013 Fase 3).

Notas sobre el Modelo de Suscripción ​

La tabla Subscription reemplaza el diseño legacy (con columnas startDate/endDate/autoRenew/stripe*) por un modelo basado en capacidades. La migración (DROP TABLE subscriptions CASCADE; sync({ alter: true })) eliminó la tabla legacy y la recreó con el schema actual. Ver docs/ADR/ADR-016-capability-based-subscription.md para la decisión arquitectónica completa.

Mush2 — Sistema IoT de control ambiental