feat: Criando tabelas para nova funcionalidade de correção de redação

This commit is contained in:
Lucas Santana 2025-02-06 20:06:25 -03:00
parent 478ca2441d
commit 206f7bcb30
3 changed files with 342 additions and 0 deletions

View 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"]}'
);

View File

@ -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;

View 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"]}'
);