3. Código-fonte do To-Do List

Para deixar a explicação mais clara e facilitar o entendimento da estrutura do projeto, organizamos a apresentação das classes seguindo a ordem em que naturalmente elas se conectam dentro da aplicação: primeiro vamos ver o modelo de domínio, que representa os dados que manipulamos; depois os DTOs, que são usados para trocar informações com quem consome a API; na sequência os repositórios, que salvam e recuperam os dados no banco; logo depois a camada de serviços, onde reunimos e coordenamos as regras de negócio; e, por fim, os controllers, que expõem tudo isso através dos endpoints da API. Essa sequência ajuda a construir o raciocínio de dentro para fora — do coração da aplicação até a porta de entrada! 🤩

3.1. Modelos de Domínio (model)

Vamos começar nossa análise pela camada de modelo, onde definimos as entidades que representam o núcleo de informação da nossa aplicação. Tudo no sistema — criação de tarefas, atualizações, conclusões, consultas — gira em torno desses modelos. Entender suas estruturas é essencial para compreendermos o comportamento do sistema como um todo.

Task.java

package br.ifsp.edu.todo.model;

@NoArgsConstructor
@Data
@Entity
public class Task {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotBlank
    @Size(min = 10, max = 100)
    private String title;

    @Size(max = 255)
    private String description;

    @NotNull
    @Enumerated(EnumType.STRING)
    private Priority priority;

    @NotNull
    private LocalDateTime dueDate;

    private boolean completed;

    @NotNull
    @Enumerated(EnumType.STRING)
    private Category category;

    private LocalDateTime createdAt;
}

A classe Task representa a entidade principal da nossa aplicação de gerenciamento de tarefas. Ela está anotada com @Entity, o que indica que será mapeada para uma tabela no banco de dados pela JPA (Jakarta Persistence API). Cada instância de Task corresponde a uma linha na tabela.

Entre seus atributos, temos:

  • id: a chave primária da tarefa, gerada automaticamente com estratégia de incremento (IDENTITY).
  • title: o título da tarefa, obrigatório (@NotBlank) e limitado entre 10 e 100 caracteres para garantir descrições concisas e claras.
  • description: um campo opcional para detalhes adicionais, limitado a 255 caracteres.
  • priority: a prioridade da tarefa, obrigatoriamente preenchida, armazenada como texto (EnumType.STRING) para facilitar a leitura no banco de dados.
  • dueDate: a data limite para conclusão da tarefa, também obrigatória.
  • completed: um booleano que indica se a tarefa foi concluída ou não.
  • category: a categoria à qual a tarefa pertence (ex: trabalho, estudo, pessoal), também obrigatoriamente preenchida e mapeada como texto no banco.
  • createdAt: o timestamp de criação da tarefa, preenchido no momento em que a tarefa é criada.

A classe utiliza ainda o Lombok para gerar automaticamente métodos como getters, setters e o construtor padrão (@NoArgsConstructor e @Data), reduzindo o código repetitivo (boilerplate) e deixando a implementação mais limpa e focada apenas nas informações essenciais da entidade.

Category.java

package br.ifsp.edu.todo.model;

public enum Category {
    STUDY, WORK, LEISURE, HEALTH, FAMILY, FRIENDS, PERSONAL, OTHER;
    
    public static Category fromString(String value) {
        return Arrays.stream(values()).filter(c -> c.name().equalsIgnoreCase(value)).findFirst()
                .orElseThrow(() -> new IllegalArgumentException("Invalid category: " + value));
    }
}

A classe Category define uma enumeração que representa as categorias possíveis para uma tarefa no nosso sistema. As opções incluem valores como STUDY, WORK, LEISURE, HEALTH, entre outros, possibilitando que o usuário classifique melhor suas tarefas de acordo com áreas da vida.

Além disso, a enumeração implementa o método utilitário fromString(String value), que permite converter uma string recebida — como em entradas de usuários ou dados de APIs — em um valor válido da enumeração. Esse método percorre todas as categorias existentes e realiza uma comparação case-insensitive para encontrar o valor correspondente. Caso a string informada não corresponda a nenhuma categoria conhecida, é lançada uma IllegalArgumentException, garantindo que apenas categorias válidas sejam aceitas. Essa abordagem reforça a robustez da nossa aplicação ao evitar erros silenciosos e inconsistências nos dados. Isso será bastante útil na nossa TaskService, como veremos mais adiante.

Priority.java

package br.ifsp.edu.todo.model;

public enum Priority {
    HIGH,
    MEDIUM,
    LOW
}

A classe Priority define uma enumeração simples que representa os níveis de prioridade que uma tarefa pode ter no sistema. As opções disponíveis são HIGH (alta), MEDIUM (média) e LOW (baixa). Essa enumeração é usada para classificar a importância relativa de cada tarefa, permitindo que o usuário ou a aplicação deem tratamento diferenciado de acordo com a prioridade definida. Por ser uma enumeração básica sem métodos adicionais, seu papel principal é fornecer um conjunto fixo e seguro de valores que podem ser atribuídos às tarefas, garantindo consistência e evitando a utilização de valores inválidos no sistema.

Concluindo esta seção, percebemos que as entidades Task, Priority e Category formam a espinha dorsal do nosso domínio, definindo tanto os dados persistidos quanto as restrições de valores possíveis. A clareza e a correção nesta camada são fundamentais, pois qualquer erro aqui propaga-se para todas as demais camadas. Agora que compreendemos como o núcleo da nossa aplicação — o modelo de domínio — está estruturado, é hora de avançarmos para uma camada igualmente fundamental: a dos DTOs. São eles que estabelecerão a comunicação segura entre o mundo externo e os nossos modelos internos.



This site uses Just the Docs, a documentation theme for Jekyll.