Skip to content

Repository files navigation

PPSMS — Sistema de Submissão e Avaliação de Artigos Científicos

Aplicação de console (Java) que simula o fluxo completo de submissão e revisão por pares (blind-review) de artigos em um evento acadêmico: um coordenador abre o evento e monta o comitê, autores submetem artigos, o sistema distribui automaticamente os trabalhos entre os revisores conforme a área temática, e ao final os autores são notificados por e-mail com os pareceres.

Projeto da disciplina Padrões de Projeto de Software — o foco é aplicar os princípios SOLID e diversos padrões de projeto (GoF) em um cenário real.


Identificação

Campo Informação
Curso Sistemas para Internet
Disciplina Padrões de Projeto de Software
Período
Professor Alex Sandro da Cunha Rêgo

Equipe 1

  • Davi
  • Arthur
  • Heitor

Sumário


Stack e requisitos

  • Java 21 (o projeto usa records, switch de expressão e sealed-like states).
  • Maven (há o wrapper mvnw/mvnw.cmd — não é preciso ter Maven instalado).
  • Lombok (geração de getters/setters/construtores) — já configurado no pom.xml.
  • Jakarta Mail (org.eclipse.angus:jakarta.mail) — envio real de e-mail.
  • dotenv-java — leitura das credenciais de e-mail a partir de um arquivo .env.

Como executar

O projeto empacota um JAR executável (via maven-shade-plugin) com classe principal com.dah.App.

1. Criar o arquivo .env (obrigatório)

Na inicialização o programa carrega um .env; se ele não existir, a aplicação não sobe. Basta copiar o exemplo:

# Linux / macOS
cp .env.example .env

# Windows (PowerShell)
Copy-Item .env.example .env

O .env.example já vem com os campos vazios:

FROM_EMAIL = ""
EMAIL_APP_PASSWORD = ""
  • Com os campos vazios (recomendado para testar/corrigir): o sistema usa um adapter falso de e-mail (FakeEmailSenderAdapter) que imprime os e-mails no console em vez de enviá-los. Nenhuma configuração externa é necessária.
  • Para enviar e-mail de verdade (Gmail): preencha FROM_EMAIL com o remetente e EMAIL_APP_PASSWORD com uma senha de app do Google. Aí o SmtpEmailSenderAdapter passa a enviar de fato (SMTP smtp.gmail.com:587, STARTTLS).

2. Compilar e rodar

O projeto usa o Maven Wrapper, então você não precisa instalar o Maven — use o executável que já vem no repositório. O comando muda conforme o sistema operacional:

Sistema Wrapper Observação
Linux / macOS ./mvnw Script shell. Se der "permissão negada", rode antes chmod +x mvnw.
Windows mvnw.cmd Funciona no CMD e no PowerShell (no PowerShell use .\mvnw.cmd).

Linux / macOS (terminal bash/zsh):

./mvnw -q package
java -jar target/ppsms-1.0-SNAPSHOT.jar

Windows (PowerShell):

.\mvnw.cmd -q package
java -jar target\ppsms-1.0-SNAPSHOT.jar

Windows (Prompt de Comando — CMD):

mvnw.cmd -q package
java -jar target\ppsms-1.0-SNAPSHOT.jar

O -q deixa a saída do Maven silenciosa (quiet). Na primeira execução o wrapper baixa o Maven e as dependências, então precisa de internet e pode demorar um pouco; depois fica em cache.

Rodar sem empacotar (opcional)

Se quiser apenas compilar e executar direto pela App (sem gerar o JAR), use o mesmo wrapper do seu sistema:

# Linux / macOS
./mvnw -q compile exec:java -Dexec.mainClass=com.dah.App
# Windows (PowerShell)
.\mvnw.cmd -q compile exec:java "-Dexec.mainClass=com.dah.App"

Alternativa (IDE): o repositório também é um projeto Eclipse (.project / .classpath). Basta importar e executar a classe com.dah.App como Java Application. Certifique-se de ter o JDK 21 e o Lombok habilitado na IDE.


Dados de demonstração (seed) e credenciais

Ao iniciar, a classe DataSeeder popula automaticamente o cenário (atende ao Requisito de Execução E1 — sem digitação inicial para testar): cria o coordenador, alguns pesquisadores, um evento aberto (SBSI 2026, categoria Full Paper, 2 revisores por artigo) e algumas áreas temáticas.

Contas já cadastradas para login:

Papel E-mail Senha Observação
Coordenador coordenador@ppsms.local 123456 Abre evento, cadastra áreas, convida revisores, distribui, dashboard
Pesquisador arthur.silva.5@academico.ifpb.edu.br 123 Autor
Pesquisador / Revisora alice@ppsms.local 123456 Convidada como revisora com áreas (Eng. de Software, IA)
Pesquisador / Revisor bob@ppsms.local 123456 Convidado como revisor; define as áreas no 1º login

Áreas temáticas semeadas: Engenharia de Software, Inteligência Artificial e Visão Computacional.

Roteiro rápido de teste: entre como coordenadorDistribuir Artigos só tem efeito depois que houver artigos submetidos, então antes entre como autor, Submeter Artigo; volte como coordenador para Distribuir; entre como revisor (Alice/Bob) para Avaliar Artigo; e volte ao coordenador para ver o Dashboard.


Arquitetura em camadas

O sistema é dividido em três camadas, com dependências sempre apontando "para dentro" (apresentação → lógica → dados), respeitando baixo acoplamento:

Camada Responsabilidade Pacotes principais
Apresentação Menus de console, leitura de entrada e exibição. Não contém regra de negócio. presentation, presentation.input, presentation.view, command
Lógica (negócio) Regras de negócio, orquestração, padrões de projeto. facade, service, workflow, observer, domain, email
Dados Persistência em memória por trás de interfaces de repositório. repository

Os dados não são persistidos em banco: cada repositório concreto guarda os objetos em listas na memória (InMemory*Repository). A regra de que existe apenas o evento atual simplifica o modelo — ao iniciar um novo evento, os dados do evento anterior (áreas, revisores, artigos, avaliações) são descartados, enquanto os usuários permanecem.


Estrutura de pastas e classes

src/main/java/com/dah/
├── App.java                         # main() — ponto de entrada
├── ApplicationBootstrap.java        # "montagem" (injeção de dependências manual) + loop inicial
│
├── presentation/                    # CAMADA DE APRESENTAÇÃO
│   ├── MainMenu.java                # roteia para o menu conforme o papel do usuário
│   ├── CoordinatorMenu.java         # menu do coordenador
│   ├── ResearcherMenu.java          # menu do pesquisador/revisor
│   ├── LoginFlowController.java     # o que acontece após o login
│   ├── ReviewerAreaSetupScreen.java # 1º login do revisor: escolher áreas de expertise
│   ├── input/InputReader.java       # leitura e validação de dados do teclado
│   └── view/ConsoleView.java        # toda a saída formatada (menus, listagens, painéis)
│
├── command/                         # PADRÃO COMMAND (ações do usuário)
│   ├── Command.java / NoDataCommand.java
│   ├── StartEventCommand, RegisterAreaCommand, InviteReviewerCommand,
│   ├── DistributeArticlesCommand, ShowDashboardCommand, ShowCurrentEventCommand,
│   └── SubmitArticleCommand, ReviewArticleCommand, DefineReviewerAreasCommand
│
├── facade/                          # PADRÕES FACADE + PROXY
│   ├── CoordinatorActions / CoordinatorFacade
│   ├── ResearcherActions  / ResearcherFacade
│   └── CoordinatorAuthorizationProxy   # verifica autorização antes de delegar
│
├── service/                         # SERVIÇOS DE NEGÓCIO
│   ├── AccountService               # cadastro/login/usuário atual
│   ├── CommitteeService             # áreas, convite de revisores, expertise
│   ├── EventService                 # início/reset do evento, dashboard, seleção da factory
│   ├── ArticleReviewService         # submissão de artigos e submissão de pareceres
│   ├── DistributionService          # distribui artigos usando a estratégia atual
│   └── DataSeeder                   # popula o cenário de demonstração
│
├── domain/                          # ENTIDADES DE DOMÍNIO
│   ├── User, Area, Article, Review, ReviewerProfile, SubmissionEvent
│   └── article/                     # PADRÃO STATE (estado do artigo)
│       ├── ArticleState (interface)
│       └── SubmittedState, UnderReview, AcceptedState, RejectedState, AttentionState
│
├── workflow/                        # PADRÕES STRATEGY + ABSTRACT FACTORY
│   ├── ReviewWorkflowContext        # guarda a estratégia/política ativas do evento
│   ├── factory/                     # ABSTRACT FACTORY (família distribuição + política)
│   │   ├── ReviewWorkflowFactory (interface)
│   │   └── One/Two/ThreeReviewerWorkflowFactory
│   ├── distribution/                # STRATEGY de distribuição
│   │   ├── DistributionStrategy (interface) + BalancedDistributionStrategy (base comum)
│   │   └── strategies/ One/Two/ThreeReviewerDistributionStrategy
│   └── review/                      # STRATEGY de conclusão (política de veredito)
│       ├── ReviewPolicy (interface)
│       └── strategies/ One/Two/ThreeReviewerPolicy
│
├── observer/                        # PADRÃO OBSERVER (notificações)
│   ├── EventPublisher               # publica eventos de domínio para os inscritos
│   ├── events/ DomainEvent, ArticleAssignedEvent, ArticleConcludedEvent, ReviewAttentionEvent
│   └── subscribers/ Subscriber, ReviewerAssignementEmailSubscriber,
│                    AuthorResultEmailSubscriber, ReviewAttentionEmailSubscriber
│
├── email/                           # PADRÃO ADAPTER (e-mail)
│   ├── EmailSender (interface)
│   ├── FakeEmailSenderAdapter       # imprime no console (sem .env)
│   └── SmtpEmailSenderAdapter       # envia de verdade via Jakarta Mail
│
├── records/                         # DTOs (Java records) de transporte de dados
│   ├── RegisterUserData, StartEventData, SubmitArticleData, ReviewData,
│   ├── DefineReviewerAreasData, ArticleForReviewDTO, CoordinatorDashboard,
│   └── PendingDetails, EmailMessage
│
├── repository/                      # CAMADA DE DADOS (Repository/DAO em memória)
│   ├── *Repository (interfaces) + InMemory*Repository (implementações)
│   └── ResettableRepository         # permite "zerar" os dados por evento
│
├── enums/                           # Category, Role, Verdict, ReviewStatus, ReviewOutcome
└── exceptions/                      # UnauthorizedOperationException, EmailSendingException

Padrões de projeto utilizados e onde

# Padrão Onde (classes / pacote) Para quê
1 Facade facade/CoordinatorFacade, facade/ResearcherFacade (interfaces CoordinatorActions, ResearcherActions) Uma fachada por ator, escondendo a complexidade dos vários serviços por trás de uma interface simples que a camada de apresentação consome.
2 Proxy facade/CoordinatorAuthorizationProxy Mesma interface da fachada do coordenador; antes de delegar cada operação, verifica se o usuário atual é coordenador (isCurrentUserCoordinator) e lança UnauthorizedOperationException caso contrário.
3 Command Pacote command/ (ex.: SubmitArticleCommand, InviteReviewerCommand, DefineReviewerAreasCommand) Encapsula cada ação do usuário como um objeto. Permite, por exemplo, adiar a definição de áreas do revisor (DefineReviewerAreasCommand) e desacopla o menu da lógica.
4 State domain/article/ArticleState + SubmittedState, UnderReview, AcceptedState, RejectedState, AttentionState O Article delega as transições (startReview, accept, reject, markAttention) ao seu estado atual — cada estado sabe o que é permitido, eliminando ifs espalhados.
5 Strategy workflow/distribution/DistributionStrategy (+ estratégias por nº de revisores) e workflow/review/ReviewPolicy (+ políticas por nº de revisores) Algoritmo de distribuição de artigos e política de conclusão (quando o artigo é aceito/rejeitado/atenção) variam de forma intercambiável conforme a configuração do evento.
6 Abstract Factory workflow/factory/ReviewWorkflowFactory + One/Two/ThreeReviewerWorkflowFactory, orquestrada por workflow/ReviewWorkflowContext Cria a família consistente {estratégia de distribuição + política de revisão} correspondente ao nº de revisores por artigo. É o padrão adicional do RF10 (ver abaixo).
7 Observer observer/EventPublisher, eventos em observer/events/, inscritos em observer/subscribers/ Publica eventos de domínio (artigo atribuído, concluído, em atenção) e notifica os inscritos (envio de e-mail) sem acoplar quem dispara ao que reage. Inscrições feitas no ApplicationBootstrap.
8 Adapter email/EmailSender + FakeEmailSenderAdapter / SmtpEmailSenderAdapter Desacopla o domínio da biblioteca concreta de e-mail (Jakarta Mail). Troca-se o fake pelo SMTP real conforme o .env, sem mudar o código que envia.
Repository / DAO (arquitetural) repository/*Repository + InMemory*Repository Abstrai a persistência (aqui, em memória) atrás de interfaces, permitindo trocar a implementação sem afetar os serviços.
DTO (Java record) Pacote records/ Transporte imutável de dados entre camadas (ex.: SubmitArticleData, ArticleForReviewDTO, CoordinatorDashboard).

Como cada requisito foi resolvido (RF01–RF10)

RF01 – Start (iniciar evento)

EventService.startEvent cria o SubmissionEvent (único/atual), descarta os dados do evento anterior chamando deleteAll() em todos os ResettableRepository (áreas, revisores, artigos, avaliações) e configura o ReviewWorkflowContext com a factory correta. Acionado pelo menu do coordenador → opção 1; dados coletados em StartEventData (nome, cidade, período, categoria e nº de revisores por artigo).

RF02 – Cadastro de usuários

AccountService.registerResearcher cadastra o pesquisador (e-mail como chave, nome, senha, instituição — RegisterUserData), rejeitando e-mail duplicado. Disponível no menu inicial → opção 1.

RF03 – Cadastro de áreas temáticas

CommitteeService.registerArea (coordenador → opção 2) cadastra as áreas e impede duplicatas. Do lado do revisor, no 1º login a ReviewerAreaSetupScreen + DefineReviewerAreasCommand chamam CommitteeService.defineExpertiseAreas para registrar as áreas de expertise, usadas depois na distribuição.

RF04 – Comitê técnico de avaliação

CommitteeService.inviteResearcher (coordenador → opção 3) transforma um pesquisador já cadastrado em revisor (cria um ReviewerProfile). A categoria do evento (Full/Short/Demo, enum Category) é definida no start pelo coordenador (chair). Para facilitar escolher o ID, a tela lista os usuários cadastrados antes de pedir o ID.

RF05 – Submissão de artigos

ArticleReviewService.submitArticle (pesquisador → opção 1) registra título, resumo, coautores e áreas (SubmitArticleData) — só aceita dentro do prazo (event.isSubmissionOpen()), senão informa mensagem adequada. Cada artigo recebe um ID e nasce no estado SubmittedState (State). O autor pode consultar seus artigos via listMyArticles. A tela lista usuários e áreas para o autor obter os IDs de coautores e temas.

RF06 – Distribuição automática

DistributionService.distributeArticles (coordenador → opção 4) usa a Strategy de distribuição ativa (ReviewWorkflowContext.getDistributionStrategy) para dividir os artigos entre revisores por afinidade de área, de forma balanceada, sem atribuir a um autor o próprio artigo. Cada atribuição gera um ArticleAssignedEvent (Observer) que dispara o e-mail ao revisor com o artigo e o prazo. O blind-review é garantido porque o ArticleForReviewDTO entregue ao revisor não expõe os autores.

RF07 – Conclusão de avaliação

ArticleReviewService.submitReview (pesquisador/revisor → opção 2) registra o parecer (contribuições, críticas e veredito — enum Verdict). A política de revisão (ReviewPolicy, Strategy) decide o desfecho (aceito / rejeitado / atenção) a partir do conjunto de pareceres, e o Article transita de estado (State). A tela lista os artigos atribuídos ao revisor, mostrando o ID da avaliação que ele deve informar.

RF08 – Dashboard

EventService.getDashboard (coordenador → opção 5) monta o CoordinatorDashboard: nº de artigos submetidos, revisores, artigos avaliados e pendentes, além da relação de pendências (PendingDetails: artigo, revisor responsável e prazo).

RF09 – Notificação aos autores

Implementada por Observer + Adapter. Quando um artigo é concluído, o ArticleConcludedEvent é publicado e o AuthorResultEmailSubscriber envia o resultado com os pareceres; casos de empate geram ReviewAttentionEventReviewAttentionEmailSubscriber. O envio é real via SmtpEmailSenderAdapter (Jakarta Mail) quando o .env está configurado; sem credenciais, o FakeEmailSenderAdapter imprime o e-mail no console.

RF10 – Padrão adicional (nº de revisores por artigo)

Requisito próprio da equipe: o coordenador escolhe 1, 2 ou 3 revisores por artigo ao iniciar o evento. Essa escolha usa o Abstract Factory (ReviewWorkflowFactoryOne/Two/ThreeReviewerWorkflowFactory, selecionada em EventService.selectFactory) para criar de forma consistente a dupla {estratégia de distribuição + política de conclusão} adequada àquela quantidade, mantida no ReviewWorkflowContext. Assim, distribuição e regra de veredito nunca ficam incompatíveis entre si.


Requisitos não funcionais atendidos

  • SOLID / baixo acoplamento: dependências por interface (fachadas, repositórios, estratégias, EmailSender); injeção manual centralizada no ApplicationBootstrap.
  • Encapsulamento e reuso: regras no domínio/serviços; estratégias compartilham base comum (BalancedDistributionStrategy).
  • Tratamento de exceções: UnauthorizedOperationException, EmailSendingException e validações de estado/prazo.
  • Saída centralizada: a apresentação concentra a exibição na ConsoleView, evitando System.out.println espalhado pela lógica de negócio.
  • Execução fácil (E1/E2): cenário pré-populado pelo DataSeeder e JAR executável com um único comando.

Diagramas

Os diagramas de apoio estão na pasta diagrams/:

Arquivo Conteúdo
DomainDiagram.(png/svg) Modelo de domínio (entidades e relações).
LayersDiagram.(png/svg) Visão em camadas (apresentação / lógica / dados).
PatternsDiagram.(png/svg) Onde cada padrão de projeto se encaixa.
states.(png/svg) Máquina de estados do Article (padrão State).
*.puml Fontes PlantUML dos diagramas acima.

Padrões de Projeto de Software — Prof. Alex Sandro C. Rêgo — Equipe 1 (Davi, Arthur, Heitor).

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages