mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-18 14:27:51 +00:00
feat: Criando tabelas para nova funcionalidade de correção de redação
This commit is contained in:
parent
478ca2441d
commit
206f7bcb30
171
supabase/migrations/20240326000001_create_essay_system.sql
Normal file
171
supabase/migrations/20240326000001_create_essay_system.sql
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
-- Criação do sistema de redações (Essays)
|
||||||
|
-- Tipos de texto (Narrativo, Dissertativo, etc)
|
||||||
|
CREATE TABLE public.essay_types (
|
||||||
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
||||||
|
slug TEXT NOT NULL UNIQUE,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
description TEXT NOT NULL,
|
||||||
|
icon TEXT NOT NULL,
|
||||||
|
active BOOLEAN DEFAULT true,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Gêneros textuais (Artigo de opinião, Carta argumentativa, etc)
|
||||||
|
CREATE TABLE public.essay_genres (
|
||||||
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
||||||
|
type_id UUID NOT NULL REFERENCES public.essay_types(id),
|
||||||
|
slug TEXT NOT NULL UNIQUE,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
description TEXT NOT NULL,
|
||||||
|
icon TEXT NOT NULL,
|
||||||
|
requirements JSONB NOT NULL DEFAULT '{}',
|
||||||
|
active BOOLEAN DEFAULT true,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Redações dos alunos
|
||||||
|
CREATE TABLE public.student_essays (
|
||||||
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
||||||
|
student_id UUID NOT NULL REFERENCES public.students(id),
|
||||||
|
type_id UUID NOT NULL REFERENCES public.essay_types(id),
|
||||||
|
genre_id UUID NOT NULL REFERENCES public.essay_genres(id),
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
status TEXT NOT NULL DEFAULT 'draft',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||||
|
CONSTRAINT status_check CHECK (status IN ('draft', 'submitted', 'analyzed'))
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Análises das redações
|
||||||
|
CREATE TABLE public.essay_analyses (
|
||||||
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
||||||
|
essay_id UUID NOT NULL REFERENCES public.student_essays(id),
|
||||||
|
overall_score INTEGER NOT NULL CHECK (overall_score >= 0 AND overall_score <= 100),
|
||||||
|
feedback JSONB NOT NULL DEFAULT '{}',
|
||||||
|
strengths TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||||
|
improvements TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||||
|
suggestions TEXT,
|
||||||
|
criteria_scores JSONB NOT NULL DEFAULT '{}',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Índices para melhor performance
|
||||||
|
CREATE INDEX idx_student_essays_student_id ON public.student_essays(student_id);
|
||||||
|
CREATE INDEX idx_student_essays_status ON public.student_essays(status);
|
||||||
|
CREATE INDEX idx_essay_genres_type_id ON public.essay_genres(type_id);
|
||||||
|
CREATE INDEX idx_essay_analyses_essay_id ON public.essay_analyses(essay_id);
|
||||||
|
|
||||||
|
-- Triggers para updated_at
|
||||||
|
CREATE OR REPLACE FUNCTION public.handle_updated_at()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
NEW.updated_at = now();
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ language 'plpgsql';
|
||||||
|
|
||||||
|
CREATE TRIGGER essay_types_updated_at
|
||||||
|
BEFORE UPDATE ON public.essay_types
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE PROCEDURE public.handle_updated_at();
|
||||||
|
|
||||||
|
CREATE TRIGGER essay_genres_updated_at
|
||||||
|
BEFORE UPDATE ON public.essay_genres
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE PROCEDURE public.handle_updated_at();
|
||||||
|
|
||||||
|
CREATE TRIGGER student_essays_updated_at
|
||||||
|
BEFORE UPDATE ON public.student_essays
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE PROCEDURE public.handle_updated_at();
|
||||||
|
|
||||||
|
-- Políticas RLS
|
||||||
|
ALTER TABLE public.essay_types ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.essay_genres ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.student_essays ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.essay_analyses ENABLE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
|
-- Políticas para essay_types (visível para todos)
|
||||||
|
CREATE POLICY "Tipos de redação visíveis para todos"
|
||||||
|
ON public.essay_types FOR SELECT
|
||||||
|
USING (active = true);
|
||||||
|
|
||||||
|
-- Políticas para essay_genres (visível para todos)
|
||||||
|
CREATE POLICY "Gêneros textuais visíveis para todos"
|
||||||
|
ON public.essay_genres FOR SELECT
|
||||||
|
USING (active = true);
|
||||||
|
|
||||||
|
-- Políticas para student_essays
|
||||||
|
CREATE POLICY "Alunos podem ver suas próprias redações"
|
||||||
|
ON public.student_essays FOR SELECT
|
||||||
|
USING (student_id = auth.uid());
|
||||||
|
|
||||||
|
CREATE POLICY "Alunos podem criar suas próprias redações"
|
||||||
|
ON public.student_essays FOR INSERT
|
||||||
|
WITH CHECK (student_id = auth.uid());
|
||||||
|
|
||||||
|
CREATE POLICY "Alunos podem atualizar suas próprias redações"
|
||||||
|
ON public.student_essays FOR UPDATE
|
||||||
|
USING (student_id = auth.uid())
|
||||||
|
WITH CHECK (student_id = auth.uid());
|
||||||
|
|
||||||
|
-- Políticas para essay_analyses
|
||||||
|
CREATE POLICY "Alunos podem ver análises de suas próprias redações"
|
||||||
|
ON public.essay_analyses FOR SELECT
|
||||||
|
USING (
|
||||||
|
essay_id IN (
|
||||||
|
SELECT id FROM public.student_essays
|
||||||
|
WHERE student_id = auth.uid()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Função para verificar se uma redação pertence ao aluno
|
||||||
|
CREATE OR REPLACE FUNCTION public.check_essay_ownership(essay_id UUID)
|
||||||
|
RETURNS BOOLEAN AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM public.student_essays
|
||||||
|
WHERE id = essay_id
|
||||||
|
AND student_id = auth.uid()
|
||||||
|
);
|
||||||
|
END;
|
||||||
|
$$ language plpgsql security definer;
|
||||||
|
|
||||||
|
-- Comentários nas tabelas
|
||||||
|
COMMENT ON TABLE public.essay_types IS 'Tipos de texto (Narrativo, Dissertativo, etc)';
|
||||||
|
COMMENT ON TABLE public.essay_genres IS 'Gêneros textuais relacionados a cada tipo de texto';
|
||||||
|
COMMENT ON TABLE public.student_essays IS 'Redações escritas pelos alunos';
|
||||||
|
COMMENT ON TABLE public.essay_analyses IS 'Análises e feedbacks das redações dos alunos';
|
||||||
|
|
||||||
|
-- Dados iniciais
|
||||||
|
INSERT INTO public.essay_types (slug, title, description, icon) VALUES
|
||||||
|
('narrative', 'Narrativo', 'Textos que contam uma história com personagens, tempo e espaço definidos', '📖'),
|
||||||
|
('dissertation', 'Dissertativo', 'Textos que apresentam uma análise e discussão de um tema', '📝'),
|
||||||
|
('descriptive', 'Descritivo', 'Textos que descrevem detalhadamente um objeto, pessoa, lugar ou situação', '🎨');
|
||||||
|
|
||||||
|
INSERT INTO public.essay_genres (type_id, slug, title, description, icon, requirements) VALUES
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'dissertation'),
|
||||||
|
'opinion-article',
|
||||||
|
'Artigo de Opinião',
|
||||||
|
'Texto que apresenta um ponto de vista sobre um tema atual',
|
||||||
|
'📰',
|
||||||
|
'{"min_words": 300, "max_words": 600, "required_sections": ["introduction", "development", "conclusion"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'narrative'),
|
||||||
|
'short-story',
|
||||||
|
'Conto',
|
||||||
|
'História curta com poucos personagens e um único conflito',
|
||||||
|
'📚',
|
||||||
|
'{"min_words": 200, "max_words": 1000, "required_elements": ["characters", "setting", "conflict", "resolution"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'descriptive'),
|
||||||
|
'character-description',
|
||||||
|
'Descrição de Personagem',
|
||||||
|
'Texto que descreve características físicas e psicológicas de um personagem',
|
||||||
|
'👤',
|
||||||
|
'{"min_words": 150, "max_words": 400, "required_aspects": ["physical", "psychological", "habits"]}'
|
||||||
|
);
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
-- Remover políticas
|
||||||
|
DROP POLICY IF EXISTS "Alunos podem ver análises de suas próprias redações" ON public.essay_analyses;
|
||||||
|
DROP POLICY IF EXISTS "Alunos podem atualizar suas próprias redações" ON public.student_essays;
|
||||||
|
DROP POLICY IF EXISTS "Alunos podem criar suas próprias redações" ON public.student_essays;
|
||||||
|
DROP POLICY IF EXISTS "Alunos podem ver suas próprias redações" ON public.student_essays;
|
||||||
|
DROP POLICY IF EXISTS "Gêneros textuais visíveis para todos" ON public.essay_genres;
|
||||||
|
DROP POLICY IF EXISTS "Tipos de redação visíveis para todos" ON public.essay_types;
|
||||||
|
|
||||||
|
-- Remover função de verificação de propriedade
|
||||||
|
DROP FUNCTION IF EXISTS public.check_essay_ownership(UUID);
|
||||||
|
|
||||||
|
-- Remover triggers
|
||||||
|
DROP TRIGGER IF EXISTS student_essays_updated_at ON public.student_essays;
|
||||||
|
DROP TRIGGER IF EXISTS essay_genres_updated_at ON public.essay_genres;
|
||||||
|
DROP TRIGGER IF EXISTS essay_types_updated_at ON public.essay_types;
|
||||||
|
|
||||||
|
-- Remover função do trigger
|
||||||
|
DROP FUNCTION IF EXISTS public.handle_updated_at();
|
||||||
|
|
||||||
|
-- Remover índices
|
||||||
|
DROP INDEX IF EXISTS public.idx_essay_analyses_essay_id;
|
||||||
|
DROP INDEX IF EXISTS public.idx_essay_genres_type_id;
|
||||||
|
DROP INDEX IF EXISTS public.idx_student_essays_status;
|
||||||
|
DROP INDEX IF EXISTS public.idx_student_essays_student_id;
|
||||||
|
|
||||||
|
-- Remover tabelas
|
||||||
|
DROP TABLE IF EXISTS public.essay_analyses;
|
||||||
|
DROP TABLE IF EXISTS public.student_essays;
|
||||||
|
DROP TABLE IF EXISTS public.essay_genres;
|
||||||
|
DROP TABLE IF EXISTS public.essay_types;
|
||||||
141
supabase/migrations/20240326000002_insert_essay_data.sql
Normal file
141
supabase/migrations/20240326000002_insert_essay_data.sql
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
-- Inserir tipos textuais
|
||||||
|
INSERT INTO public.essay_types (slug, title, description, icon) VALUES
|
||||||
|
('narrative', 'Narrativo', 'Textos que narram acontecimentos reais ou fictícios, com personagens, tempo e espaço definidos', '📖'),
|
||||||
|
('descriptive', 'Descrição', 'Textos que descrevem detalhadamente características de algo ou alguém', '🎨'),
|
||||||
|
('expository', 'Expositivo', 'Textos que explicam e informam sobre um determinado assunto', '📚'),
|
||||||
|
('argumentative', 'Argumentativo', 'Textos que defendem uma ideia ou ponto de vista com argumentos', '⚖️'),
|
||||||
|
('injunctive', 'Injuntivo', 'Textos que orientam ou instruem sobre como realizar algo', '📝');
|
||||||
|
|
||||||
|
-- Inserir gêneros textuais para tipo Narrativo
|
||||||
|
INSERT INTO public.essay_genres (type_id, slug, title, description, icon, requirements) VALUES
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'narrative'),
|
||||||
|
'short-story',
|
||||||
|
'Conto',
|
||||||
|
'História curta com poucos personagens e um único conflito',
|
||||||
|
'📚',
|
||||||
|
'{"min_words": 200, "max_words": 1000, "required_elements": ["personagens", "tempo", "espaço", "conflito", "resolução"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'narrative'),
|
||||||
|
'chronicle',
|
||||||
|
'Crônica',
|
||||||
|
'Narrativa curta que retrata situações do cotidiano',
|
||||||
|
'📰',
|
||||||
|
'{"min_words": 150, "max_words": 800, "required_elements": ["situação_cotidiana", "reflexão", "linguagem_informal"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'narrative'),
|
||||||
|
'novel',
|
||||||
|
'Romance',
|
||||||
|
'História longa com desenvolvimento aprofundado de personagens e tramas',
|
||||||
|
'📖',
|
||||||
|
'{"min_words": 1000, "max_words": 3000, "required_elements": ["personagens_principais", "personagens_secundários", "múltiplos_conflitos", "desenvolvimento_completo"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'narrative'),
|
||||||
|
'news',
|
||||||
|
'Notícia',
|
||||||
|
'Relato de fatos reais de forma objetiva',
|
||||||
|
'📰',
|
||||||
|
'{"min_words": 150, "max_words": 500, "required_elements": ["lead", "corpo_da_notícia", "objetividade"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'narrative'),
|
||||||
|
'biography',
|
||||||
|
'Biografia/Autobiografia',
|
||||||
|
'Relato da vida de uma pessoa',
|
||||||
|
'👤',
|
||||||
|
'{"min_words": 300, "max_words": 1000, "required_elements": ["dados_pessoais", "acontecimentos_importantes", "ordem_cronológica"]}'
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Inserir gêneros textuais para tipo Descritivo
|
||||||
|
INSERT INTO public.essay_genres (type_id, slug, title, description, icon, requirements) VALUES
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'descriptive'),
|
||||||
|
'menu',
|
||||||
|
'Cardápio',
|
||||||
|
'Descrição detalhada de pratos e bebidas',
|
||||||
|
'🍽️',
|
||||||
|
'{"min_words": 50, "max_words": 200, "required_elements": ["nome_do_prato", "ingredientes", "preço"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'descriptive'),
|
||||||
|
'descriptive-report',
|
||||||
|
'Relato descritivo',
|
||||||
|
'Descrição detalhada de um objeto, pessoa ou ambiente',
|
||||||
|
'🔍',
|
||||||
|
'{"min_words": 200, "max_words": 600, "required_elements": ["características_físicas", "sensações", "detalhes_específicos"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'descriptive'),
|
||||||
|
'reportage',
|
||||||
|
'Reportagem',
|
||||||
|
'Descrição aprofundada de um fato ou tema',
|
||||||
|
'📰',
|
||||||
|
'{"min_words": 400, "max_words": 1000, "required_elements": ["contextualização", "detalhamento", "fontes"]}'
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Inserir gêneros textuais para tipo Expositivo
|
||||||
|
INSERT INTO public.essay_genres (type_id, slug, title, description, icon, requirements) VALUES
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'expository'),
|
||||||
|
'didactic-text',
|
||||||
|
'Texto didático',
|
||||||
|
'Explicação clara de um conteúdo para fins educacionais',
|
||||||
|
'📚',
|
||||||
|
'{"min_words": 200, "max_words": 800, "required_elements": ["definição", "exemplos", "explicação"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'expository'),
|
||||||
|
'lecture',
|
||||||
|
'Palestra',
|
||||||
|
'Apresentação expositiva sobre um tema específico',
|
||||||
|
'🎤',
|
||||||
|
'{"min_words": 500, "max_words": 1500, "required_elements": ["introdução", "desenvolvimento", "conclusão", "exemplos_práticos"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'expository'),
|
||||||
|
'reportage-exp',
|
||||||
|
'Reportagem',
|
||||||
|
'Texto informativo sobre um tema ou acontecimento',
|
||||||
|
'📰',
|
||||||
|
'{"min_words": 400, "max_words": 1000, "required_elements": ["contextualização", "dados", "fontes"]}'
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Inserir gêneros textuais para tipo Argumentativo
|
||||||
|
INSERT INTO public.essay_genres (type_id, slug, title, description, icon, requirements) VALUES
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'argumentative'),
|
||||||
|
'open-letter',
|
||||||
|
'Carta aberta',
|
||||||
|
'Texto que expõe publicamente argumentos sobre uma questão',
|
||||||
|
'✉️',
|
||||||
|
'{"min_words": 300, "max_words": 800, "required_elements": ["destinatário", "argumentos", "pedido_ou_reivindicação"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'argumentative'),
|
||||||
|
'thesis',
|
||||||
|
'Tese',
|
||||||
|
'Texto que defende uma ideia central com argumentos',
|
||||||
|
'📑',
|
||||||
|
'{"min_words": 500, "max_words": 1500, "required_elements": ["hipótese", "argumentos", "comprovação"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'argumentative'),
|
||||||
|
'scientific-article',
|
||||||
|
'Artigo científico',
|
||||||
|
'Texto que apresenta resultados de uma pesquisa',
|
||||||
|
'🔬',
|
||||||
|
'{"min_words": 1000, "max_words": 3000, "required_elements": ["introdução", "metodologia", "resultados", "conclusão"]}'
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Inserir gêneros textuais para tipo Injuntivo
|
||||||
|
INSERT INTO public.essay_genres (type_id, slug, title, description, icon, requirements) VALUES
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'injunctive'),
|
||||||
|
'instruction-manual',
|
||||||
|
'Manual de instrução',
|
||||||
|
'Texto que orienta sobre o uso de um produto',
|
||||||
|
'📖',
|
||||||
|
'{"min_words": 100, "max_words": 500, "required_elements": ["passo_a_passo", "advertências", "ilustrações"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'injunctive'),
|
||||||
|
'advertisement',
|
||||||
|
'Propaganda',
|
||||||
|
'Texto que persuade o leitor a uma ação',
|
||||||
|
'📢',
|
||||||
|
'{"min_words": 50, "max_words": 200, "required_elements": ["slogan", "argumentos_persuasivos", "chamada_para_ação"]}'
|
||||||
|
),
|
||||||
|
((SELECT id FROM public.essay_types WHERE slug = 'injunctive'),
|
||||||
|
'recipe',
|
||||||
|
'Receita',
|
||||||
|
'Texto que instrui o preparo de um prato',
|
||||||
|
'👩🍳',
|
||||||
|
'{"min_words": 100, "max_words": 400, "required_elements": ["ingredientes", "modo_de_preparo", "tempo_de_preparo", "rendimento"]}'
|
||||||
|
);
|
||||||
Loading…
Reference in New Issue
Block a user