Inicializar rioCata - Sistema de Catación de Café
- Base de datos PostgreSQL 16 con extensiones JSONB y arrays - Docker Compose para containerización - Scripts SQL de inicialización (schema, funciones, índices, datos de prueba) - Suite de tests de validación (18 tests) - Queries de ejemplo (17 queries) - Script helper para gestión (scripts/riocata.sh) - Documentación completa en README.md Estructura: - 4 tablas principales: sesion, auth.users, sesion_participante, muestra, evaluacion - Tipo ENUM para defectos - 2 triggers automáticos (updated_at, puntaje_final) - 19 índices de optimización (GIN, B-tree, funcionales) - Constraints de validación para arrays y JSONB - 2 funciones auxiliares para análisis
This commit is contained in:
123
postgres/init/01_schema.sql
Normal file
123
postgres/init/01_schema.sql
Normal file
@@ -0,0 +1,123 @@
|
||||
-- ============================================
|
||||
-- rioCata - Sistema de Catación de Café
|
||||
-- Schema de Base de Datos
|
||||
-- ============================================
|
||||
|
||||
-- Habilitar extensiones necesarias
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- ============================================
|
||||
-- TIPOS ENUMERADOS
|
||||
-- ============================================
|
||||
|
||||
-- Tipo de defecto en la catación
|
||||
CREATE TYPE defecto_tipo AS ENUM ('Mohoso', 'Fenólico', 'Papa');
|
||||
|
||||
-- ============================================
|
||||
-- TABLAS
|
||||
-- ============================================
|
||||
|
||||
-- Sesiones de catación
|
||||
CREATE TABLE sesion (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
codigo text UNIQUE, -- opcional: código visible (ej. "S-2025-10-17-01")
|
||||
fecha date NOT NULL,
|
||||
nombre text, -- ej. "Mesa #3 Lotes Lavados"
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE sesion IS 'Sesiones de catación de café';
|
||||
COMMENT ON COLUMN sesion.codigo IS 'Código único identificador de la sesión';
|
||||
COMMENT ON COLUMN sesion.fecha IS 'Fecha en que se realiza la catación';
|
||||
COMMENT ON COLUMN sesion.nombre IS 'Nombre descriptivo de la sesión';
|
||||
|
||||
-- Crear schema auth si no existe (antes de crear la tabla)
|
||||
CREATE SCHEMA IF NOT EXISTS auth;
|
||||
|
||||
-- Tabla de usuarios (simula auth.users de Supabase para desarrollo local)
|
||||
-- En producción se usaría directamente auth.users de Supabase
|
||||
CREATE TABLE auth.users (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
email text UNIQUE NOT NULL,
|
||||
nombre text,
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE auth.users IS 'Tabla de usuarios (simula auth.users de Supabase para desarrollo)';
|
||||
|
||||
-- Participantes (catadores) por sesión
|
||||
CREATE TABLE sesion_participante (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
sesion_id uuid NOT NULL REFERENCES sesion(id) ON DELETE CASCADE,
|
||||
catador_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE RESTRICT,
|
||||
rol text DEFAULT 'catador', -- opcional: juez, invitado, etc.
|
||||
UNIQUE (sesion_id, catador_id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE sesion_participante IS 'Relación de participantes (catadores) en sesiones de catación';
|
||||
COMMENT ON COLUMN sesion_participante.rol IS 'Rol del participante: catador, juez, invitado, etc.';
|
||||
|
||||
-- Muestras pertenecen a una sesión
|
||||
CREATE TABLE muestra (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
sesion_id uuid NOT NULL REFERENCES sesion(id) ON DELETE CASCADE,
|
||||
codigo text NOT NULL, -- "Muestra 1", "A-101", etc.
|
||||
posicion int, -- ej. orden físico en mesa
|
||||
UNIQUE (sesion_id, codigo)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE muestra IS 'Muestras de café a ser evaluadas en una sesión';
|
||||
COMMENT ON COLUMN muestra.codigo IS 'Código identificador de la muestra dentro de la sesión';
|
||||
COMMENT ON COLUMN muestra.posicion IS 'Orden físico de la muestra en la mesa de catación';
|
||||
|
||||
-- Evaluación de una muestra hecha por un participante específico de esa sesión
|
||||
CREATE TABLE evaluacion (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
muestra_id uuid NOT NULL REFERENCES muestra(id) ON DELETE CASCADE,
|
||||
sesion_participante_id uuid NOT NULL REFERENCES sesion_participante(id) ON DELETE CASCADE,
|
||||
|
||||
-- JSONB según lo acordado
|
||||
intensidades jsonb NOT NULL, -- { fragancia: {descriptiva, afectiva}, ... }
|
||||
fragancia_aroma_notas jsonb DEFAULT '[]', -- array de objetos [{categoria, subcategoria, notaEspecifica}]
|
||||
sabor_notas jsonb DEFAULT '[]', -- array de objetos
|
||||
|
||||
-- Arrays según lo acordado
|
||||
tazas_no_uniformes smallint[] DEFAULT '{}', -- valores 1..5
|
||||
tazas_defectuosas smallint[] DEFAULT '{}', -- valores 1..5
|
||||
sensacion_en_boca text[] DEFAULT '{}', -- Áspero, Suave, Aceitoso, Metálico, Astringente
|
||||
gustos_predominantes text[] DEFAULT '{}', -- 1..2 elementos entre Salado, Amargo, Ácido, Dulce, Umami
|
||||
|
||||
defecto defecto_tipo, -- opcional
|
||||
otras_notas text,
|
||||
puntaje_final int, -- guardado por trigger
|
||||
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
|
||||
-- Una evaluación por participante por muestra
|
||||
UNIQUE (muestra_id, sesion_participante_id),
|
||||
|
||||
-- Constraints de validez
|
||||
CHECK (tazas_no_uniformes <@ ARRAY[1,2,3,4,5]::smallint[]),
|
||||
CHECK (tazas_defectuosas <@ ARRAY[1,2,3,4,5]::smallint[]),
|
||||
|
||||
CHECK (sensacion_en_boca <@ ARRAY['Áspero','Suave','Aceitoso','Metálico','Astringente']::text[]),
|
||||
CHECK (gustos_predominantes <@ ARRAY['Salado','Amargo','Ácido','Dulce','Umami']::text[]),
|
||||
CHECK (COALESCE(array_length(gustos_predominantes,1),0) BETWEEN 0 AND 2),
|
||||
|
||||
-- Validación de rangos en intensidades (descriptiva 1..15, afectiva 1..10)
|
||||
CHECK (NOT jsonb_path_exists(intensidades, '$.*.descriptiva ? (@ < 1 || @ > 15)')),
|
||||
CHECK (NOT jsonb_path_exists(intensidades, '$.*.afectiva ? (@ < 1 || @ > 10)'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE evaluacion IS 'Evaluaciones de muestras realizadas por catadores';
|
||||
COMMENT ON COLUMN evaluacion.intensidades IS 'Intensidades descriptivas y afectivas de los 8 parámetros evaluados';
|
||||
COMMENT ON COLUMN evaluacion.fragancia_aroma_notas IS 'Array de familias de fragancia/aroma (categoría, subcategoría, nota específica)';
|
||||
COMMENT ON COLUMN evaluacion.sabor_notas IS 'Array de familias de sabor (categoría, subcategoría, nota específica)';
|
||||
COMMENT ON COLUMN evaluacion.tazas_no_uniformes IS 'Números de taza (1-5) que no fueron uniformes';
|
||||
COMMENT ON COLUMN evaluacion.tazas_defectuosas IS 'Números de taza (1-5) con defectos graves';
|
||||
COMMENT ON COLUMN evaluacion.sensacion_en_boca IS 'Sensaciones táctiles: Áspero, Suave, Aceitoso, Metálico, Astringente';
|
||||
COMMENT ON COLUMN evaluacion.gustos_predominantes IS 'Gustos básicos predominantes (1-2): Salado, Amargo, Ácido, Dulce, Umami';
|
||||
COMMENT ON COLUMN evaluacion.defecto IS 'Tipo de defecto identificado si aplica';
|
||||
COMMENT ON COLUMN evaluacion.otras_notas IS 'Notas adicionales del catador en texto libre';
|
||||
COMMENT ON COLUMN evaluacion.puntaje_final IS 'Suma de los valores afectivos (calculado automáticamente por trigger)';
|
||||
105
postgres/init/02_functions.sql
Normal file
105
postgres/init/02_functions.sql
Normal file
@@ -0,0 +1,105 @@
|
||||
-- ============================================
|
||||
-- rioCata - Funciones y Triggers
|
||||
-- ============================================
|
||||
|
||||
-- ============================================
|
||||
-- FUNCIÓN: Actualizar updated_at
|
||||
-- ============================================
|
||||
CREATE OR REPLACE FUNCTION set_updated_at()
|
||||
RETURNS trigger LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
NEW.updated_at := now();
|
||||
RETURN NEW;
|
||||
END $$;
|
||||
|
||||
COMMENT ON FUNCTION set_updated_at() IS 'Actualiza automáticamente el campo updated_at al timestamp actual';
|
||||
|
||||
-- Trigger para actualizar updated_at en evaluacion
|
||||
CREATE TRIGGER trg_eval_updated_at
|
||||
BEFORE UPDATE ON evaluacion
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
-- ============================================
|
||||
-- FUNCIÓN: Calcular puntaje final
|
||||
-- ============================================
|
||||
-- Calcula el puntaje_final sumando SOLO los valores afectivos presentes
|
||||
CREATE OR REPLACE FUNCTION eval_compute_score()
|
||||
RETURNS trigger LANGUAGE plpgsql AS $$
|
||||
DECLARE
|
||||
s int := 0;
|
||||
BEGIN
|
||||
-- Suma todos los valores afectivos presentes en intensidades
|
||||
-- Si alguno es null, COALESCE lo convierte en 0
|
||||
s := s + COALESCE((NEW.intensidades->'fragancia' ->>'afectiva')::int, 0);
|
||||
s := s + COALESCE((NEW.intensidades->'aroma' ->>'afectiva')::int, 0);
|
||||
s := s + COALESCE((NEW.intensidades->'sabor' ->>'afectiva')::int, 0);
|
||||
s := s + COALESCE((NEW.intensidades->'saborResidual' ->>'afectiva')::int, 0);
|
||||
s := s + COALESCE((NEW.intensidades->'acidez' ->>'afectiva')::int, 0);
|
||||
s := s + COALESCE((NEW.intensidades->'dulzor' ->>'afectiva')::int, 0);
|
||||
s := s + COALESCE((NEW.intensidades->'sensacionBoca' ->>'afectiva')::int, 0);
|
||||
s := s + COALESCE((NEW.intensidades->'impresionGlobal'->>'afectiva')::int, 0);
|
||||
|
||||
NEW.puntaje_final := s;
|
||||
RETURN NEW;
|
||||
END $$;
|
||||
|
||||
COMMENT ON FUNCTION eval_compute_score() IS 'Calcula automáticamente el puntaje_final como suma de valores afectivos';
|
||||
|
||||
-- Trigger para calcular puntaje_final en INSERT y UPDATE
|
||||
CREATE TRIGGER trg_eval_score_bi
|
||||
BEFORE INSERT OR UPDATE OF intensidades
|
||||
ON evaluacion
|
||||
FOR EACH ROW EXECUTE FUNCTION eval_compute_score();
|
||||
|
||||
-- ============================================
|
||||
-- FUNCIONES AUXILIARES DE CONSULTA
|
||||
-- ============================================
|
||||
|
||||
-- Función para obtener el promedio de un parámetro afectivo en una sesión
|
||||
CREATE OR REPLACE FUNCTION get_promedio_parametro_afectivo(
|
||||
p_sesion_id uuid,
|
||||
p_parametro text -- 'fragancia', 'aroma', 'sabor', etc.
|
||||
)
|
||||
RETURNS numeric AS $$
|
||||
BEGIN
|
||||
RETURN (
|
||||
SELECT AVG(((e.intensidades -> p_parametro ->>'afectiva')::int))
|
||||
FROM sesion s
|
||||
JOIN muestra m ON m.sesion_id = s.id
|
||||
JOIN evaluacion e ON e.muestra_id = m.id
|
||||
WHERE s.id = p_sesion_id
|
||||
);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
COMMENT ON FUNCTION get_promedio_parametro_afectivo(uuid, text) IS 'Obtiene el promedio de un parámetro afectivo para una sesión';
|
||||
|
||||
-- Función para obtener las top N muestras de una sesión por puntaje
|
||||
CREATE OR REPLACE FUNCTION get_top_muestras(
|
||||
p_sesion_id uuid,
|
||||
p_limit int DEFAULT 3
|
||||
)
|
||||
RETURNS TABLE (
|
||||
muestra_codigo text,
|
||||
puntaje_final int,
|
||||
catador_email text,
|
||||
catador_nombre text
|
||||
) AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
m.codigo,
|
||||
e.puntaje_final,
|
||||
u.email,
|
||||
u.nombre
|
||||
FROM muestra m
|
||||
JOIN evaluacion e ON e.muestra_id = m.id
|
||||
JOIN sesion_participante sp ON sp.id = e.sesion_participante_id
|
||||
JOIN auth.users u ON u.id = sp.catador_id
|
||||
WHERE m.sesion_id = p_sesion_id
|
||||
ORDER BY e.puntaje_final DESC
|
||||
LIMIT p_limit;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
COMMENT ON FUNCTION get_top_muestras(uuid, int) IS 'Obtiene las muestras con mejor puntaje de una sesión';
|
||||
77
postgres/init/03_indexes.sql
Normal file
77
postgres/init/03_indexes.sql
Normal file
@@ -0,0 +1,77 @@
|
||||
-- ============================================
|
||||
-- rioCata - Índices para Optimización
|
||||
-- ============================================
|
||||
|
||||
-- ============================================
|
||||
-- ÍNDICES EN CLAVES FORÁNEAS
|
||||
-- ============================================
|
||||
|
||||
CREATE INDEX idx_sesion_participante_sesion_id ON sesion_participante(sesion_id);
|
||||
CREATE INDEX idx_sesion_participante_catador_id ON sesion_participante(catador_id);
|
||||
|
||||
CREATE INDEX idx_muestra_sesion ON muestra(sesion_id);
|
||||
|
||||
CREATE INDEX idx_eval_muestra ON evaluacion(muestra_id);
|
||||
CREATE INDEX idx_eval_participante ON evaluacion(sesion_participante_id);
|
||||
|
||||
-- ============================================
|
||||
-- ÍNDICES EN CAMPOS ESPECÍFICOS
|
||||
-- ============================================
|
||||
|
||||
-- Índice para búsquedas por tipo de defecto
|
||||
CREATE INDEX idx_eval_defecto ON evaluacion(defecto);
|
||||
|
||||
-- Índice para búsquedas por puntaje final
|
||||
CREATE INDEX idx_eval_puntaje_final ON evaluacion(puntaje_final DESC);
|
||||
|
||||
-- ============================================
|
||||
-- ÍNDICES GIN PARA JSONB Y ARRAYS
|
||||
-- ============================================
|
||||
|
||||
-- Índices GIN para consultas de contención en JSONB
|
||||
CREATE INDEX idx_eval_json_intensidades ON evaluacion USING GIN (intensidades jsonb_path_ops);
|
||||
CREATE INDEX idx_eval_aroma_notas ON evaluacion USING GIN (fragancia_aroma_notas);
|
||||
CREATE INDEX idx_eval_sabor_notas ON evaluacion USING GIN (sabor_notas);
|
||||
|
||||
-- Índices GIN para arrays (permite consultas con @>, &&, etc.)
|
||||
CREATE INDEX idx_eval_tazas_defectuosas ON evaluacion USING GIN (tazas_defectuosas);
|
||||
CREATE INDEX idx_eval_tazas_no_uniformes ON evaluacion USING GIN (tazas_no_uniformes);
|
||||
CREATE INDEX idx_eval_sensacion_boca ON evaluacion USING GIN (sensacion_en_boca);
|
||||
CREATE INDEX idx_eval_gustos_predominantes ON evaluacion USING GIN (gustos_predominantes);
|
||||
|
||||
-- ============================================
|
||||
-- ÍNDICES FUNCIONALES (OPCIONALES)
|
||||
-- ============================================
|
||||
|
||||
-- Índices funcionales para consultas frecuentes sobre valores específicos en intensidades
|
||||
-- Estos son opcionales pero mejoran el rendimiento de queries que filtran por valores afectivos específicos
|
||||
|
||||
-- Ejemplo: filtrar por acidez afectiva >= 8
|
||||
CREATE INDEX idx_eval_int_acidez_afectiva
|
||||
ON evaluacion ( ((intensidades->'acidez'->>'afectiva')::int) );
|
||||
|
||||
-- Ejemplo: filtrar por dulzor afectivo >= 8
|
||||
CREATE INDEX idx_eval_int_dulzor_afectivo
|
||||
ON evaluacion ( ((intensidades->'dulzor'->>'afectiva')::int) );
|
||||
|
||||
-- Ejemplo: filtrar por sabor afectivo >= 8
|
||||
CREATE INDEX idx_eval_int_sabor_afectivo
|
||||
ON evaluacion ( ((intensidades->'sabor'->>'afectiva')::int) );
|
||||
|
||||
-- ============================================
|
||||
-- ÍNDICES DE TEXTO (PARA BÚSQUEDA)
|
||||
-- ============================================
|
||||
|
||||
-- Índice para búsqueda de texto en otras_notas
|
||||
CREATE INDEX idx_eval_otras_notas_gin ON evaluacion USING GIN (to_tsvector('spanish', COALESCE(otras_notas, '')));
|
||||
|
||||
-- Índice para búsqueda en nombres de sesión
|
||||
CREATE INDEX idx_sesion_nombre_gin ON sesion USING GIN (to_tsvector('spanish', COALESCE(nombre, '')));
|
||||
|
||||
-- ============================================
|
||||
-- COMENTARIOS
|
||||
-- ============================================
|
||||
|
||||
COMMENT ON INDEX idx_eval_json_intensidades IS 'Índice GIN para consultas de contención en intensidades (jsonb_path_ops)';
|
||||
COMMENT ON INDEX idx_eval_tazas_defectuosas IS 'Índice GIN para búsquedas de tazas defectuosas específicas';
|
||||
COMMENT ON INDEX idx_eval_int_acidez_afectiva IS 'Índice funcional para filtros por valor afectivo de acidez';
|
||||
244
postgres/init/04_sample_data.sql
Normal file
244
postgres/init/04_sample_data.sql
Normal file
@@ -0,0 +1,244 @@
|
||||
-- ============================================
|
||||
-- rioCata - Datos de Prueba
|
||||
-- ============================================
|
||||
|
||||
-- ============================================
|
||||
-- USUARIOS DE PRUEBA
|
||||
-- ============================================
|
||||
|
||||
INSERT INTO auth.users (id, email, nombre) VALUES
|
||||
('11111111-1111-1111-1111-111111111111', 'dario@nucleoriofrio.com', 'Dario'),
|
||||
('22222222-2222-2222-2222-222222222222', 'juan.catador@example.com', 'Juan Pérez'),
|
||||
('33333333-3333-3333-3333-333333333333', 'maria.juez@example.com', 'María González');
|
||||
|
||||
-- ============================================
|
||||
-- SESIÓN DE CATACIÓN DE PRUEBA
|
||||
-- ============================================
|
||||
|
||||
INSERT INTO sesion (id, codigo, fecha, nombre) VALUES
|
||||
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'S-2025-10-17-01', '2025-10-17', 'Mesa Laboratorio #1 - Lotes Lavados');
|
||||
|
||||
-- ============================================
|
||||
-- PARTICIPANTES DE LA SESIÓN
|
||||
-- ============================================
|
||||
|
||||
INSERT INTO sesion_participante (id, sesion_id, catador_id, rol) VALUES
|
||||
('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '11111111-1111-1111-1111-111111111111', 'catador'),
|
||||
('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '22222222-2222-2222-2222-222222222222', 'catador'),
|
||||
('dddddddd-dddd-dddd-dddd-dddddddddddd', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '33333333-3333-3333-3333-333333333333', 'juez');
|
||||
|
||||
-- ============================================
|
||||
-- MUESTRAS DE CAFÉ
|
||||
-- ============================================
|
||||
|
||||
INSERT INTO muestra (id, sesion_id, codigo, posicion) VALUES
|
||||
('eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Muestra A-101', 1),
|
||||
('ffffffff-ffff-ffff-ffff-ffffffffffff', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Muestra B-202', 2),
|
||||
('00000000-0000-0000-0000-000000000001', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Muestra C-303', 3);
|
||||
|
||||
-- ============================================
|
||||
-- EVALUACIONES DE PRUEBA
|
||||
-- ============================================
|
||||
|
||||
-- Evaluación 1: Dario evalúa Muestra A-101 (café excelente)
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id,
|
||||
sesion_participante_id,
|
||||
intensidades,
|
||||
fragancia_aroma_notas,
|
||||
sabor_notas,
|
||||
tazas_no_uniformes,
|
||||
tazas_defectuosas,
|
||||
sensacion_en_boca,
|
||||
gustos_predominantes,
|
||||
defecto,
|
||||
otras_notas
|
||||
) VALUES (
|
||||
'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee',
|
||||
'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb',
|
||||
'{
|
||||
"fragancia": {"descriptiva": 8, "afectiva": 9},
|
||||
"aroma": {"descriptiva": 9, "afectiva": 9},
|
||||
"sabor": {"descriptiva": 10, "afectiva": 10},
|
||||
"saborResidual": {"descriptiva": 8, "afectiva": 9},
|
||||
"acidez": {"descriptiva": 9, "afectiva": 9},
|
||||
"dulzor": {"descriptiva": 10, "afectiva": 10},
|
||||
"sensacionBoca": {"descriptiva": 8, "afectiva": 9},
|
||||
"impresionGlobal": {"descriptiva": null, "afectiva": 10}
|
||||
}'::jsonb,
|
||||
'[
|
||||
{"categoria": "Afrutado", "subcategoria": "Cítricos", "notaEspecifica": "Naranja dulce"},
|
||||
{"categoria": "Floral", "subcategoria": "Jazmín", "notaEspecifica": null}
|
||||
]'::jsonb,
|
||||
'[
|
||||
{"categoria": "Afrutado", "subcategoria": "Bayas", "notaEspecifica": "Fresa madura"},
|
||||
{"categoria": "Chocolatado", "subcategoria": "Chocolate con leche", "notaEspecifica": null}
|
||||
]'::jsonb,
|
||||
ARRAY[]::smallint[],
|
||||
ARRAY[]::smallint[],
|
||||
ARRAY['Suave', 'Aceitoso']::text[],
|
||||
ARRAY['Ácido', 'Dulce']::text[],
|
||||
null,
|
||||
'Café excepcional. Muy balanceado, con dulzor prominente y acidez brillante. Notas a vino tinto en el retrogusto. Cuerpo medio-alto, muy limpio.'
|
||||
);
|
||||
|
||||
-- Evaluación 2: Juan evalúa Muestra A-101 (también buena evaluación)
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id,
|
||||
sesion_participante_id,
|
||||
intensidades,
|
||||
fragancia_aroma_notas,
|
||||
sabor_notas,
|
||||
tazas_no_uniformes,
|
||||
tazas_defectuosas,
|
||||
sensacion_en_boca,
|
||||
gustos_predominantes,
|
||||
defecto,
|
||||
otras_notas
|
||||
) VALUES (
|
||||
'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee',
|
||||
'cccccccc-cccc-cccc-cccc-cccccccccccc',
|
||||
'{
|
||||
"fragancia": {"descriptiva": 7, "afectiva": 8},
|
||||
"aroma": {"descriptiva": 8, "afectiva": 9},
|
||||
"sabor": {"descriptiva": 9, "afectiva": 9},
|
||||
"saborResidual": {"descriptiva": 7, "afectiva": 8},
|
||||
"acidez": {"descriptiva": 8, "afectiva": 8},
|
||||
"dulzor": {"descriptiva": 9, "afectiva": 9},
|
||||
"sensacionBoca": {"descriptiva": 7, "afectiva": 8},
|
||||
"impresionGlobal": {"descriptiva": null, "afectiva": 9}
|
||||
}'::jsonb,
|
||||
'[
|
||||
{"categoria": "Afrutado", "subcategoria": "Cítricos", "notaEspecifica": "Mandarina"}
|
||||
]'::jsonb,
|
||||
'[
|
||||
{"categoria": "Afrutado", "subcategoria": "Bayas", "notaEspecifica": "Mora"},
|
||||
{"categoria": "Caramelizado", "subcategoria": "Caramelo", "notaEspecifica": null}
|
||||
]'::jsonb,
|
||||
ARRAY[]::smallint[],
|
||||
ARRAY[]::smallint[],
|
||||
ARRAY['Suave']::text[],
|
||||
ARRAY['Dulce', 'Ácido']::text[],
|
||||
null,
|
||||
'Muy buen café. Dulce y complejo. Buena acidez cítrica. Cuerpo medio.'
|
||||
);
|
||||
|
||||
-- Evaluación 3: Dario evalúa Muestra B-202 (café con problemas de uniformidad)
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id,
|
||||
sesion_participante_id,
|
||||
intensidades,
|
||||
fragancia_aroma_notas,
|
||||
sabor_notas,
|
||||
tazas_no_uniformes,
|
||||
tazas_defectuosas,
|
||||
sensacion_en_boca,
|
||||
gustos_predominantes,
|
||||
defecto,
|
||||
otras_notas
|
||||
) VALUES (
|
||||
'ffffffff-ffff-ffff-ffff-ffffffffffff',
|
||||
'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb',
|
||||
'{
|
||||
"fragancia": {"descriptiva": 5, "afectiva": 6},
|
||||
"aroma": {"descriptiva": 6, "afectiva": 7},
|
||||
"sabor": {"descriptiva": 6, "afectiva": 7},
|
||||
"saborResidual": {"descriptiva": 5, "afectiva": 6},
|
||||
"acidez": {"descriptiva": 7, "afectiva": 7},
|
||||
"dulzor": {"descriptiva": 6, "afectiva": 7},
|
||||
"sensacionBoca": {"descriptiva": 5, "afectiva": 6},
|
||||
"impresionGlobal": {"descriptiva": null, "afectiva": 6}
|
||||
}'::jsonb,
|
||||
'[
|
||||
{"categoria": "Especiado", "subcategoria": "Canela", "notaEspecifica": null}
|
||||
]'::jsonb,
|
||||
'[
|
||||
{"categoria": "Nueces", "subcategoria": "Almendra", "notaEspecifica": null}
|
||||
]'::jsonb,
|
||||
ARRAY[2, 5]::smallint[],
|
||||
ARRAY[]::smallint[],
|
||||
ARRAY['Áspero']::text[],
|
||||
ARRAY['Ácido']::text[],
|
||||
null,
|
||||
'Café promedio. Las tazas 2 y 5 no estaban uniformes con las demás. Algo de astringencia. Cuerpo ligero-medio.'
|
||||
);
|
||||
|
||||
-- Evaluación 4: María evalúa Muestra C-303 (café con defecto fenólico)
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id,
|
||||
sesion_participante_id,
|
||||
intensidades,
|
||||
fragancia_aroma_notas,
|
||||
sabor_notas,
|
||||
tazas_no_uniformes,
|
||||
tazas_defectuosas,
|
||||
sensacion_en_boca,
|
||||
gustos_predominantes,
|
||||
defecto,
|
||||
otras_notas
|
||||
) VALUES (
|
||||
'00000000-0000-0000-0000-000000000001',
|
||||
'dddddddd-dddd-dddd-dddd-dddddddddddd',
|
||||
'{
|
||||
"fragancia": {"descriptiva": 4, "afectiva": 4},
|
||||
"aroma": {"descriptiva": 3, "afectiva": 3},
|
||||
"sabor": {"descriptiva": 3, "afectiva": 3},
|
||||
"saborResidual": {"descriptiva": 2, "afectiva": 2},
|
||||
"acidez": {"descriptiva": 5, "afectiva": 5},
|
||||
"dulzor": {"descriptiva": 4, "afectiva": 4},
|
||||
"sensacionBoca": {"descriptiva": 3, "afectiva": 3},
|
||||
"impresionGlobal": {"descriptiva": null, "afectiva": 2}
|
||||
}'::jsonb,
|
||||
'[
|
||||
{"categoria": "Otros", "subcategoria": "Químico", "notaEspecifica": "Medicinal"}
|
||||
]'::jsonb,
|
||||
'[
|
||||
{"categoria": "Otros", "subcategoria": "Químico", "notaEspecifica": "Fenólico"}
|
||||
]'::jsonb,
|
||||
ARRAY[3, 4, 5]::smallint[],
|
||||
ARRAY[5]::smallint[],
|
||||
ARRAY['Áspero', 'Astringente']::text[],
|
||||
ARRAY['Amargo']::text[],
|
||||
'Fenólico',
|
||||
'Café con defecto fenólico grave en taza 5. Sabor medicinal/químico. No apto para comercialización.'
|
||||
);
|
||||
|
||||
-- Evaluación 5: Juan evalúa Muestra B-202
|
||||
INSERT INTO evaluacion (
|
||||
muestra_id,
|
||||
sesion_participante_id,
|
||||
intensidades,
|
||||
fragancia_aroma_notas,
|
||||
sabor_notas,
|
||||
tazas_no_uniformes,
|
||||
tazas_defectuosas,
|
||||
sensacion_en_boca,
|
||||
gustos_predominantes,
|
||||
defecto,
|
||||
otras_notas
|
||||
) VALUES (
|
||||
'ffffffff-ffff-ffff-ffff-ffffffffffff',
|
||||
'cccccccc-cccc-cccc-cccc-cccccccccccc',
|
||||
'{
|
||||
"fragancia": {"descriptiva": 6, "afectiva": 7},
|
||||
"aroma": {"descriptiva": 6, "afectiva": 7},
|
||||
"sabor": {"descriptiva": 7, "afectiva": 7},
|
||||
"saborResidual": {"descriptiva": 6, "afectiva": 7},
|
||||
"acidez": {"descriptiva": 6, "afectiva": 7},
|
||||
"dulzor": {"descriptiva": 7, "afectiva": 7},
|
||||
"sensacionBoca": {"descriptiva": 6, "afectiva": 7},
|
||||
"impresionGlobal": {"descriptiva": null, "afectiva": 7}
|
||||
}'::jsonb,
|
||||
'[
|
||||
{"categoria": "Nueces", "subcategoria": "Avellana", "notaEspecifica": null}
|
||||
]'::jsonb,
|
||||
'[
|
||||
{"categoria": "Caramelizado", "subcategoria": "Miel", "notaEspecifica": null}
|
||||
]'::jsonb,
|
||||
ARRAY[3]::smallint[],
|
||||
ARRAY[]::smallint[],
|
||||
ARRAY['Suave']::text[],
|
||||
ARRAY['Dulce']::text[],
|
||||
null,
|
||||
'Café correcto. Taza 3 ligeramente diferente. Notas a nueces tostadas. Cuerpo medio.'
|
||||
);
|
||||
Reference in New Issue
Block a user