Skip to content

savedjobs: criação de endpoint GET e ajuste do README#192

Open
larisarapio wants to merge 50 commits intomainfrom
savedjobs-endpoint-larissa
Open

savedjobs: criação de endpoint GET e ajuste do README#192
larisarapio wants to merge 50 commits intomainfrom
savedjobs-endpoint-larissa

Conversation

@larisarapio
Copy link
Copy Markdown
Contributor

@larisarapio larisarapio commented Apr 8, 2025

Descrição

Atualização do README.md com informações relevantes para novos integrantes do projeto, incluindo instruções detalhadas para configuração do ambiente local e resolução de possíveis erros de integração.

Implementado o endpoint GET para listar todas as vagas salvas.

Ajuste na autenticação da criação de vagas salvas, que acabou não sendo tratado na tarefa anterior realizada pelo colega José. Como forma de otimizar a entrega, o ajuste foi realizado diretamente nesta branch.

⚠️ Observação: Durante o desenvolvimento, identificamos que não foi feito o fork do projeto inicialmente, o que pode ocasionar algum conflito ou problema nesta branch. Fiquem atentos ao revisar.

Summary by CodeRabbit

  • Novos Recursos

    • Adicionada a funcionalidade de "Vagas Salvas", permitindo que usuários salvem vagas e visualizem suas vagas salvas.
    • Implementados endpoints para salvar vagas e listar vagas salvas, com filtros e paginação.
    • As vagas salvas expiram automaticamente após 7 dias, com limpeza periódica automática.
    • Documentação Swagger ampliada para cobrir os novos endpoints de vagas salvas.
  • Documentação

    • README atualizado com instruções detalhadas de configuração, contribuição, resolução de problemas e organização da equipe.
  • Ajustes de Estilo e Refatoração

    • Melhorias de formatação e padronização em múltiplos arquivos para maior legibilidade e consistência.
  • Testes

    • Adicionados testes básicos para o serviço de vagas salvas.
  • Chores

    • Atualização de dependências e variáveis de ambiente no Docker Compose para maior flexibilidade de configuração.

joselazarojunior and others added 30 commits March 20, 2025 08:42
…s. parte que faltava de autentificação em post foi ajustada
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/modules/savedjobs/services/find-all-savedjobs.service.ts (1)

8-8: Considere usar "Jobs" no plural para variáveis e classes.

Um comentário anterior de revisão mencionou "Job > Jobs - pra variáveis". Recomendo manter consistência na nomenclatura utilizando o plural "Jobs" em todo o código.

🧰 Tools
🪛 ESLint

[error] 8-8: Delete

(prettier/prettier)

🧹 Nitpick comments (2)
src/modules/savedjobs/services/find-all-savedjobs.service.ts (2)

1-5: Padronize o uso de aspas simples para importações.

Os padrões de estilo do projeto parecem favorecer o uso de aspas simples para importações, mas aqui estão sendo usadas aspas duplas.

-import { Injectable } from "@nestjs/common";
-import { SavedJobsEntity } from "src/database/entities/savedjobs.entity";
-import { PageDto, PageOptionsDto } from "src/shared/pagination";
-import { SavedJobsRepository } from "../repository/savedjobs.repository";
-import { GetAllSavedJobsDto } from "../dtos/get-all-savedjobs.dto";
+import { Injectable } from '@nestjs/common';
+import { SavedJobsEntity } from 'src/database/entities/savedjobs.entity';
+import { PageDto, PageOptionsDto } from 'src/shared/pagination';
+import { SavedJobsRepository } from '../repository/savedjobs.repository';
+import { GetAllSavedJobsDto } from '../dtos/get-all-savedjobs.dto';
🧰 Tools
🪛 ESLint

[error] 1-1: Replace "@nestjs/common";␍ with '@nestjs/common';

(prettier/prettier)


[error] 2-2: Replace "src/database/entities/savedjobs.entity";␍ with 'src/database/entities/savedjobs.entity';

(prettier/prettier)


[error] 3-3: Replace "src/shared/pagination";␍ with 'src/shared/pagination';

(prettier/prettier)


[error] 4-4: Replace "../repository/savedjobs.repository";␍ with '../repository/savedjobs.repository';

(prettier/prettier)


[error] 5-5: Replace "../dtos/get-all-savedjobs.dto";␍ with '../dtos/get-all-savedjobs.dto';

(prettier/prettier)


11-16: Bom trabalho na implementação do método execute.

O método está corretamente tipado com os parâmetros pageOptionsDto e filters, e retorna uma Promise com o tipo PageDto<SavedJobsEntity>. A função atua como uma passagem direta para o repositório, o que segue o princípio de responsabilidade única.

Considere adicionar tratamento de erros no nível do serviço para casos que o repositório não cobriu.

  async execute(
    pageOptionsDto: PageOptionsDto,
    filters: GetAllSavedJobsDto,
  ): Promise<PageDto<SavedJobsEntity>> {
-    return this.savedJobsRepository.getAllSavedJobs(pageOptionsDto, filters);
+    try {
+      return await this.savedJobsRepository.getAllSavedJobs(pageOptionsDto, filters);
+    } catch (error) {
+      // Adicione tratamento específico se necessário ou apenas re-lance o erro
+      throw error;
+    }
  }
🧰 Tools
🪛 ESLint

[error] 11-11: Delete

(prettier/prettier)


[error] 12-12: Delete

(prettier/prettier)


[error] 13-13: Delete

(prettier/prettier)


[error] 14-14: Delete

(prettier/prettier)


[error] 15-15: Delete

(prettier/prettier)


[error] 16-16: Delete

(prettier/prettier)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13ff3d5 and 25bcbaf.

📒 Files selected for processing (1)
  • src/modules/savedjobs/services/find-all-savedjobs.service.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/modules/savedjobs/services/find-all-savedjobs.service.ts (4)
src/modules/savedjobs/repository/savedjobs.repository.ts (1)
  • Injectable (8-44)
src/shared/pagination/pageOptions.dto.ts (1)
  • PageOptionsDto (6-42)
src/modules/savedjobs/dtos/get-all-savedjobs.dto.ts (1)
  • GetAllSavedJobsDto (4-22)
src/shared/pagination/page.dto.ts (1)
  • PageDto (4-14)
🪛 ESLint
src/modules/savedjobs/services/find-all-savedjobs.service.ts

[error] 1-1: Replace "@nestjs/common";␍ with '@nestjs/common';

(prettier/prettier)


[error] 2-2: Replace "src/database/entities/savedjobs.entity";␍ with 'src/database/entities/savedjobs.entity';

(prettier/prettier)


[error] 3-3: Replace "src/shared/pagination";␍ with 'src/shared/pagination';

(prettier/prettier)


[error] 4-4: Replace "../repository/savedjobs.repository";␍ with '../repository/savedjobs.repository';

(prettier/prettier)


[error] 5-5: Replace "../dtos/get-all-savedjobs.dto";␍ with '../dtos/get-all-savedjobs.dto';

(prettier/prettier)


[error] 6-6: Delete

(prettier/prettier)


[error] 7-7: Delete

(prettier/prettier)


[error] 8-8: Delete

(prettier/prettier)


[error] 9-9: Delete

(prettier/prettier)


[error] 10-10: Delete

(prettier/prettier)


[error] 11-11: Delete

(prettier/prettier)


[error] 12-12: Delete

(prettier/prettier)


[error] 13-13: Delete

(prettier/prettier)


[error] 14-14: Delete

(prettier/prettier)


[error] 15-15: Delete

(prettier/prettier)


[error] 16-16: Delete

(prettier/prettier)


[error] 17-17: Insert

(prettier/prettier)

🔇 Additional comments (2)
src/modules/savedjobs/services/find-all-savedjobs.service.ts (2)

8-9: Service implementado adequadamente com injeção de dependência.

A classe segue corretamente o padrão de injeção de dependência do NestJS com o decorator @Injectable() e recebe o repositório no construtor.

🧰 Tools
🪛 ESLint

[error] 8-8: Delete

(prettier/prettier)


[error] 9-9: Delete

(prettier/prettier)


1-17:

Details

❓ Verification inconclusive

Avalie a necessidade de verificação de autorização.

O serviço não verifica se o usuário tem permissão para acessar as vagas salvas. Considere implementar verificações de autorização para garantir que um usuário só possa ver suas próprias vagas salvas, a menos que seja um administrador.


🏁 Script executed:

#!/bin/bash
# Verificar se há verificações de autorização no controller correspondente

# Procurar pelo controller que usa este serviço
rg -A 10 "FindAllSavedJobsService" --type ts

# Verificar se existem decorators de autorização nos arquivos do módulo
rg "@UseGuards|@Roles|@RequirePermissions" --type ts src/modules/savedjobs/

Length of output: 3937


Rever autorização na listagem de vagas salvas

No serviço FindAllSavedJobsService (src/modules/savedjobs/services/find-all-savedjobs.service.ts, linhas 1-17) não há verificação interna de autorização. Embora o controller (src/modules/savedjobs/savedjobs.controller.ts) utilize @UseGuards(AuthGuard()) para a rota de criação (exemplo: método saveJob), não foi possível confirmar que o endpoint que lista as vagas salvas está protegido de forma similar.

  • Verifique se o endpoint que invoca FindAllSavedJobsService implementa proteção de autorização para garantir que apenas o usuário proprietário (ou um administrador) possa acessar as vagas salvas.
  • Caso a proteção já esteja sendo tratada em outro nível, confirme que todos os endpoints relevantes estão adequadamente protegidos.
🧰 Tools
🪛 ESLint

[error] 1-1: Replace "@nestjs/common";␍ with '@nestjs/common';

(prettier/prettier)


[error] 2-2: Replace "src/database/entities/savedjobs.entity";␍ with 'src/database/entities/savedjobs.entity';

(prettier/prettier)


[error] 3-3: Replace "src/shared/pagination";␍ with 'src/shared/pagination';

(prettier/prettier)


[error] 4-4: Replace "../repository/savedjobs.repository";␍ with '../repository/savedjobs.repository';

(prettier/prettier)


[error] 5-5: Replace "../dtos/get-all-savedjobs.dto";␍ with '../dtos/get-all-savedjobs.dto';

(prettier/prettier)


[error] 6-6: Delete

(prettier/prettier)


[error] 7-7: Delete

(prettier/prettier)


[error] 8-8: Delete

(prettier/prettier)


[error] 9-9: Delete

(prettier/prettier)


[error] 10-10: Delete

(prettier/prettier)


[error] 11-11: Delete

(prettier/prettier)


[error] 12-12: Delete

(prettier/prettier)


[error] 13-13: Delete

(prettier/prettier)


[error] 14-14: Delete

(prettier/prettier)


[error] 15-15: Delete

(prettier/prettier)


[error] 16-16: Delete

(prettier/prettier)


[error] 17-17: Insert

(prettier/prettier)

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/database/entities/savedjobs.entity.ts (1)

21-22: ⚠️ Potential issue

Por que o jobId está configurado como nullable?

O campo jobId está definido como nullable: true, o que permite salvar empregos sem um ID de job válido. Isso parece contraditório com o propósito da entidade, já que um "emprego salvo" sem referência a um emprego real não faz sentido do ponto de vista de negócio.

Além disso, não há garantia de integridade referencial, pois o campo está definido como uma simples coluna UUID em vez de uma relação com a entidade de empregos.

Sugestão:

  1. Altere para nullable: false ou
  2. Preferivelmente, transforme em uma relação ManyToOne com a entidade Jobs:
- @Column('uuid', { nullable: true })
- jobId: string;
+ @ManyToOne(() => JobsEntity, { onDelete: 'CASCADE', nullable: false })
+ @JoinColumn({ name: 'jobId' })
+ job: JobsEntity;

Isso garantirá a integridade referencial e impedirá a criação de registros sem um job válido.

🧰 Tools
🪛 ESLint

[error] 21-21: Delete ··

(prettier/prettier)


[error] 22-22: Replace ···· with ··

(prettier/prettier)

🧹 Nitpick comments (4)
src/database/entities/savedjobs.entity.ts (4)

1-33: Adicione índices para melhorar a performance de consultas

A entidade não possui índices definidos além da chave primária. Para melhorar o desempenho das consultas, especialmente ao buscar empregos salvos por jobId ou userId, é recomendável adicionar índices apropriados.

@Entity('tb_saved_jobs')
+ @Index(['jobId'])
+ @Index(['user'])
export class SavedJobsEntity {
  // restante do código
}

Não se esqueça de importar o decorador Index do typeorm:

import {
  Column,
  CreateDateColumn,
  Entity,
+ Index,
  ManyToOne,
  PrimaryGeneratedColumn,
} from 'typeorm';
🧰 Tools
🪛 ESLint

[error] 2-2: Delete ··

(prettier/prettier)


[error] 3-3: Delete ··

(prettier/prettier)


[error] 4-4: Replace ···· with ··

(prettier/prettier)


[error] 5-5: Delete ··

(prettier/prettier)


[error] 6-6: Replace ···· with ··

(prettier/prettier)


[error] 7-7: Delete ··

(prettier/prettier)


[error] 8-8: Delete ··

(prettier/prettier)


[error] 9-9: Delete ··

(prettier/prettier)


[error] 10-10: Delete ··

(prettier/prettier)


[error] 11-11: Delete ··

(prettier/prettier)


[error] 12-12: Replace ···· with ··

(prettier/prettier)


[error] 13-13: Delete ··

(prettier/prettier)


[error] 14-14: Delete ··

(prettier/prettier)


[error] 15-15: Delete ··

(prettier/prettier)


[error] 16-16: Delete ··

(prettier/prettier)


[error] 17-17: Delete ··

(prettier/prettier)


[error] 18-18: Replace ···· with ··

(prettier/prettier)


[error] 19-19: Delete ··

(prettier/prettier)


[error] 20-20: Delete ··

(prettier/prettier)


[error] 21-21: Delete ··

(prettier/prettier)


[error] 22-22: Replace ···· with ··

(prettier/prettier)


[error] 23-23: Delete ··

(prettier/prettier)


[error] 24-24: Replace ···· with ··

(prettier/prettier)


[error] 25-25: Delete ··

(prettier/prettier)


[error] 26-26: Delete ··

(prettier/prettier)


[error] 27-27: Delete ··

(prettier/prettier)


[error] 28-28: Replace ······ with ····

(prettier/prettier)


[error] 29-29: Delete ··

(prettier/prettier)


[error] 30-30: Replace ······ with ····

(prettier/prettier)


[error] 31-31: Delete ··

(prettier/prettier)


[error] 32-32: Delete ··

(prettier/prettier)


[error] 33-33: Replace ··} with }⏎

(prettier/prettier)


1-33: Adicione documentação para a entidade e seus campos

A entidade não possui documentação explicando seu propósito e o significado de seus campos. Adicionar comentários JSDoc melhoraria a compreensão do código para outros desenvolvedores.

Exemplo:

/**
+ * Entidade que representa um emprego salvo por um usuário.
+ * Esta tabela armazena as relações entre usuários e vagas que eles salvaram.
+ */
@Entity('tb_saved_jobs')
export class SavedJobsEntity {
  @PrimaryGeneratedColumn('uuid')
+ /** Identificador único do registro de emprego salvo */
  id: string;

  @ManyToOne(() => UsersEntity, (user) => user.savedJobs, {
    onDelete: 'CASCADE',
    nullable: false,
  })
+ /** Usuário que salvou o emprego */
  user: UsersEntity;
  
  // Outros campos...
}
🧰 Tools
🪛 ESLint

[error] 2-2: Delete ··

(prettier/prettier)


[error] 3-3: Delete ··

(prettier/prettier)


[error] 4-4: Replace ···· with ··

(prettier/prettier)


[error] 5-5: Delete ··

(prettier/prettier)


[error] 6-6: Replace ···· with ··

(prettier/prettier)


[error] 7-7: Delete ··

(prettier/prettier)


[error] 8-8: Delete ··

(prettier/prettier)


[error] 9-9: Delete ··

(prettier/prettier)


[error] 10-10: Delete ··

(prettier/prettier)


[error] 11-11: Delete ··

(prettier/prettier)


[error] 12-12: Replace ···· with ··

(prettier/prettier)


[error] 13-13: Delete ··

(prettier/prettier)


[error] 14-14: Delete ··

(prettier/prettier)


[error] 15-15: Delete ··

(prettier/prettier)


[error] 16-16: Delete ··

(prettier/prettier)


[error] 17-17: Delete ··

(prettier/prettier)


[error] 18-18: Replace ···· with ··

(prettier/prettier)


[error] 19-19: Delete ··

(prettier/prettier)


[error] 20-20: Delete ··

(prettier/prettier)


[error] 21-21: Delete ··

(prettier/prettier)


[error] 22-22: Replace ···· with ··

(prettier/prettier)


[error] 23-23: Delete ··

(prettier/prettier)


[error] 24-24: Replace ···· with ··

(prettier/prettier)


[error] 25-25: Delete ··

(prettier/prettier)


[error] 26-26: Delete ··

(prettier/prettier)


[error] 27-27: Delete ··

(prettier/prettier)


[error] 28-28: Replace ······ with ····

(prettier/prettier)


[error] 29-29: Delete ··

(prettier/prettier)


[error] 30-30: Replace ······ with ····

(prettier/prettier)


[error] 31-31: Delete ··

(prettier/prettier)


[error] 32-32: Delete ··

(prettier/prettier)


[error] 33-33: Replace ··} with }⏎

(prettier/prettier)


1-33: Corrija a formatação do código para seguir o padrão do projeto

O código contém problemas de formatação como identificado pelas ferramentas de análise estática. Certifique-se de usar a configuração de formatação correta e execute o prettier para formatar o arquivo adequadamente.

Execute o seguinte comando para corrigir automaticamente os problemas de formatação:

npm run format

ou

yarn format
🧰 Tools
🪛 ESLint

[error] 2-2: Delete ··

(prettier/prettier)


[error] 3-3: Delete ··

(prettier/prettier)


[error] 4-4: Replace ···· with ··

(prettier/prettier)


[error] 5-5: Delete ··

(prettier/prettier)


[error] 6-6: Replace ···· with ··

(prettier/prettier)


[error] 7-7: Delete ··

(prettier/prettier)


[error] 8-8: Delete ··

(prettier/prettier)


[error] 9-9: Delete ··

(prettier/prettier)


[error] 10-10: Delete ··

(prettier/prettier)


[error] 11-11: Delete ··

(prettier/prettier)


[error] 12-12: Replace ···· with ··

(prettier/prettier)


[error] 13-13: Delete ··

(prettier/prettier)


[error] 14-14: Delete ··

(prettier/prettier)


[error] 15-15: Delete ··

(prettier/prettier)


[error] 16-16: Delete ··

(prettier/prettier)


[error] 17-17: Delete ··

(prettier/prettier)


[error] 18-18: Replace ···· with ··

(prettier/prettier)


[error] 19-19: Delete ··

(prettier/prettier)


[error] 20-20: Delete ··

(prettier/prettier)


[error] 21-21: Delete ··

(prettier/prettier)


[error] 22-22: Replace ···· with ··

(prettier/prettier)


[error] 23-23: Delete ··

(prettier/prettier)


[error] 24-24: Replace ···· with ··

(prettier/prettier)


[error] 25-25: Delete ··

(prettier/prettier)


[error] 26-26: Delete ··

(prettier/prettier)


[error] 27-27: Delete ··

(prettier/prettier)


[error] 28-28: Replace ······ with ····

(prettier/prettier)


[error] 29-29: Delete ··

(prettier/prettier)


[error] 30-30: Replace ······ with ····

(prettier/prettier)


[error] 31-31: Delete ··

(prettier/prettier)


[error] 32-32: Delete ··

(prettier/prettier)


[error] 33-33: Replace ··} with }⏎

(prettier/prettier)


24-25: Considere adicionar campo updatedAt para rastreamento de modificações

A entidade possui apenas o campo savedAt, mas não tem um campo para rastrear atualizações. Embora possa não ser essencial para esta entidade específica (se você não espera que os registros sejam atualizados), é uma boa prática incluir um campo updatedAt para manter consistência com outras entidades e facilitar auditorias futuras.

@CreateDateColumn()
savedAt: Date;

+ @UpdateDateColumn()
+ updatedAt: Date;

Não se esqueça de adicionar o import:

import {
  Column,
  CreateDateColumn,
+ UpdateDateColumn,
  Entity,
  ManyToOne,
  PrimaryGeneratedColumn,
} from 'typeorm';
🧰 Tools
🪛 ESLint

[error] 24-24: Replace ···· with ··

(prettier/prettier)


[error] 25-25: Delete ··

(prettier/prettier)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 25bcbaf and 40673a1.

📒 Files selected for processing (1)
  • src/database/entities/savedjobs.entity.ts (1 hunks)
🧰 Additional context used
🪛 ESLint
src/database/entities/savedjobs.entity.ts

[error] 2-2: Delete ··

(prettier/prettier)


[error] 3-3: Delete ··

(prettier/prettier)


[error] 4-4: Replace ···· with ··

(prettier/prettier)


[error] 5-5: Delete ··

(prettier/prettier)


[error] 6-6: Replace ···· with ··

(prettier/prettier)


[error] 7-7: Delete ··

(prettier/prettier)


[error] 8-8: Delete ··

(prettier/prettier)


[error] 9-9: Delete ··

(prettier/prettier)


[error] 10-10: Delete ··

(prettier/prettier)


[error] 11-11: Delete ··

(prettier/prettier)


[error] 12-12: Replace ···· with ··

(prettier/prettier)


[error] 13-13: Delete ··

(prettier/prettier)


[error] 14-14: Delete ··

(prettier/prettier)


[error] 15-15: Delete ··

(prettier/prettier)


[error] 16-16: Delete ··

(prettier/prettier)


[error] 17-17: Delete ··

(prettier/prettier)


[error] 18-18: Replace ···· with ··

(prettier/prettier)


[error] 19-19: Delete ··

(prettier/prettier)


[error] 20-20: Delete ··

(prettier/prettier)


[error] 21-21: Delete ··

(prettier/prettier)


[error] 22-22: Replace ···· with ··

(prettier/prettier)


[error] 23-23: Delete ··

(prettier/prettier)


[error] 24-24: Replace ···· with ··

(prettier/prettier)


[error] 25-25: Delete ··

(prettier/prettier)


[error] 26-26: Delete ··

(prettier/prettier)


[error] 27-27: Delete ··

(prettier/prettier)


[error] 28-28: Replace ······ with ····

(prettier/prettier)


[error] 29-29: Delete ··

(prettier/prettier)


[error] 30-30: Replace ······ with ····

(prettier/prettier)


[error] 31-31: Delete ··

(prettier/prettier)


[error] 32-32: Delete ··

(prettier/prettier)


[error] 33-33: Replace ··} with }⏎

(prettier/prettier)

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
src/shared/Swagger/decorators/savedjobs/create-savedjobs.swagger.decorator.ts (1)

11-11: Tipo de resposta incorreto para a criação bem-sucedida.

O NotFoundSwagger está sendo usado para representar uma resposta de sucesso (status 201), o que é semanticamente incorreto. A resposta de sucesso deve utilizar um tipo que represente a estrutura dos dados retornados quando uma vaga é salva com sucesso.

-      type: NotFoundSwagger,
+      type: SavedJobResponseSwagger, // Substitua pelo tipo que representa uma vaga salva com sucesso

Recomendo criar uma classe específica como SavedJobResponseSwagger que reflita a estrutura de uma vaga salva.

🧰 Tools
🪛 ESLint

[error] 11-11: Delete

(prettier/prettier)

🧹 Nitpick comments (3)
src/shared/Swagger/decorators/savedjobs/create-savedjobs.swagger.decorator.ts (1)

19-19: Remover espaços extras.

Existem espaços extras após a vírgula que devem ser removidos para manter a consistência no código.

-      status: HttpStatus.CONFLICT,  
+      status: HttpStatus.CONFLICT,
🧰 Tools
🪛 ESLint

[error] 19-19: Delete ··␍

(prettier/prettier)

src/modules/savedjobs/services/savedjobs.service.ts (2)

29-30: Ajuste de formatação sugerido pelo Prettier.
A mensagem de exceção precisa de uma formatação específica indicada pelo lint para manter o padrão do projeto.

- throw new BadRequestException('O ID do usuário e o ID da vaga devem ser fornecidos');
+ throw new BadRequestException(
+   'O ID do usuário e o ID da vaga devem ser fornecidos',
+ );
🧰 Tools
🪛 ESLint

[error] 30-30: Replace 'O·ID·do·usuário·e·o·ID·da·vaga·devem·ser·fornecidos' with ⏎········'O·ID·do·usuário·e·o·ID·da·vaga·devem·ser·fornecidos',⏎······

(prettier/prettier)


43-45: Inserir vírgula após a chave jobId.
Segundo o relatório do ESLint/Prettier, falta uma vírgula para manter o padrão de formatação.

where: { user: user, jobId }
+ where: { user: user, jobId },
🧰 Tools
🪛 ESLint

[error] 44-44: Insert ,

(prettier/prettier)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40673a1 and 6fe9921.

📒 Files selected for processing (2)
  • src/modules/savedjobs/services/savedjobs.service.ts (1 hunks)
  • src/shared/Swagger/decorators/savedjobs/create-savedjobs.swagger.decorator.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/shared/Swagger/decorators/savedjobs/create-savedjobs.swagger.decorator.ts (2)
src/shared/Swagger/not-found.swagger.ts (1)
  • NotFoundSwagger (2-5)
src/shared/Swagger/bad-request.swagger.ts (1)
  • BadRequestSwagger (2-5)
src/modules/savedjobs/services/savedjobs.service.ts (2)
src/modules/savedjobs/repository/savedjobs.repository.ts (1)
  • Injectable (8-44)
src/modules/savedjobs/dtos/create-savedJob-dto.ts (1)
  • CreateSavedJobDto (3-11)
🪛 ESLint
src/shared/Swagger/decorators/savedjobs/create-savedjobs.swagger.decorator.ts

[error] 1-1: Replace "@nestjs/common";␍ with '@nestjs/common';

(prettier/prettier)


[error] 2-2: Replace "@nestjs/swagger";␍ with '@nestjs/swagger';

(prettier/prettier)


[error] 3-3: Replace "../../not-found.swagger";␍ with '../../not-found.swagger';

(prettier/prettier)


[error] 4-4: Replace "../../bad-request.swagger";␍ with '../../bad-request.swagger';

(prettier/prettier)


[error] 5-5: Delete

(prettier/prettier)


[error] 6-6: Delete

(prettier/prettier)


[error] 7-7: Delete

(prettier/prettier)


[error] 8-8: Delete

(prettier/prettier)


[error] 9-9: Delete

(prettier/prettier)


[error] 10-10: Replace ·'Cadastro·realizado·com·sucesso.·Retorna·os·dados·do·novo·registro.',␍ with ⏎········'Cadastro·realizado·com·sucesso.·Retorna·os·dados·do·novo·registro.',

(prettier/prettier)


[error] 11-11: Delete

(prettier/prettier)


[error] 12-12: Delete

(prettier/prettier)


[error] 13-13: Delete

(prettier/prettier)


[error] 14-14: Delete

(prettier/prettier)


[error] 15-15: Replace ·'Requisição·inválida.·Verifique·os·campos·enviados·no·corpo·da·requisição.',␍ with ⏎········'Requisição·inválida.·Verifique·os·campos·enviados·no·corpo·da·requisição.',

(prettier/prettier)


[error] 16-16: Delete

(prettier/prettier)


[error] 17-17: Delete

(prettier/prettier)


[error] 18-18: Delete

(prettier/prettier)


[error] 19-19: Delete ··␍

(prettier/prettier)


[error] 20-20: Delete

(prettier/prettier)


[error] 21-21: Delete

(prettier/prettier)


[error] 22-22: Delete

(prettier/prettier)


[error] 23-23: Delete

(prettier/prettier)


[error] 24-24: Replace ········description:·'Endpoint·responsável·por·criar·uma·vaga·salva.·Requer·dados·obrigatórios·no·corpo·da·requisição.',␍ with ······description:⏎········'Endpoint·responsável·por·criar·uma·vaga·salva.·Requer·dados·obrigatórios·no·corpo·da·requisição.',

(prettier/prettier)


[error] 25-25: Delete

(prettier/prettier)


[error] 26-26: Delete

(prettier/prettier)


[error] 27-27: Delete

(prettier/prettier)

src/modules/savedjobs/services/savedjobs.service.ts

[error] 30-30: Replace 'O·ID·do·usuário·e·o·ID·da·vaga·devem·ser·fornecidos' with ⏎········'O·ID·do·usuário·e·o·ID·da·vaga·devem·ser·fornecidos',⏎······

(prettier/prettier)


[error] 44-44: Insert ,

(prettier/prettier)

🔇 Additional comments (2)
src/shared/Swagger/decorators/savedjobs/create-savedjobs.swagger.decorator.ts (1)

6-27: Implementar validação para evitar duplicações.

Conforme sugerido em um comentário anterior, é importante validar se a vaga já foi salva pelo usuário antes de salvar novamente. Embora esta validação deva ser implementada no controlador ou serviço, é bom garantir que a documentação Swagger reflita corretamente este comportamento, como já está fazendo com a resposta 409.

Observe que o endpoint já prevê o status 409 para o caso de vaga já salva, o que é correto.

🧰 Tools
🪛 ESLint

[error] 6-6: Delete

(prettier/prettier)


[error] 7-7: Delete

(prettier/prettier)


[error] 8-8: Delete

(prettier/prettier)


[error] 9-9: Delete

(prettier/prettier)


[error] 10-10: Replace ·'Cadastro·realizado·com·sucesso.·Retorna·os·dados·do·novo·registro.',␍ with ⏎········'Cadastro·realizado·com·sucesso.·Retorna·os·dados·do·novo·registro.',

(prettier/prettier)


[error] 11-11: Delete

(prettier/prettier)


[error] 12-12: Delete

(prettier/prettier)


[error] 13-13: Delete

(prettier/prettier)


[error] 14-14: Delete

(prettier/prettier)


[error] 15-15: Replace ·'Requisição·inválida.·Verifique·os·campos·enviados·no·corpo·da·requisição.',␍ with ⏎········'Requisição·inválida.·Verifique·os·campos·enviados·no·corpo·da·requisição.',

(prettier/prettier)


[error] 16-16: Delete

(prettier/prettier)


[error] 17-17: Delete

(prettier/prettier)


[error] 18-18: Delete

(prettier/prettier)


[error] 19-19: Delete ··␍

(prettier/prettier)


[error] 20-20: Delete

(prettier/prettier)


[error] 21-21: Delete

(prettier/prettier)


[error] 22-22: Delete

(prettier/prettier)


[error] 23-23: Delete

(prettier/prettier)


[error] 24-24: Replace ········description:·'Endpoint·responsável·por·criar·uma·vaga·salva.·Requer·dados·obrigatórios·no·corpo·da·requisição.',␍ with ······description:⏎········'Endpoint·responsável·por·criar·uma·vaga·salva.·Requer·dados·obrigatórios·no·corpo·da·requisição.',

(prettier/prettier)


[error] 25-25: Delete

(prettier/prettier)


[error] 26-26: Delete

(prettier/prettier)


[error] 27-27: Delete

(prettier/prettier)

src/modules/savedjobs/services/savedjobs.service.ts (1)

1-22: Ótima separação de responsabilidades e uso correto dos repositórios.
A declaração do serviço com o decorador @Injectable() e a injeção de dependências via constructor estão corretas e bem estruturadas.

Comment on lines +1 to +5
import { applyDecorators, HttpStatus } from "@nestjs/common";
import { ApiOperation, ApiResponse } from "@nestjs/swagger";
import { NotFoundSwagger } from "../../not-found.swagger";
import { BadRequestSwagger } from "../../bad-request.swagger";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Falta importação para o tipo de resposta de sucesso.

Está faltando a importação de um tipo adequado para representar a resposta de sucesso da criação de uma vaga salva.

 import { applyDecorators, HttpStatus } from "@nestjs/common";
 import { ApiOperation, ApiResponse } from "@nestjs/swagger";
 import { NotFoundSwagger } from "../../not-found.swagger";
 import { BadRequestSwagger } from "../../bad-request.swagger";
+import { SavedJobResponseSwagger } from "../../saved-job-response.swagger"; // Importe o tipo correto
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { applyDecorators, HttpStatus } from "@nestjs/common";
import { ApiOperation, ApiResponse } from "@nestjs/swagger";
import { NotFoundSwagger } from "../../not-found.swagger";
import { BadRequestSwagger } from "../../bad-request.swagger";
import { applyDecorators, HttpStatus } from "@nestjs/common";
import { ApiOperation, ApiResponse } from "@nestjs/swagger";
import { NotFoundSwagger } from "../../not-found.swagger";
import { BadRequestSwagger } from "../../bad-request.swagger";
import { SavedJobResponseSwagger } from "../../saved-job-response.swagger"; // Importe o tipo correto
🧰 Tools
🪛 ESLint

[error] 1-1: Replace "@nestjs/common";␍ with '@nestjs/common';

(prettier/prettier)


[error] 2-2: Replace "@nestjs/swagger";␍ with '@nestjs/swagger';

(prettier/prettier)


[error] 3-3: Replace "../../not-found.swagger";␍ with '../../not-found.swagger';

(prettier/prettier)


[error] 4-4: Replace "../../bad-request.swagger";␍ with '../../bad-request.swagger';

(prettier/prettier)


[error] 5-5: Delete

(prettier/prettier)

Comment on lines +43 to +49
const existingSavedJob = await this.savedJobsRepository.findOne({
where: { user: user, jobId }
});

if (existingSavedJob) {
throw new BadRequestException('Este trabalho já foi salvo pelo usuário');
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Prevenir condições de corrida ao salvar vagas duplicadas.
Ao verificar se o usuário já salvou a vaga, ainda pode haver problemas de duplicidade em cenários concorrentes (por exemplo, se duas requisições simultâneas passarem pela checagem antes de salvar). Sugere-se criar uma constraint de unicidade no banco para (userId, jobId) ou envolver a lógica em transação para proteção contra duplicações concorrentes.

🧰 Tools
🪛 ESLint

[error] 44-44: Insert ,

(prettier/prettier)

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

♻️ Duplicate comments (2)
src/database/entities/savedjobs.entity.ts (1)

23-24: 🛠️ Refactor suggestion

Considere tornar jobId não nulo.

O campo jobId está configurado como nullable, mas isso parece contradizer o propósito da entidade. Como um usuário poderia salvar uma vaga sem o ID da vaga? Recomendo alterar para não-nulo para manter a integridade dos dados.

-@Column('uuid', { nullable: true })
+@Column('uuid', { nullable: false })
 jobId: string;
🧰 Tools
🪛 ESLint

[error] 23-23: Delete ··

(prettier/prettier)


[error] 24-24: Delete ··

(prettier/prettier)

src/modules/savedjobs/savedjobs.controller.ts (1)

43-60: 🛠️ Refactor suggestion

Utilize o usuário autenticado para filtrar as vagas salvas.

O endpoint getAllSavedJobs está protegido com AuthGuard(), mas não utiliza o usuário autenticado para filtrar as vagas. É mais seguro e correto mostrar apenas as vagas salvas do usuário autenticado.

  @Get()
  @ApiBearerAuth()
  @UseGuards(AuthGuard())
  @SwaggerFindSavedJobs()
  @ApiOperation({ summary: 'Obtenha todos os trabalhos salvos com filtros e paginação.' })
  async getAllSavedJobs(
    @Query() pageOptionsDto: PageOptionsDto,
    @Query() query: GetAllSavedJobsDto,
+   @GetUser() user: UsersEntity,
  ): Promise<PageDto<SavedJobsEntity>> {
    try {
-     return await this.findAllSavedJobsService.execute(pageOptionsDto, query);
+     return this.findAllSavedJobsService.execute(pageOptionsDto, {
+       ...query,
+       userId: user.id
+     });
    } catch (error) {
      throw new HttpException(
        'Erro ao buscar vagas salvas',
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

Certifique-se de que o DTO GetAllSavedJobsDto tenha o campo userId opcional:

export class GetAllSavedJobsDto {
+ @IsOptional()
+ @IsUUID()
+ userId?: string;

  // outros campos...
}
🧰 Tools
🪛 ESLint

[error] 47-47: Replace ·summary:·'Obtenha·todos·os·trabalhos·salvos·com·filtros·e·paginação.' with ⏎····summary:·'Obtenha·todos·os·trabalhos·salvos·com·filtros·e·paginação.',⏎·

(prettier/prettier)

🧹 Nitpick comments (3)
src/modules/savedjobs/services/savedjobs.service.ts (3)

45-51: Implementação correta para evitar duplicações de vagas salvas.

A verificação de vagas já salvas pelo usuário e o lançamento de exceção apropriada é uma boa abordagem para evitar duplicações. Considere adicionar também uma restrição de unicidade no nível do banco de dados para prevenir condições de corrida em ambientes de alta concorrência.

Para garantir ainda mais proteção contra duplicidades em cenários concorrentes, você poderia envolver a operação em uma transação ou implementar uma restrição única no banco de dados para o par (userId, jobId).

🧰 Tools
🪛 ESLint

[error] 46-46: Insert ,

(prettier/prettier)


54-59: Remova a linha em branco desnecessária.

Há uma linha em branco desnecessária entre a criação do objeto e suas propriedades.

 const newSavedJob = this.savedJobsRepository.create({
-      
      user,
      jobId,
      savedAt: new Date(),
 });
🧰 Tools
🪛 ESLint

[error] 54-55: Delete ⏎······

(prettier/prettier)


29-38: Verificação de entrada redundante.

A verificação de !userId || !jobId é redundante, pois o DTO já tem decoradores @IsNotEmpty() que validam isso. Se os decoradores estiverem funcionando corretamente com a validação global do NestJS, essa verificação adicional não seria necessária.

🧰 Tools
🪛 ESLint

[error] 30-30: Replace 'O·ID·do·usuário·e·o·ID·da·vaga·devem·ser·fornecidos' with ⏎········'O·ID·do·usuário·e·o·ID·da·vaga·devem·ser·fornecidos',⏎······

(prettier/prettier)


[error] 36-36: Delete ······

(prettier/prettier)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6fe9921 and aaaad9c.

📒 Files selected for processing (4)
  • src/database/entities/savedjobs.entity.ts (1 hunks)
  • src/modules/auth/services/auth-login.service.ts (1 hunks)
  • src/modules/savedjobs/savedjobs.controller.ts (1 hunks)
  • src/modules/savedjobs/services/savedjobs.service.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/database/entities/savedjobs.entity.ts (1)
src/database/entities/users.entity.ts (1)
  • Entity (22-108)
src/modules/savedjobs/services/savedjobs.service.ts (2)
src/modules/savedjobs/repository/savedjobs.repository.ts (1)
  • Injectable (8-44)
src/modules/savedjobs/dtos/create-savedJob-dto.ts (1)
  • CreateSavedJobDto (3-11)
🪛 ESLint
src/database/entities/savedjobs.entity.ts

[error] 2-2: Delete ··

(prettier/prettier)


[error] 3-3: Delete ··

(prettier/prettier)


[error] 4-4: Replace ···· with ··

(prettier/prettier)


[error] 5-5: Delete ··

(prettier/prettier)


[error] 6-6: Replace ···· with ··

(prettier/prettier)


[error] 7-7: Delete ··

(prettier/prettier)


[error] 8-8: Delete ··

(prettier/prettier)


[error] 9-9: Delete ··

(prettier/prettier)


[error] 10-10: Delete ··

(prettier/prettier)


[error] 11-11: Delete ··

(prettier/prettier)


[error] 12-12: Delete ··

(prettier/prettier)


[error] 13-13: Replace ···· with ··

(prettier/prettier)


[error] 14-14: Delete ··

(prettier/prettier)


[error] 15-15: Delete ··

(prettier/prettier)


[error] 16-16: Delete ··

(prettier/prettier)


[error] 17-17: Delete ··

(prettier/prettier)


[error] 18-18: Delete ··

(prettier/prettier)


[error] 19-19: Replace ···· with ··

(prettier/prettier)


[error] 20-20: Delete ··

(prettier/prettier)


[error] 21-21: Delete ··

(prettier/prettier)


[error] 22-22: Delete ··

(prettier/prettier)


[error] 23-23: Delete ··

(prettier/prettier)


[error] 24-24: Delete ··

(prettier/prettier)


[error] 25-25: Delete ··

(prettier/prettier)


[error] 26-26: Delete ··

(prettier/prettier)


[error] 27-27: Delete ··

(prettier/prettier)


[error] 28-28: Delete ··

(prettier/prettier)


[error] 29-29: Delete ··

(prettier/prettier)


[error] 30-30: Replace ······ with ····

(prettier/prettier)


[error] 31-31: Delete ··

(prettier/prettier)


[error] 32-32: Replace ······ with ····

(prettier/prettier)


[error] 33-33: Delete ··

(prettier/prettier)


[error] 34-34: Delete ··

(prettier/prettier)


[error] 35-35: Replace ··} with }⏎

(prettier/prettier)

src/modules/savedjobs/savedjobs.controller.ts

[error] 1-1: Replace ·Body,·Controller,·Get,·HttpException,·HttpStatus,·Post,·Query,·UseGuards· with ⏎··Body,⏎··Controller,⏎··Get,⏎··HttpException,⏎··HttpStatus,⏎··Post,⏎··Query,⏎··UseGuards,⏎

(prettier/prettier)


[error] 12-12: 'log' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 14-15: Delete

(prettier/prettier)


[error] 25-25: Delete ·

(prettier/prettier)


[error] 33-33: Delete ······

(prettier/prettier)


[error] 47-47: Replace ·summary:·'Obtenha·todos·os·trabalhos·salvos·com·filtros·e·paginação.' with ⏎····summary:·'Obtenha·todos·os·trabalhos·salvos·com·filtros·e·paginação.',⏎·

(prettier/prettier)

src/modules/savedjobs/services/savedjobs.service.ts

[error] 30-30: Replace 'O·ID·do·usuário·e·o·ID·da·vaga·devem·ser·fornecidos' with ⏎········'O·ID·do·usuário·e·o·ID·da·vaga·devem·ser·fornecidos',⏎······

(prettier/prettier)


[error] 36-36: Delete ······

(prettier/prettier)


[error] 46-46: Insert ,

(prettier/prettier)


[error] 52-52: Insert ;

(prettier/prettier)


[error] 54-55: Delete ⏎······

(prettier/prettier)

🔇 Additional comments (1)
src/database/entities/savedjobs.entity.ts (1)

16-21: LGTM! Relação com cascata para exclusão.

A configuração da relação com UsersEntity está correta, com cascata para exclusão (onDelete: 'CASCADE') e não permitindo valores nulos (nullable: false), o que garante que quando um usuário for excluído, todas as suas vagas salvas também serão removidas.

🧰 Tools
🪛 ESLint

[error] 16-16: Delete ··

(prettier/prettier)


[error] 17-17: Delete ··

(prettier/prettier)


[error] 18-18: Delete ··

(prettier/prettier)


[error] 19-19: Replace ···· with ··

(prettier/prettier)


[error] 20-20: Delete ··

(prettier/prettier)


[error] 21-21: Delete ··

(prettier/prettier)

Comment on lines +11 to +35
@Entity('tb_saved_jobs')
export class SavedJobsEntity {
@PrimaryGeneratedColumn('uuid')
id: string;

@ManyToOne(() => UsersEntity, (user) => user.savedJobs, {
onDelete: 'CASCADE',
nullable: false,
})
@JoinColumn({ name: 'userId' })
user: UsersEntity;

@Column('uuid', { nullable: true })
jobId: string;

@CreateDateColumn()
savedAt: Date;

constructor(savedJob?: Partial<SavedJobsEntity>) {
this.id = savedJob?.id;
this.user = savedJob?.user;
this.jobId = savedJob?.jobId;
this.savedAt = savedJob?.savedAt;
}
} No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Adicione restrição de unicidade para evitar duplicações.

Não há uma restrição de unicidade para evitar que um usuário salve a mesma vaga várias vezes. Embora a validação seja feita no serviço, é uma boa prática adicionar essa restrição também na camada de banco de dados.

@Entity('tb_saved_jobs')
export class SavedJobsEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @ManyToOne(() => UsersEntity, (user) => user.savedJobs, {
    onDelete: 'CASCADE',
    nullable: false,
  })
  @JoinColumn({ name: 'userId' })
  user: UsersEntity;

  @Column('uuid', { nullable: true })
  jobId: string;

+ @Index('IDX_USER_JOB', ['user', 'jobId'], { unique: true })
  @CreateDateColumn()
  savedAt: Date;

  constructor(savedJob?: Partial<SavedJobsEntity>) {
    this.id = savedJob?.id;
    this.user = savedJob?.user;
    this.jobId = savedJob?.jobId;
    this.savedAt = savedJob?.savedAt;
  }
}

Não esqueça de adicionar a importação:

import { Column, CreateDateColumn, Entity, Index, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
🧰 Tools
🪛 ESLint

[error] 11-11: Delete ··

(prettier/prettier)


[error] 12-12: Delete ··

(prettier/prettier)


[error] 13-13: Replace ···· with ··

(prettier/prettier)


[error] 14-14: Delete ··

(prettier/prettier)


[error] 15-15: Delete ··

(prettier/prettier)


[error] 16-16: Delete ··

(prettier/prettier)


[error] 17-17: Delete ··

(prettier/prettier)


[error] 18-18: Delete ··

(prettier/prettier)


[error] 19-19: Replace ···· with ··

(prettier/prettier)


[error] 20-20: Delete ··

(prettier/prettier)


[error] 21-21: Delete ··

(prettier/prettier)


[error] 22-22: Delete ··

(prettier/prettier)


[error] 23-23: Delete ··

(prettier/prettier)


[error] 24-24: Delete ··

(prettier/prettier)


[error] 25-25: Delete ··

(prettier/prettier)


[error] 26-26: Delete ··

(prettier/prettier)


[error] 27-27: Delete ··

(prettier/prettier)


[error] 28-28: Delete ··

(prettier/prettier)


[error] 29-29: Delete ··

(prettier/prettier)


[error] 30-30: Replace ······ with ····

(prettier/prettier)


[error] 31-31: Delete ··

(prettier/prettier)


[error] 32-32: Replace ······ with ····

(prettier/prettier)


[error] 33-33: Delete ··

(prettier/prettier)


[error] 34-34: Delete ··

(prettier/prettier)


[error] 35-35: Replace ··} with }⏎

(prettier/prettier)

Comment on lines +23 to +41
@Post()
@ApiBearerAuth()
@UseGuards(AuthGuard())
@SwaggerCreateSavedJobs()
@ApiOperation({ summary: 'Salvar vaga para um usuário' })
async saveJob(
@Body() createSavedJobDto: CreateSavedJobDto,
): Promise<SavedJobsEntity> {
try {
console.log(createSavedJobDto);

return await this.savedJobsService.saveJob(createSavedJobDto);
} catch (error) {
throw new HttpException(
'Erro ao salvar vaga',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Utilize o usuário autenticado no endpoint de salvar vagas.

O endpoint está protegido com AuthGuard(), mas não está utilizando as informações do usuário autenticado. Em vez de receber o userId no DTO, é mais seguro obter o usuário diretamente do token de autenticação.

  @Post()
  @ApiBearerAuth()
  @UseGuards(AuthGuard()) 
  @SwaggerCreateSavedJobs()
  @ApiOperation({ summary: 'Salvar vaga para um usuário' })
  async saveJob(
    @Body() createSavedJobDto: CreateSavedJobDto,
+   @GetUser() user: UsersEntity,
  ): Promise<SavedJobsEntity> {
    try {
-     console.log(createSavedJobDto);
      
-     return await this.savedJobsService.saveJob(createSavedJobDto);
+     return this.savedJobsService.saveJob({
+       ...createSavedJobDto,
+       userId: user.id
+     });
    } catch (error) {
      throw new HttpException(
        'Erro ao salvar vaga',
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

Não esqueça de adicionar as importações:

import { GetUser } from '../auth/get-user.decorator';
import { UsersEntity } from '../../database/entities/users.entity';

E atualize o DTO para tornar o userId opcional:

export class CreateSavedJobDto {
- @IsUUID()
- @IsNotEmpty()
+ @IsOptional()
+ @IsUUID()
  userId: string;

  @IsUUID()
  @IsNotEmpty()
  jobId: string;
}
🧰 Tools
🪛 ESLint

[error] 25-25: Delete ·

(prettier/prettier)


[error] 33-33: Delete ······

(prettier/prettier)

… tabelas. ajuste no controller de savedjobs na validacao ds 7 dias
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (6)
src/database/entities/savedjobs.entity.ts (1)

12-40: 🛠️ Refactor suggestion

Adicione restrição de unicidade para evitar duplicações e ajuste a configuração da relação job.

A entidade SavedJobsEntity está bem estruturada, mas possui duas melhorias importantes a serem implementadas:

  1. Não há uma restrição de unicidade para evitar que um usuário salve a mesma vaga várias vezes
  2. A relação com a entidade JobsEntity não tem configuração de onDelete para tratar exclusões em cascata

Aplique estas alterações:

+import {
   Column,
   CreateDateColumn,
   Entity,
+  Index,
   JoinColumn,
   ManyToOne,
   PrimaryGeneratedColumn,
 } from 'typeorm';
 import { UsersEntity } from './users.entity';
 import { JobsEntity } from './jobs.entity';
 
 @Entity('tb_saved_jobs')
+@Index('IDX_USER_JOB', ['user', 'job'], { unique: true })
 export class SavedJobsEntity {
   @PrimaryGeneratedColumn('uuid')
   id: string;
 
   @ManyToOne(() => UsersEntity, (user) => user.savedJobs, {
     onDelete: 'CASCADE',
     nullable: false,
   })
   @JoinColumn({ name: 'userId' })
   user: UsersEntity;
 
-  @ManyToOne(() => JobsEntity, (job) => job.savedJobs, { eager: false })
+  @ManyToOne(() => JobsEntity, (job) => job.savedJobs, { 
+    eager: false,
+    onDelete: 'CASCADE',
+    nullable: false 
+  })
+  @JoinColumn({ name: 'jobId' })
   job: JobsEntity;
 
   @CreateDateColumn()
   savedAt: Date;

Além disso, o nome da coluna da relação deve ser consistente com o uso em migrações (jobId).

src/modules/savedjobs/services/savedjobs.service.ts (1)

42-51: 🛠️ Refactor suggestion

Verificação de duplicidade implementada, mas falta proteção contra condições de corrida.

A verificação se o usuário já salvou a vaga está implementada corretamente, mas ainda pode haver problemas de duplicidade em cenários concorrentes (por exemplo, se duas requisições simultâneas passarem pela checagem antes de salvar).

Recomendo adicionar uma constraint de unicidade no banco de dados para o par (userId, jobId) em uma migração separada:

// Exemplo de migração para adicionar constraint de unicidade
await queryRunner.query(
  `ALTER TABLE "tb_saved_jobs" ADD CONSTRAINT "UQ_user_job" UNIQUE ("userId", "jobId")`
);
🧰 Tools
🪛 ESLint

[error] 45-45: Replace }·,· with ·},

(prettier/prettier)


[error] 50-50: Replace 'Este·trabalho·já·foi·salvo·por·este·usuário.' with ⏎········'Este·trabalho·já·foi·salvo·por·este·usuário.',⏎······

(prettier/prettier)

src/modules/savedjobs/savedjobs.controller.ts (4)

49-53: Especifique um tipo de retorno para o método getAllSavedJobs.

O método não tem um tipo de retorno explícito, o que dificulta a compreensão da API.

  async getAllSavedJobs(
    @Query() pageOptionsDto: PageOptionsDto,
    @Query() query: GetAllSavedJobsDto,
- ) {
+ ): Promise<PageDto<SavedJobsEntity>> {

Não esqueça de adicionar a importação:

import { PageDto } from 'src/shared/pagination';
🧰 Tools
🪛 ESLint

[error] 49-49: Replace ·summary:·'Obtenha·todos·os·trabalhos·salvos·com·filtros·e·paginação.' with ⏎····summary:·'Obtenha·todos·os·trabalhos·salvos·com·filtros·e·paginação.',⏎·

(prettier/prettier)


25-27: 🛠️ Refactor suggestion

Utilize o usuário autenticado ao invés de receber userId via DTO.

O endpoint utiliza autenticação, mas ainda recebe o userId via DTO ao invés de extraí-lo do token JWT, o que pode permitir que um usuário salve vagas em nome de outro.

  async saveJob(
    @Body() createSavedJobDto: CreateSavedJobDto,
+   @GetUser() user: UsersEntity,
  ): Promise<any> { 
    try {
-     const savedJob = await this.savedJobsService.saveJob(createSavedJobDto);
+     const savedJob = await this.savedJobsService.saveJob({
+       ...createSavedJobDto,
+       userId: user.id
+     });

Não esqueça de adicionar as importações:

import { GetUser } from '../../decorators/get-user.decorator';
import { UsersEntity } from '../../../database/entities/users.entity';
🧰 Tools
🪛 ESLint

[error] 25-27: Replace ⏎····@Body()·createSavedJobDto:·CreateSavedJobDto,⏎··):·Promise<any>·{· with @Body()·createSavedJobDto:·CreateSavedJobDto):·Promise<any>·{

(prettier/prettier)


54-61: 🛠️ Refactor suggestion

Inclua detalhes do erro original na exceção.

A exceção lançada não inclui informações sobre o erro original no método getAllSavedJobs, ao contrário do que foi feito no método saveJob.

    } catch (error) {
      throw new HttpException(
-       'Erro ao buscar vagas salvas',
+       `Erro ao buscar vagas salvas: ${error.message || 'erro desconhecido'}`,
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }

45-53: 🛠️ Refactor suggestion

Utilize o usuário autenticado para filtrar os resultados.

O endpoint utiliza autenticação, mas não está aproveitando as informações do usuário para filtrar apenas suas próprias vagas salvas.

  async getAllSavedJobs(
    @Query() pageOptionsDto: PageOptionsDto,
    @Query() query: GetAllSavedJobsDto,
+   @GetUser() user: UsersEntity,
  ) {
    try {
-     return await this.findAllSavedJobsService.execute(pageOptionsDto, query);
+     return await this.findAllSavedJobsService.execute(pageOptionsDto, {
+       ...query,
+       userId: user.id
+     });
🧰 Tools
🪛 ESLint

[error] 49-49: Replace ·summary:·'Obtenha·todos·os·trabalhos·salvos·com·filtros·e·paginação.' with ⏎····summary:·'Obtenha·todos·os·trabalhos·salvos·com·filtros·e·paginação.',⏎·

(prettier/prettier)

🧹 Nitpick comments (8)
src/modules/auth/services/auth-login.service.ts (1)

21-21: Remover linha em branco desnecessária

A linha em branco inserida em 21 gera um desvio nas regras do Prettier (prettier/prettier). Recomendo removê-la para manter o estilo consistente.

🧰 Tools
🪛 ESLint

[error] 21-22: Delete

(prettier/prettier)

src/database/migrations/1745267234389-migrations.ts (1)

1-14: Migração corretamente implementada para atualizar a coluna expiresAt.

A migração remove o valor padrão da coluna "expiresAt" na tabela "tb_saved_jobs", o que é adequado se a intenção é que este valor seja definido explicitamente durante a criação dos registros.

No entanto, há vários problemas de formatação apontados pelo ESLint que precisam ser corrigidos para manter a consistência do código.

Sugiro aplicar as seguintes alterações de formatação:

-import { MigrationInterface, QueryRunner } from "typeorm";
+import { MigrationInterface, QueryRunner } from 'typeorm';

 export class Migrations1745267234389 implements MigrationInterface {
-    name = 'Migrations1745267234389'
+    name = 'Migrations1745267234389';

     public async up(queryRunner: QueryRunner): Promise<void> {
-        await queryRunner.query(`ALTER TABLE "tb_saved_jobs" ALTER COLUMN "expiresAt" DROP DEFAULT`);
+        await queryRunner.query(
+            `ALTER TABLE "tb_saved_jobs" ALTER COLUMN "expiresAt" DROP DEFAULT`
+        );
     }

     public async down(queryRunner: QueryRunner): Promise<void> {
-        await queryRunner.query(`ALTER TABLE "tb_saved_jobs" ALTER COLUMN "expiresAt" SET DEFAULT now()`);
+        await queryRunner.query(
+            `ALTER TABLE "tb_saved_jobs" ALTER COLUMN "expiresAt" SET DEFAULT now()`
+        );
     }
 }
🧰 Tools
🪛 ESLint

[error] 1-1: Replace "typeorm" with 'typeorm'

(prettier/prettier)


[error] 4-4: Replace ··name·=·'Migrations1745267234389' with name·=·'Migrations1745267234389';

(prettier/prettier)


[error] 6-6: Delete ··

(prettier/prettier)


[error] 7-7: Replace ········await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"expiresAt"·DROP·DEFAULT); with ····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"expiresAt"·DROP·DEFAULT,

(prettier/prettier)


[error] 8-9: Replace }⏎ with );

(prettier/prettier)


[error] 10-10: Insert }⏎⏎

(prettier/prettier)


[error] 11-11: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"expiresAt"·SET·DEFAULT·now()`` with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"expiresAt"·SET·DEFAULT·now()`,⏎····`

(prettier/prettier)


[error] 12-13: Replace ··}⏎ with }

(prettier/prettier)

src/database/entities/savedjobs.entity.ts (1)

30-31: Configure propriedades adicionais para a coluna expiresAt.

A coluna expiresAt precisa de configurações adicionais como nullable e default para garantir comportamento consistente.

-  @Column({ type: 'timestamp' })
+  @Column({ type: 'timestamp', nullable: true })
   expiresAt: Date;
src/database/migrations/1745262789787-migrations.ts (2)

6-17: Utilize uma abordagem mais segura para verificação e adição de colunas.

A abordagem de verificar a existência da coluna antes de adicioná-la é boa, mas a implementação pode ser melhorada.

  1. As alterações da tabela poderiam ser agrupadas em uma transação para garantir consistência.
  2. Adicionar verificação de existência das outras operações para evitar erros.
 public async up(queryRunner: QueryRunner): Promise<void> {
     const hasExpiresAt = await queryRunner.hasColumn('tb_saved_jobs', 'expiresAt');
     if (!hasExpiresAt) {
         await queryRunner.query(`ALTER TABLE "tb_saved_jobs" ADD "expiresAt" TIMESTAMP NOT NULL DEFAULT now()`);
     }

+    // Verificar se a constraint existe antes de removê-la
+    const tableConstraints = await queryRunner.query(
+        `SELECT * FROM information_schema.table_constraints 
+         WHERE table_name = 'tb_saved_jobs' AND constraint_name = 'FK_3845b06bfda63ccc1da359b378a'`
+    );
+    
+    if (tableConstraints.length > 0) {
         await queryRunner.query(`ALTER TABLE "tb_saved_jobs" DROP CONSTRAINT "FK_3845b06bfda63ccc1da359b378a"`);
+    }

Além disso, há vários problemas de formatação apontados pelo ESLint que deveriam ser corrigidos.

🧰 Tools
🪛 ESLint

[error] 6-6: Delete ··

(prettier/prettier)


[error] 7-7: Replace ········const·hasExpiresAt·=·await·queryRunner.hasColumn('tb_saved_jobs',·'expiresAt'); with ····const·hasExpiresAt·=·await·queryRunner.hasColumn(⏎······'tb_saved_jobs',⏎······'expiresAt',

(prettier/prettier)


[error] 8-8: Insert );⏎

(prettier/prettier)


[error] 9-9: Replace ············await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now()); with ······await·queryRunner.query(⏎········ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now(),

(prettier/prettier)


[error] 10-11: Replace ··}⏎ with );

(prettier/prettier)


[error] 12-12: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"); with }⏎⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a",

(prettier/prettier)


[error] 13-13: Insert );⏎

(prettier/prettier)


[error] 14-14: Delete ····

(prettier/prettier)


[error] 15-15: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·SET·NOT·NULL); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·SET·NOT·NULL,

(prettier/prettier)


[error] 16-16: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·CASCADE·ON·UPDATE·NO·ACTION); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·CASCADE·ON·UPDATE·NO·ACTION,

(prettier/prettier)


19-27: Garanta que o método down seja totalmente compatível com as alterações do método up.

O método down deve reverter exatamente as alterações feitas no método up, na ordem inversa, para garantir consistência.

Sugiro adicionar verificações similares às do método up para evitar erros durante a reversão:

 public async down(queryRunner: QueryRunner): Promise<void> {
+    // Verificar se a constraint existe antes de removê-la
+    const tableConstraints = await queryRunner.query(
+        `SELECT * FROM information_schema.table_constraints 
+         WHERE table_name = 'tb_saved_jobs' AND constraint_name = 'FK_3845b06bfda63ccc1da359b378a'`
+    );
+    
+    if (tableConstraints.length > 0) {
         await queryRunner.query(`ALTER TABLE "tb_saved_jobs" DROP CONSTRAINT "FK_3845b06bfda63ccc1da359b378a"`);
+    }

Adicionalmente, resolva os problemas de formatação apontados pelo ESLint.

🧰 Tools
🪛 ESLint

[error] 19-19: Insert }⏎⏎

(prettier/prettier)


[error] 20-20: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a",

(prettier/prettier)


[error] 21-21: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·DROP·NOT·NULL); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·DROP·NOT·NULL,

(prettier/prettier)


[error] 22-22: Insert );⏎

(prettier/prettier)


[error] 23-23: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·"jobId"·character·varying·NOT·NULL); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·"jobId"·character·varying·NOT·NULL,

(prettier/prettier)


[error] 24-24: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·COLUMN·"expiresAt"); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·COLUMN·"expiresAt",

(prettier/prettier)


[error] 25-25: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·NO·ACTION·ON·UPDATE·NO·ACTION); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·NO·ACTION·ON·UPDATE·NO·ACTION,

(prettier/prettier)


[error] 26-26: Replace ·· with ····);⏎

(prettier/prettier)

src/database/migrations/1745261990419-migrations.ts (1)

6-13:

Details

❓ Verification inconclusive

Adicionada a funcionalidade de expiração para vagas salvas com CASCADE na exclusão de usuários.

Esta migração adiciona uma coluna expiresAt e muda a restrição de chave estrangeira para CASCADE na exclusão. Isto significa que quando um usuário for excluído, todas as suas vagas salvas serão automaticamente removidas.

A alteração do tipo da coluna jobId de character varying para UUID pode causar problemas de compatibilidade se já existirem dados. Certifique-se de que todos os jobIds existentes são compatíveis com o formato UUID.

Execute este script para verificar se todos os valores de jobId existentes são compatíveis com o formato UUID:


🏁 Script executed:

#!/bin/bash
# Verifica se os valores existentes de jobId são compatíveis com UUID

echo "Verificando formato de jobId na tabela tb_saved_jobs..."
rg -A 3 "INSERT INTO.*tb_saved_jobs.*jobId" --include "*.ts" --include "*.sql"

Length of output: 643


Para ajustar o comando e buscar ocorrências de INSERT em tb_saved_jobs, execute:


🏁 Script executed:

#!/bin/bash
echo "Buscando INSERT INTO tb_saved_jobs em arquivos .ts e .sql..."
rg -g '*.ts' -g '*.sql' 'INSERT INTO.*tb_saved_jobs' -A3

Length of output: 189


Verifique compatibilidade de jobId existente com UUID antes de aplicar a migração

Não foram encontradas inserções de tb_saved_jobs no código; é necessário confirmar diretamente no banco de dados que todos os valores atuais de jobId seguem o formato UUID.

Sugestão de consulta SQL para validação:

SELECT jobId
FROM tb_saved_jobs
WHERE jobId IS NOT NULL
  AND jobId !~* '^[0-9A-F0-9]{8}-[0-9A-F0-9]{4}-[0-9A-F0-9]{4}-[0-9A-F0-9]{4}-[0-9A-F0-9]{12}$';

Se essa consulta retornar qualquer registro, será preciso converter ou atualizar esses valores antes de executar a migração.

🧰 Tools
🪛 ESLint

[error] 6-6: Delete ··

(prettier/prettier)


[error] 7-7: Replace ········await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"); with ····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a",

(prettier/prettier)


[error] 8-8: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now()); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now(),

(prettier/prettier)


[error] 9-9: Insert );⏎

(prettier/prettier)


[error] 10-10: Delete ····

(prettier/prettier)


[error] 11-11: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·SET·NOT·NULL); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·SET·NOT·NULL,

(prettier/prettier)


[error] 12-12: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·CASCADE·ON·UPDATE·NO·ACTION); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·CASCADE·ON·UPDATE·NO·ACTION,

(prettier/prettier)

src/modules/savedjobs/services/savedjobs.service.ts (1)

66-69: Considere limitar os dados retornados nas relações.

Ao retornar as relações completas user e job, você pode estar expondo mais informações do que o necessário, incluindo dados sensíveis do usuário. Considere selecionar apenas os campos necessários dessas entidades.

  return this.savedJobsRepository.findOne({
    where: { id: savedJob.id },
-   relations: ['user', 'job'],
+   relations: ['user', 'job'],
+   select: {
+     id: true,
+     savedAt: true, 
+     expiresAt: true,
+     user: {
+       id: true,
+       name: true,
+       email: true
+     },
+     job: {
+       id: true,
+       title: true,
+       company: true
+     }
+   }
  });
src/modules/savedjobs/savedjobs.controller.ts (1)

27-27: Especifique um tipo de retorno mais preciso.

O tipo de retorno Promise<any> é muito genérico. Especifique um tipo mais preciso para melhorar a documentação da API.

- ): Promise<any> { 
+ ): Promise<{ message: string; statusCode: number; savedJob: SavedJobsEntity }> {
🧰 Tools
🪛 ESLint

[error] 25-27: Replace ⏎····@Body()·createSavedJobDto:·CreateSavedJobDto,⏎··):·Promise<any>·{· with @Body()·createSavedJobDto:·CreateSavedJobDto):·Promise<any>·{

(prettier/prettier)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aaaad9c and d78ccf5.

📒 Files selected for processing (9)
  • src/database/entities/jobs.entity.ts (2 hunks)
  • src/database/entities/savedjobs.entity.ts (1 hunks)
  • src/database/migrations/1745261990419-migrations.ts (1 hunks)
  • src/database/migrations/1745262789787-migrations.ts (1 hunks)
  • src/database/migrations/1745267234389-migrations.ts (1 hunks)
  • src/modules/auth/services/auth-login.service.ts (1 hunks)
  • src/modules/company/repository/company-repository.ts (0 hunks)
  • src/modules/savedjobs/savedjobs.controller.ts (1 hunks)
  • src/modules/savedjobs/services/savedjobs.service.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/modules/company/repository/company-repository.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/database/entities/savedjobs.entity.ts (2)
src/database/entities/jobs.entity.ts (1)
  • Entity (20-142)
src/database/entities/users.entity.ts (1)
  • Entity (22-108)
🪛 ESLint
src/database/migrations/1745267234389-migrations.ts

[error] 1-1: Replace "typeorm" with 'typeorm'

(prettier/prettier)


[error] 4-4: Replace ··name·=·'Migrations1745267234389' with name·=·'Migrations1745267234389';

(prettier/prettier)


[error] 6-6: Delete ··

(prettier/prettier)


[error] 7-7: Replace ········await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"expiresAt"·DROP·DEFAULT); with ····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"expiresAt"·DROP·DEFAULT,

(prettier/prettier)


[error] 8-9: Replace }⏎ with );

(prettier/prettier)


[error] 10-10: Insert }⏎⏎

(prettier/prettier)


[error] 11-11: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"expiresAt"·SET·DEFAULT·now()`` with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"expiresAt"·SET·DEFAULT·now()`,⏎····`

(prettier/prettier)


[error] 12-13: Replace ··}⏎ with }

(prettier/prettier)

src/database/entities/jobs.entity.ts

[error] 141-141: Delete ··

(prettier/prettier)

src/modules/savedjobs/services/savedjobs.service.ts

[error] 24-24: Replace createSavedJobDto:·CreateSavedJobDto with ⏎····createSavedJobDto:·CreateSavedJobDto,⏎··

(prettier/prettier)


[error] 26-26: Delete ·

(prettier/prettier)


[error] 28-28: Replace 'O·ID·do·usuário·e·o·ID·da·vaga·devem·ser·fornecidos' with ⏎········'O·ID·do·usuário·e·o·ID·da·vaga·devem·ser·fornecidos',⏎······

(prettier/prettier)


[error] 30-30: Delete ··

(prettier/prettier)


[error] 35-35: Delete ··

(prettier/prettier)


[error] 41-41: Delete ··

(prettier/prettier)


[error] 45-45: Replace }·,· with ·},

(prettier/prettier)


[error] 50-50: Replace 'Este·trabalho·já·foi·salvo·por·este·usuário.' with ⏎········'Este·trabalho·já·foi·salvo·por·este·usuário.',⏎······

(prettier/prettier)


[error] 52-52: Delete ··

(prettier/prettier)


[error] 59-59: Delete ·

(prettier/prettier)

src/database/migrations/1745261990419-migrations.ts

[error] 1-1: Replace "typeorm" with 'typeorm'

(prettier/prettier)


[error] 4-4: Replace ····name·=·'Migrations1745261990419' with ··name·=·'Migrations1745261990419';

(prettier/prettier)


[error] 6-6: Delete ··

(prettier/prettier)


[error] 7-7: Replace ········await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"); with ····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a",

(prettier/prettier)


[error] 8-8: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now()); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now(),

(prettier/prettier)


[error] 9-9: Insert );⏎

(prettier/prettier)


[error] 10-10: Delete ····

(prettier/prettier)


[error] 11-11: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·SET·NOT·NULL); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·SET·NOT·NULL,

(prettier/prettier)


[error] 12-12: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·CASCADE·ON·UPDATE·NO·ACTION); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·CASCADE·ON·UPDATE·NO·ACTION,

(prettier/prettier)


[error] 13-14: Replace }⏎ with );

(prettier/prettier)


[error] 15-15: Insert }⏎⏎

(prettier/prettier)


[error] 16-16: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a",

(prettier/prettier)


[error] 17-17: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·DROP·NOT·NULL); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·DROP·NOT·NULL,

(prettier/prettier)


[error] 18-18: Insert );⏎

(prettier/prettier)


[error] 19-19: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·"jobId"·character·varying·NOT·NULL); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·"jobId"·character·varying·NOT·NULL,

(prettier/prettier)


[error] 20-20: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·COLUMN·"expiresAt"); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·COLUMN·"expiresAt",

(prettier/prettier)


[error] 21-21: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·NO·ACTION·ON·UPDATE·NO·ACTION`` with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·NO·ACTION·ON·UPDATE·NO·ACTION`,⏎····`

(prettier/prettier)


[error] 22-23: Replace ··}⏎ with }

(prettier/prettier)

src/database/migrations/1745262789787-migrations.ts

[error] 1-1: Replace "typeorm" with 'typeorm'

(prettier/prettier)


[error] 4-4: Replace ····name·=·'Migrations1745262789787' with ··name·=·'Migrations1745262789787';

(prettier/prettier)


[error] 6-6: Delete ··

(prettier/prettier)


[error] 7-7: Replace ········const·hasExpiresAt·=·await·queryRunner.hasColumn('tb_saved_jobs',·'expiresAt'); with ····const·hasExpiresAt·=·await·queryRunner.hasColumn(⏎······'tb_saved_jobs',⏎······'expiresAt',

(prettier/prettier)


[error] 8-8: Insert );⏎

(prettier/prettier)


[error] 9-9: Replace ············await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now()); with ······await·queryRunner.query(⏎········ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now(),

(prettier/prettier)


[error] 10-11: Replace ··}⏎ with );

(prettier/prettier)


[error] 12-12: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"); with }⏎⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a",

(prettier/prettier)


[error] 13-13: Insert );⏎

(prettier/prettier)


[error] 14-14: Delete ····

(prettier/prettier)


[error] 15-15: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·SET·NOT·NULL); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·SET·NOT·NULL,

(prettier/prettier)


[error] 16-16: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·CASCADE·ON·UPDATE·NO·ACTION); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·CASCADE·ON·UPDATE·NO·ACTION,

(prettier/prettier)


[error] 17-18: Replace }⏎ with );

(prettier/prettier)


[error] 19-19: Insert }⏎⏎

(prettier/prettier)


[error] 20-20: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a",

(prettier/prettier)


[error] 21-21: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·DROP·NOT·NULL); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·DROP·NOT·NULL,

(prettier/prettier)


[error] 22-22: Insert );⏎

(prettier/prettier)


[error] 23-23: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·"jobId"·character·varying·NOT·NULL); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·"jobId"·character·varying·NOT·NULL,

(prettier/prettier)


[error] 24-24: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·COLUMN·"expiresAt"); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·COLUMN·"expiresAt",

(prettier/prettier)


[error] 25-25: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·NO·ACTION·ON·UPDATE·NO·ACTION); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·NO·ACTION·ON·UPDATE·NO·ACTION,

(prettier/prettier)


[error] 26-26: Replace ·· with ····);⏎

(prettier/prettier)

src/modules/auth/services/auth-login.service.ts

[error] 21-22: Delete

(prettier/prettier)

src/modules/savedjobs/savedjobs.controller.ts

[error] 1-1: Replace ·Body,·Controller,·Get,·HttpException,·HttpStatus,·Post,·Query,·UseGuards· with ⏎··Body,⏎··Controller,⏎··Get,⏎··HttpException,⏎··HttpStatus,⏎··Post,⏎··Query,⏎··UseGuards,⏎

(prettier/prettier)


[error] 25-27: Replace ⏎····@Body()·createSavedJobDto:·CreateSavedJobDto,⏎··):·Promise<any>·{· with @Body()·createSavedJobDto:·CreateSavedJobDto):·Promise<any>·{

(prettier/prettier)


[error] 37-38: Delete ⏎······

(prettier/prettier)


[error] 49-49: Replace ·summary:·'Obtenha·todos·os·trabalhos·salvos·com·filtros·e·paginação.' with ⏎····summary:·'Obtenha·todos·os·trabalhos·salvos·com·filtros·e·paginação.',⏎·

(prettier/prettier)

🔇 Additional comments (3)
src/database/entities/jobs.entity.ts (1)

18-18: Importação corretamente adicionada.

A importação da entidade SavedJobsEntity foi adicionada corretamente para estabelecer o relacionamento com Jobs.

src/database/entities/savedjobs.entity.ts (1)

1-10: Importações corretamente configuradas.

As importações necessárias do TypeORM e as entidades relacionadas (UsersEntity e JobsEntity) foram configuradas adequadamente.

src/modules/savedjobs/services/savedjobs.service.ts (1)

53-55: Bom controle de expiração implementado.

A implementação do controle de expiração das vagas salvas está correta, definindo uma data de expiração 7 dias após a data de salvamento. Isto está alinhado com a inclusão da coluna expiresAt na tabela.

Copy link
Copy Markdown
Contributor

@MikaelMelo1 MikaelMelo1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Algumas observações.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/modules/savedjobs/services/find-all-savedjobs.service.ts (1)

18-18: ⚠️ Potential issue

Corrigir mensagem de erro para refletir a operação sendo realizada.

A mensagem de erro atual menciona "Falha ao salvar os trabalhos salvos", mas esta função é para buscar/listar os jobs salvos, não para salvá-los.

- throw new InternalServerErrorException(`Falha ao salvar os trabalhos salvos: ${error.message}`);
+ throw new InternalServerErrorException(`Falha ao buscar os jobs salvos: ${error.message}`);
🧰 Tools
🪛 ESLint

[error] 18-18: Replace ``Falha·ao·salvar·os·trabalhos·salvos:·${error.message});␍ with `⏎········`Falha·ao·salvar·os·trabalhos·salvos:·${error.message}`,⏎······);`

(prettier/prettier)

🧹 Nitpick comments (2)
src/modules/savedjobs/services/find-all-savedjobs.service.ts (2)

1-5: Padronizar uso de aspas simples nos imports.

Os imports estão usando aspas duplas, mas o padrão do projeto parece ser usar aspas simples conforme indicado pela análise estática.

- import { Injectable, InternalServerErrorException } from "@nestjs/common";
- import { SavedJobsEntity } from "src/database/entities/savedjobs.entity";
- import { PageDto, PageOptionsDto } from "src/shared/pagination";
- import { SavedJobsRepository } from "../repository/savedjobs.repository";
- import { GetAllSavedJobsDto } from "../dtos/get-all-savedjobs.dto";
+ import { Injectable, InternalServerErrorException } from '@nestjs/common';
+ import { SavedJobsEntity } from 'src/database/entities/savedjobs.entity';
+ import { PageDto, PageOptionsDto } from 'src/shared/pagination';
+ import { SavedJobsRepository } from '../repository/savedjobs.repository';
+ import { GetAllSavedJobsDto } from '../dtos/get-all-savedjobs.dto';
🧰 Tools
🪛 ESLint

[error] 1-1: Replace "@nestjs/common";␍ with '@nestjs/common';

(prettier/prettier)


[error] 2-2: Replace "src/database/entities/savedjobs.entity";␍ with 'src/database/entities/savedjobs.entity';

(prettier/prettier)


[error] 3-3: Replace "src/shared/pagination";␍ with 'src/shared/pagination';

(prettier/prettier)


[error] 4-4: Replace "../repository/savedjobs.repository";␍ with '../repository/savedjobs.repository';

(prettier/prettier)


[error] 5-5: Replace "../dtos/get-all-savedjobs.dto";␍ with '../dtos/get-all-savedjobs.dto';

(prettier/prettier)


16-16: Formatar parâmetros em várias linhas para melhor legibilidade.

Para manter consistência com o estilo do projeto, considere formatar os parâmetros em múltiplas linhas.

- return await this.savedJobsRepository.getAllSavedJobs(pageOptionsDto, filters);
+ return await this.savedJobsRepository.getAllSavedJobs(
+   pageOptionsDto,
+   filters,
+ );
🧰 Tools
🪛 ESLint

[error] 16-16: Replace pageOptionsDto,·filters);␍ with ⏎········pageOptionsDto,⏎········filters,⏎······);

(prettier/prettier)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d78ccf5 and 00b10b6.

📒 Files selected for processing (1)
  • src/modules/savedjobs/services/find-all-savedjobs.service.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/modules/savedjobs/services/find-all-savedjobs.service.ts (4)
src/modules/savedjobs/repository/savedjobs.repository.ts (1)
  • Injectable (8-44)
src/shared/pagination/pageOptions.dto.ts (1)
  • PageOptionsDto (6-42)
src/modules/savedjobs/dtos/get-all-savedjobs.dto.ts (1)
  • GetAllSavedJobsDto (4-22)
src/shared/pagination/page.dto.ts (1)
  • PageDto (4-14)
🪛 ESLint
src/modules/savedjobs/services/find-all-savedjobs.service.ts

[error] 1-1: Replace "@nestjs/common";␍ with '@nestjs/common';

(prettier/prettier)


[error] 2-2: Replace "src/database/entities/savedjobs.entity";␍ with 'src/database/entities/savedjobs.entity';

(prettier/prettier)


[error] 3-3: Replace "src/shared/pagination";␍ with 'src/shared/pagination';

(prettier/prettier)


[error] 4-4: Replace "../repository/savedjobs.repository";␍ with '../repository/savedjobs.repository';

(prettier/prettier)


[error] 5-5: Replace "../dtos/get-all-savedjobs.dto";␍ with '../dtos/get-all-savedjobs.dto';

(prettier/prettier)


[error] 6-6: Delete

(prettier/prettier)


[error] 7-7: Delete

(prettier/prettier)


[error] 8-8: Delete

(prettier/prettier)


[error] 9-9: Delete

(prettier/prettier)


[error] 10-10: Delete

(prettier/prettier)


[error] 11-11: Delete

(prettier/prettier)


[error] 12-12: Delete

(prettier/prettier)


[error] 13-13: Delete

(prettier/prettier)


[error] 14-14: Delete

(prettier/prettier)


[error] 15-15: Delete

(prettier/prettier)


[error] 16-16: Replace pageOptionsDto,·filters);␍ with ⏎········pageOptionsDto,⏎········filters,⏎······);

(prettier/prettier)


[error] 17-17: Delete

(prettier/prettier)


[error] 18-18: Replace ``Falha·ao·salvar·os·trabalhos·salvos:·${error.message});␍ with `⏎········`Falha·ao·salvar·os·trabalhos·salvos:·${error.message}`,⏎······);`

(prettier/prettier)


[error] 19-19: Delete

(prettier/prettier)


[error] 20-20: Delete

(prettier/prettier)


[error] 21-21: Insert

(prettier/prettier)

🔇 Additional comments (1)
src/modules/savedjobs/services/find-all-savedjobs.service.ts (1)

1-21: Arquitetura bem implementada para listar jobs salvos com paginação e filtros.

O serviço está bem estruturado seguindo os padrões do NestJS com injeção de dependência, tratamento de erros e tipos bem definidos. A implementação utiliza corretamente os DTOs de paginação e filtros.

🧰 Tools
🪛 ESLint

[error] 1-1: Replace "@nestjs/common";␍ with '@nestjs/common';

(prettier/prettier)


[error] 2-2: Replace "src/database/entities/savedjobs.entity";␍ with 'src/database/entities/savedjobs.entity';

(prettier/prettier)


[error] 3-3: Replace "src/shared/pagination";␍ with 'src/shared/pagination';

(prettier/prettier)


[error] 4-4: Replace "../repository/savedjobs.repository";␍ with '../repository/savedjobs.repository';

(prettier/prettier)


[error] 5-5: Replace "../dtos/get-all-savedjobs.dto";␍ with '../dtos/get-all-savedjobs.dto';

(prettier/prettier)


[error] 6-6: Delete

(prettier/prettier)


[error] 7-7: Delete

(prettier/prettier)


[error] 8-8: Delete

(prettier/prettier)


[error] 9-9: Delete

(prettier/prettier)


[error] 10-10: Delete

(prettier/prettier)


[error] 11-11: Delete

(prettier/prettier)


[error] 12-12: Delete

(prettier/prettier)


[error] 13-13: Delete

(prettier/prettier)


[error] 14-14: Delete

(prettier/prettier)


[error] 15-15: Delete

(prettier/prettier)


[error] 16-16: Replace pageOptionsDto,·filters);␍ with ⏎········pageOptionsDto,⏎········filters,⏎······);

(prettier/prettier)


[error] 17-17: Delete

(prettier/prettier)


[error] 18-18: Replace ``Falha·ao·salvar·os·trabalhos·salvos:·${error.message});␍ with `⏎········`Falha·ao·salvar·os·trabalhos·salvos:·${error.message}`,⏎······);`

(prettier/prettier)


[error] 19-19: Delete

(prettier/prettier)


[error] 20-20: Delete

(prettier/prettier)


[error] 21-21: Insert

(prettier/prettier)

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/shared/Swagger/decorators/savedjobs/create-savedjobs.swagger.decorator.ts (1)

8-36: Decorador de Swagger implementado corretamente com todas as respostas necessárias.

O decorador implementa corretamente todas as possíveis respostas para a operação de salvar uma vaga:

  • Sucesso (201): Retorna a entidade SavedJobsEntity
  • Requisição inválida (400): Usa o tipo correto BadRequestSwagger
  • Conflito (409): Usa o novo tipo ConflictSwagger para indicar que a vaga já foi salva
  • Não encontrado (404): Usa o tipo correto NotFoundSwagger

As correções solicitadas nos comentários anteriores foram implementadas corretamente, como o uso de SavedJobsEntity para o tipo de resposta de sucesso e o uso de ConflictSwagger para o tipo de resposta de conflito.

No entanto, há alguns problemas de formatação que precisam ser corrigidos para seguir o padrão de estilo do projeto. Recomendo usar uma ferramenta de formatação automática como o Prettier.

Além disso, sugiro considerar a adição de uma descrição mais detalhada na documentação para ajudar outros desenvolvedores:

   ApiOperation({
     summary: 'Salvar uma vaga',
-    description: 'Cria um novo registro de vaga salva para o usuário autenticado. Requer dados obrigatórios no corpo da requisição.',
+    description: 'Cria um novo registro de vaga salva para o usuário autenticado. Requer dados obrigatórios no corpo da requisição, incluindo o ID da vaga a ser salva.',
   }),
🧰 Tools
🪛 ESLint

[error] 8-8: Delete

(prettier/prettier)


[error] 9-9: Delete

(prettier/prettier)


[error] 10-10: Delete

(prettier/prettier)


[error] 11-11: Delete

(prettier/prettier)


[error] 12-12: Delete

(prettier/prettier)


[error] 13-13: Replace ·'Cria·um·novo·registro·de·vaga·salva·para·o·usuário·autenticado.·Requer·dados·obrigatórios·no·corpo·da·requisição.',␍ with ⏎········'Cria·um·novo·registro·de·vaga·salva·para·o·usuário·autenticado.·Requer·dados·obrigatórios·no·corpo·da·requisição.',

(prettier/prettier)


[error] 14-14: Delete

(prettier/prettier)


[error] 15-15: Delete

(prettier/prettier)


[error] 16-16: Delete

(prettier/prettier)


[error] 17-17: Replace ·'Vaga·salva·com·sucesso.·Retorna·os·dados·do·registro·criado.',␍ with ⏎········'Vaga·salva·com·sucesso.·Retorna·os·dados·do·registro·criado.',

(prettier/prettier)


[error] 18-18: Delete

(prettier/prettier)


[error] 19-19: Delete

(prettier/prettier)


[error] 20-20: Delete

(prettier/prettier)


[error] 21-21: Delete

(prettier/prettier)


[error] 22-22: Replace ·'Requisição·inválida.·Verifique·os·campos·enviados·no·corpo·da·requisição.',␍ with ⏎········'Requisição·inválida.·Verifique·os·campos·enviados·no·corpo·da·requisição.',

(prettier/prettier)


[error] 23-23: Delete

(prettier/prettier)


[error] 24-24: Delete

(prettier/prettier)


[error] 25-25: Delete

(prettier/prettier)


[error] 26-26: Delete

(prettier/prettier)


[error] 27-27: Delete

(prettier/prettier)


[error] 28-28: Delete

(prettier/prettier)


[error] 29-29: Delete

(prettier/prettier)


[error] 30-30: Delete

(prettier/prettier)


[error] 31-31: Delete

(prettier/prettier)


[error] 32-32: Delete

(prettier/prettier)


[error] 33-33: Delete

(prettier/prettier)


[error] 34-34: Delete

(prettier/prettier)


[error] 35-35: Delete

(prettier/prettier)


[error] 36-36: Insert

(prettier/prettier)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00b10b6 and d0a1052.

📒 Files selected for processing (2)
  • src/shared/Swagger/conflict.swagger.ts (1 hunks)
  • src/shared/Swagger/decorators/savedjobs/create-savedjobs.swagger.decorator.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/shared/Swagger/decorators/savedjobs/create-savedjobs.swagger.decorator.ts (3)
src/shared/Swagger/bad-request.swagger.ts (1)
  • BadRequestSwagger (2-5)
src/shared/Swagger/conflict.swagger.ts (1)
  • ConflictSwagger (3-6)
src/shared/Swagger/not-found.swagger.ts (1)
  • NotFoundSwagger (2-5)
🪛 ESLint
src/shared/Swagger/conflict.swagger.ts

[error] 1-1: Replace "@nestjs/swagger";␍ with '@nestjs/swagger';

(prettier/prettier)


[error] 2-2: Delete

(prettier/prettier)


[error] 3-3: Delete

(prettier/prettier)


[error] 4-4: Replace ····@ApiProperty()␍ with ··@ApiProperty()

(prettier/prettier)


[error] 5-5: Replace ····message:·string;␍ with ··message:·string;

(prettier/prettier)


[error] 6-6: Replace ··} with }⏎

(prettier/prettier)

src/shared/Swagger/decorators/savedjobs/create-savedjobs.swagger.decorator.ts

[error] 1-1: Replace "@nestjs/common";␍ with '@nestjs/common';

(prettier/prettier)


[error] 2-2: Replace "@nestjs/swagger";␍ with '@nestjs/swagger';

(prettier/prettier)


[error] 3-3: Replace "../../not-found.swagger";␍ with '../../not-found.swagger';

(prettier/prettier)


[error] 4-4: Replace "../../bad-request.swagger";␍ with '../../bad-request.swagger';

(prettier/prettier)


[error] 5-5: Replace "src/database/entities/savedjobs.entity";␍ with 'src/database/entities/savedjobs.entity';

(prettier/prettier)


[error] 6-6: Replace "../../conflict.swagger";␍ with '../../conflict.swagger';

(prettier/prettier)


[error] 7-7: Delete

(prettier/prettier)


[error] 8-8: Delete

(prettier/prettier)


[error] 9-9: Delete

(prettier/prettier)


[error] 10-10: Delete

(prettier/prettier)


[error] 11-11: Delete

(prettier/prettier)


[error] 12-12: Delete

(prettier/prettier)


[error] 13-13: Replace ·'Cria·um·novo·registro·de·vaga·salva·para·o·usuário·autenticado.·Requer·dados·obrigatórios·no·corpo·da·requisição.',␍ with ⏎········'Cria·um·novo·registro·de·vaga·salva·para·o·usuário·autenticado.·Requer·dados·obrigatórios·no·corpo·da·requisição.',

(prettier/prettier)


[error] 14-14: Delete

(prettier/prettier)


[error] 15-15: Delete

(prettier/prettier)


[error] 16-16: Delete

(prettier/prettier)


[error] 17-17: Replace ·'Vaga·salva·com·sucesso.·Retorna·os·dados·do·registro·criado.',␍ with ⏎········'Vaga·salva·com·sucesso.·Retorna·os·dados·do·registro·criado.',

(prettier/prettier)


[error] 18-18: Delete

(prettier/prettier)


[error] 19-19: Delete

(prettier/prettier)


[error] 20-20: Delete

(prettier/prettier)


[error] 21-21: Delete

(prettier/prettier)


[error] 22-22: Replace ·'Requisição·inválida.·Verifique·os·campos·enviados·no·corpo·da·requisição.',␍ with ⏎········'Requisição·inválida.·Verifique·os·campos·enviados·no·corpo·da·requisição.',

(prettier/prettier)


[error] 23-23: Delete

(prettier/prettier)


[error] 24-24: Delete

(prettier/prettier)


[error] 25-25: Delete

(prettier/prettier)


[error] 26-26: Delete

(prettier/prettier)


[error] 27-27: Delete

(prettier/prettier)


[error] 28-28: Delete

(prettier/prettier)


[error] 29-29: Delete

(prettier/prettier)


[error] 30-30: Delete

(prettier/prettier)


[error] 31-31: Delete

(prettier/prettier)


[error] 32-32: Delete

(prettier/prettier)


[error] 33-33: Delete

(prettier/prettier)


[error] 34-34: Delete

(prettier/prettier)


[error] 35-35: Delete

(prettier/prettier)


[error] 36-36: Insert

(prettier/prettier)

🔇 Additional comments (2)
src/shared/Swagger/conflict.swagger.ts (1)

1-6: Classe de resposta para conflitos implementada corretamente.

A classe ConflictSwagger segue o mesmo padrão que as outras classes de resposta de erro no projeto, como NotFoundSwagger e BadRequestSwagger, mantendo a consistência do código.

No entanto, há alguns problemas de formatação que precisam ser corrigidos para seguir o padrão de estilo do projeto:

-import { ApiProperty } from "@nestjs/swagger";
+import { ApiProperty } from '@nestjs/swagger';

 export class ConflictSwagger {
-    @ApiProperty()
-    message: string;
-  }
+  @ApiProperty()
+  message: string;
+}
🧰 Tools
🪛 ESLint

[error] 1-1: Replace "@nestjs/swagger";␍ with '@nestjs/swagger';

(prettier/prettier)


[error] 2-2: Delete

(prettier/prettier)


[error] 3-3: Delete

(prettier/prettier)


[error] 4-4: Replace ····@ApiProperty()␍ with ··@ApiProperty()

(prettier/prettier)


[error] 5-5: Replace ····message:·string;␍ with ··message:·string;

(prettier/prettier)


[error] 6-6: Replace ··} with }⏎

(prettier/prettier)

src/shared/Swagger/decorators/savedjobs/create-savedjobs.swagger.decorator.ts (1)

1-7: Importações corretas e completas.

As importações estão corretamente definidas, incluindo a nova classe ConflictSwagger que foi adicionada.

Há alguns problemas de formatação com aspas:

-import { applyDecorators, HttpStatus } from "@nestjs/common";
-import { ApiBearerAuth, ApiOperation, ApiResponse } from "@nestjs/swagger";
-import { NotFoundSwagger } from "../../not-found.swagger";
-import { BadRequestSwagger } from "../../bad-request.swagger";
-import { SavedJobsEntity } from "src/database/entities/savedjobs.entity";
-import { ConflictSwagger } from "../../conflict.swagger";
+import { applyDecorators, HttpStatus } from '@nestjs/common';
+import { ApiBearerAuth, ApiOperation, ApiResponse } from '@nestjs/swagger';
+import { NotFoundSwagger } from '../../not-found.swagger';
+import { BadRequestSwagger } from '../../bad-request.swagger';
+import { SavedJobsEntity } from 'src/database/entities/savedjobs.entity';
+import { ConflictSwagger } from '../../conflict.swagger';
🧰 Tools
🪛 ESLint

[error] 1-1: Replace "@nestjs/common";␍ with '@nestjs/common';

(prettier/prettier)


[error] 2-2: Replace "@nestjs/swagger";␍ with '@nestjs/swagger';

(prettier/prettier)


[error] 3-3: Replace "../../not-found.swagger";␍ with '../../not-found.swagger';

(prettier/prettier)


[error] 4-4: Replace "../../bad-request.swagger";␍ with '../../bad-request.swagger';

(prettier/prettier)


[error] 5-5: Replace "src/database/entities/savedjobs.entity";␍ with 'src/database/entities/savedjobs.entity';

(prettier/prettier)


[error] 6-6: Replace "../../conflict.swagger";␍ with '../../conflict.swagger';

(prettier/prettier)


[error] 7-7: Delete

(prettier/prettier)

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
README.md (1)

355-355: ⚠️ Potential issue

Corrija o link quebrado na seção de Feedback.

O link na seção de Feedback aponta para uma âncora inexistente (#contribuição).

-Se você tiver algum feedback, por favor nos deixe saber por meio do nosso fazendo uma [contribuição](#contribuição).
+Se você tiver algum feedback, por favor nos deixe saber por meio do nosso fazendo uma [contribuição](#como_contribuir).
♻️ Duplicate comments (1)
src/modules/savedjobs/savedjobs.controller.ts (1)

80-87: 🛠️ Refactor suggestion

Utilize o usuário autenticado para filtrar as vagas salvas.

O endpoint está protegido com AuthGuard(), mas não aproveita as informações do usuário autenticado para filtrar as vagas salvas.

Utilize o decorator @GetUser() para obter o usuário autenticado e filtre apenas as vagas salvas desse usuário:

  async getAllSavedJobs(
    @Query() pageOptionsDto: PageOptionsDto,
    @Query() query: GetAllSavedJobsDto,
+   @GetUser() user: UsersEntity,
  ): Promise<PageDto<SavedJobsEntity>> {
    try {
-     const savedJobs = await this.findAllSavedJobsService.getAllSavedJobs(pageOptionsDto, query);
+     const savedJobs = await this.findAllSavedJobsService.getAllSavedJobs(
+       pageOptionsDto, 
+       { ...query, userId: user.id }
+     );
      return savedJobs;

Isso garante que um usuário só pode ver suas próprias vagas salvas, melhorando a segurança da API.

🧰 Tools
🪛 ESLint

[error] 85-85: Replace pageOptionsDto,·query with ⏎········pageOptionsDto,⏎········query,⏎······

(prettier/prettier)

🧹 Nitpick comments (4)
src/modules/savedjobs/savedjobs.controller.ts (1)

43-43: Defina um tipo de retorno específico para melhorar a tipagem.

O método saveJob está usando Promise<any> como tipo de retorno, o que dificulta a compreensão da API.

Defina um tipo específico para melhorar a tipagem e documentação:

- ): Promise<any> {
+ ): Promise<{
+   message: string;
+   statusCode: number;
+   savedJob: SavedJobsEntity;
+ }> {

Não esqueça de adicionar o import caso necessário:

import { SavedJobsEntity } from '../../database/entities/savedjobs.entity';
🧰 Tools
🪛 ESLint

[error] 41-43: Replace ⏎····@Body()·createSavedJobDto:·CreateSavedJobDto,⏎·· with @Body()·createSavedJobDto:·CreateSavedJobDto

(prettier/prettier)

README.md (3)

9-9: Adicione texto alternativo (alt text) à imagem do banner.

A imagem do banner não tem um texto alternativo adequado, o que prejudica a acessibilidade.

-<img width="100%" src="https://capsule-render.vercel.app/api?type=waving&width=100%&color=2088f2&fontColor=ffffff&height=300&section=header&text=Sou%20Junior&fontSize=90&animation=fadeIn&fontAlignY=38&desc=Projeto%20Opensource%20para%20melhorar%20o%20match%20entre%20profissionais%20Juniors%20e%20Empresas!&descAlignY=61&descAlign=52" /> 
+<img width="100%" src="https://capsule-render.vercel.app/api?type=waving&width=100%&color=2088f2&fontColor=ffffff&height=300&section=header&text=Sou%20Junior&fontSize=90&animation=fadeIn&fontAlignY=38&desc=Projeto%20Opensource%20para%20melhorar%20o%20match%20entre%20profissionais%20Juniors%20e%20Empresas!&descAlignY=61&descAlign=52" alt="Banner do Projeto Sou Junior" /> 
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

9-9: Images should have alternate text (alt text)
null

(MD045, no-alt-text)


11-11: Adicione texto alternativo (alt text) ao contador de visitantes.

A imagem do contador de visitantes não tem um texto alternativo adequado.

-<p align="center">Visitantes: <img src="https://profile-counter.glitch.me/SouJunior/count.svg" /></p>
+<p align="center">Visitantes: <img src="https://profile-counter.glitch.me/SouJunior/count.svg" alt="Contador de visitantes" /></p>
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

11-11: Images should have alternate text (alt text)
null

(MD045, no-alt-text)


28-28: Corrija a pontuação no cabeçalho.

O cabeçalho "Pré-requisitos:" termina com dois pontos, o que não segue as melhores práticas de Markdown.

-### Pré-requisitos:
+### Pré-requisitos
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

28-28: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7fa3626 and e8ba139.

📒 Files selected for processing (2)
  • README.md (5 hunks)
  • src/modules/savedjobs/savedjobs.controller.ts (1 hunks)
🧰 Additional context used
🪛 ESLint
src/modules/savedjobs/savedjobs.controller.ts

[error] 1-1: Replace ·Body,·Controller,·Get,·HttpException,·HttpStatus,·Post,·Query,·UseGuards,·UsePipes,·ValidationPipe· with ⏎··Body,⏎··Controller,⏎··Get,⏎··HttpException,⏎··HttpStatus,⏎··Post,⏎··Query,⏎··UseGuards,⏎··UsePipes,⏎··ValidationPipe,⏎

(prettier/prettier)


[error] 2-2: Replace ·ApiBearerAuth,·ApiOperation,·ApiTags,·ApiResponse· with ⏎··ApiBearerAuth,⏎··ApiOperation,⏎··ApiTags,⏎··ApiResponse,⏎

(prettier/prettier)


[error] 23-23: Delete ··

(prettier/prettier)


[error] 33-33: Replace ·/*·exemplo·do·objeto·salvo·*/ with ⏎··········/*·exemplo·do·objeto·salvo·*/⏎·······

(prettier/prettier)


[error] 41-43: Replace ⏎····@Body()·createSavedJobDto:·CreateSavedJobDto,⏎·· with @Body()·createSavedJobDto:·CreateSavedJobDto

(prettier/prettier)


[error] 63-63: Replace ·summary:·'Obtenha·todos·os·trabalhos·salvos·com·filtros·e·paginação.' with ⏎····summary:·'Obtenha·todos·os·trabalhos·salvos·com·filtros·e·paginação.',⏎·

(prettier/prettier)


[error] 69-69: Replace /*·exemplo·de·lista·de·jobs·*/ with ⏎··········/*·exemplo·de·lista·de·jobs·*/⏎········

(prettier/prettier)


[error] 85-85: Replace pageOptionsDto,·query with ⏎········pageOptionsDto,⏎········query,⏎······

(prettier/prettier)

🪛 markdownlint-cli2 (0.17.2)
README.md

9-9: Images should have alternate text (alt text)
null

(MD045, no-alt-text)


11-11: Images should have alternate text (alt text)
null

(MD045, no-alt-text)


28-28: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

🪛 LanguageTool
README.md

[uncategorized] ~139-~139: Esta locução deve ser separada por vírgulas.
Context: ...ash CREATE DATABASE "vagas-api"; ``` ✅ Agora sim, tudo certo? Siga com as migrations! `...

(VERB_COMMA_CONJUNCTION)

🔇 Additional comments (4)
README.md (4)

70-81: Excelente adição de instruções para configuração do arquivo .env!

A inclusão detalhada das variáveis de ambiente necessárias e as instruções de segurança sobre não compartilhar o arquivo são muito úteis para novos desenvolvedores.


116-143: Ótima seção de solução de problemas!

A adição da seção de troubleshooting é muito útil, especialmente para problemas comuns de autenticação e banco de dados que os novos desenvolvedores podem enfrentar.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~139-~139: Esta locução deve ser separada por vírgulas.
Context: ...ash CREATE DATABASE "vagas-api"; ``` ✅ Agora sim, tudo certo? Siga com as migrations! `...

(VERB_COMMA_CONJUNCTION)


230-243: Excelente adição da seção "Como contribuir".

A nova seção fornece instruções claras sobre como os desenvolvedores podem contribuir para o projeto, abordando desde a criação de issues até o envio de PRs.


248-348: Organização exemplar da seção de equipe.

A reorganização da equipe em tabelas estruturadas por função torna o reconhecimento dos contribuidores muito mais claro e profissional.

Comment on lines +80 to +83
async getAllSavedJobs(
@Query() pageOptionsDto: PageOptionsDto,
@Query() query: GetAllSavedJobsDto,
) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Defina um tipo de retorno específico para o método getAllSavedJobs.

O método getAllSavedJobs não tem um tipo de retorno explícito, o que dificulta a compreensão da API.

  async getAllSavedJobs(
    @Query() pageOptionsDto: PageOptionsDto,
    @Query() query: GetAllSavedJobsDto,
-  ) {
+  ): Promise<PageDto<SavedJobsEntity>> {

Não esqueça de adicionar a importação:

import { PageDto } from 'src/shared/pagination';
import { SavedJobsEntity } from '../../database/entities/savedjobs.entity';

Comment on lines +41 to +43
async saveJob(
@Body() createSavedJobDto: CreateSavedJobDto,
): Promise<any> {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Falta usar o decorator @getuser() para obter o usuário autenticado.

O endpoint está protegido com AuthGuard(), mas não está utilizando as informações do usuário autenticado. Em vez de receber o userId no DTO, é mais seguro obtê-lo diretamente do token.

Aplique a seguinte alteração:

  async saveJob(
    @Body() createSavedJobDto: CreateSavedJobDto,
+   @GetUser() user: UsersEntity,
  ): Promise<any> {
    try {
-     const savedJob = await this.savedJobsService.saveJob(createSavedJobDto);
+     const savedJob = await this.savedJobsService.saveJob({
+       ...createSavedJobDto,
+       userId: user.id
+     });
      return {
        message: 'Sua vaga foi salva com sucesso!',
        statusCode: HttpStatus.CREATED,
        savedJob: savedJob,
      };

Não esqueça de adicionar as importações:

import { GetUser } from '../auth/get-user.decorator';
import { UsersEntity } from '../../database/entities/users.entity';

E atualize o DTO para tornar o userId opcional:

export class CreateSavedJobDto {
- @IsUUID()
- @IsNotEmpty()
+ @IsOptional()
+ @IsUUID()
  userId: string;

  @IsUUID()
  @IsNotEmpty()
  jobId: string;
}
🧰 Tools
🪛 ESLint

[error] 41-43: Replace ⏎····@Body()·createSavedJobDto:·CreateSavedJobDto,⏎·· with @Body()·createSavedJobDto:·CreateSavedJobDto

(prettier/prettier)

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/database/entities/jobs.entity.ts (1)

143-145: Correção de formatação necessária na definição do relacionamento.

O relacionamento com SavedJobsEntity está corretamente implementado, mas existem problemas de formatação que devem ser corrigidos:

  1. Use aspas simples em vez de aspas duplas (padrão do projeto)
  2. Remova a linha extra após a definição de savedJobs
  @OneToMany(() => SavedJobsEntity, (savedJob) => savedJob.job)
- @JoinColumn({name: "jobId"})
+ @JoinColumn({ name: 'jobId' })
  savedJobs: SavedJobsEntity[];
-
🧰 Tools
🪛 ESLint

[error] 144-144: Replace name:·"jobId" with ·name:·'jobId'·

(prettier/prettier)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e8ba139 and dddc8c7.

📒 Files selected for processing (2)
  • src/database/entities/jobs.entity.ts (3 hunks)
  • src/database/entities/savedjobs.entity.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/database/entities/savedjobs.entity.ts
🧰 Additional context used
🪛 ESLint
src/database/entities/jobs.entity.ts

[error] 144-144: Replace name:·"jobId" with ·name:·'jobId'·

(prettier/prettier)


[error] 145-146: Delete

(prettier/prettier)

🔇 Additional comments (3)
src/database/entities/jobs.entity.ts (3)

18-20: Importações adicionadas para suportar funcionalidade de vagas salvas e validação de status.

As importações adicionadas estão corretas e necessárias para as novas funcionalidades. A importação do SavedJobsEntity permite a relação com a nova entidade, enquanto StatusEnum e IsEnum possibilitam a validação adequada do campo de status.


120-122: Implementação adequada do enum para status com validação.

Excelente implementação do campo status utilizando enum e validação com class-validator. A alteração melhora a tipagem e garante a integridade dos dados através da validação com @IsEnum.


144-144: Verificar necessidade do @joincolumn no OneToMany.

O decorador @JoinColumn geralmente não é necessário em relacionamentos @OneToMany, pois a coluna de junção é definida no lado @ManyToOne da relação. O TypeORM automaticamente estabelece a relação inversa.

Verifique na entidade SavedJobsEntity se já existe um @ManyToOne com @JoinColumn apontando para o JobsEntity.

🧰 Tools
🪛 ESLint

[error] 144-144: Replace name:·"jobId" with ·name:·'jobId'·

(prettier/prettier)

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (2)
src/app.module.ts (2)

52-52: A arquitetura do módulo parece inconsistente.

O SavedJobsEntity e JobsEntity estão sendo registrados no TypeOrmModule.forFeature do módulo principal, enquanto o ideal seria registrá-los apenas no SavedJobsModule. Isso está criando uma dependência desnecessária no módulo principal.

Considere mover esta configuração para o módulo específico em vez de mantê-la no AppModule:

-    TypeOrmModule.forFeature([UsersEntity, SavedJobsEntity, JobsEntity]),
+    TypeOrmModule.forFeature([UsersEntity]),

57-58: Remova o controller e o serviço do AppModule.

O SavedJobsController e o SavedJobsService não deveriam estar declarados no módulo principal, pois isso viola o princípio de modularidade do NestJS. Eles deveriam estar apenas no SavedJobsModule.

-  controllers: [AppController, SavedJobsController],
-  providers: [AppService, UserRepository, SavedJobsService],
+  controllers: [AppController],
+  providers: [AppService, UserRepository],
🧹 Nitpick comments (10)
src/database/migrations/1746107506888-migrations.ts (1)

9-9: Considere usar CASCADE ou SET NULL para a foreign key.

A restrição de chave estrangeira está configurada com ON DELETE NO ACTION ON UPDATE NO ACTION, o que significa que se uma vaga for deletada, os registros de vagas salvas permanecerão no banco. Isso pode causar referências inválidas.

Considere usar ON DELETE CASCADE para excluir automaticamente os registros de vagas salvas quando uma vaga for excluída, ou ON DELETE SET NULL se quiser manter um histórico de vagas salvas.

-        await queryRunner.query(`ALTER TABLE "tb_saved_jobs" ADD CONSTRAINT "FK_9bbd9a1f3bb4942f0471816b111" FOREIGN KEY ("jobId") REFERENCES "tb_jobs"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
+        await queryRunner.query(`ALTER TABLE "tb_saved_jobs" ADD CONSTRAINT "FK_9bbd9a1f3bb4942f0471816b111" FOREIGN KEY ("jobId") REFERENCES "tb_jobs"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
🧰 Tools
🪛 ESLint

[error] 9-9: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_9bbd9a1f3bb4942f0471816b111"·FOREIGN·KEY·("jobId")·REFERENCES·"tb_jobs"("id")·ON·DELETE·NO·ACTION·ON·UPDATE·NO·ACTION); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_9bbd9a1f3bb4942f0471816b111"·FOREIGN·KEY·("jobId")·REFERENCES·"tb_jobs"("id")·ON·DELETE·NO·ACTION·ON·UPDATE·NO·ACTION,

(prettier/prettier)

src/modules/savedjobs/savedjobs.module.ts (3)

3-3: Corrija o caminho de importação redundante.

A importação contém múltiplos ./././. que são redundantes e podem causar confusão. Simplifique para um único ./.

-import { SavedJobsService } from '././././services/savedjobs.service';
+import { SavedJobsService } from './services/savedjobs.service';

19-20: Adicione vírgula após o último item do array.

Falta uma vírgula após SavedJobsCleanerService para manter a consistência e facilitar futuras adições ao array.

    SavedJobsService,
    FindAllSavedJobsService,
    SavedJobsRepository, 
-   SavedJobsCleanerService
+   SavedJobsCleanerService,
🧰 Tools
🪛 ESLint

[error] 19-19: Insert ,

(prettier/prettier)


25-26: Adicione vírgula após o último item do array.

Falta uma vírgula após SavedJobsCleanerService para manter a consistência e facilitar futuras adições ao array.

    SavedJobsService,
    FindAllSavedJobsService,
    SavedJobsRepository, 
-   SavedJobsCleanerService
+   SavedJobsCleanerService,
🧰 Tools
🪛 ESLint

[error] 25-25: Insert ,

(prettier/prettier)

src/modules/savedjobs/services/savedjobs-cleaner.service.ts (1)

1-5: Padronize o estilo de aspas nos imports.

Os imports estão usando aspas duplas, enquanto o padrão do projeto parece ser aspas simples. Mantenha a consistência com o restante do código.

-import { Injectable, Logger } from "@nestjs/common";
-import { Cron, CronExpression } from "@nestjs/schedule";
-import { InjectRepository } from "@nestjs/typeorm";
-import { SavedJobsEntity } from "src/database/entities/savedjobs.entity";
-import { LessThan, Repository } from "typeorm";
+import { Injectable, Logger } from '@nestjs/common';
+import { Cron, CronExpression } from '@nestjs/schedule';
+import { InjectRepository } from '@nestjs/typeorm';
+import { SavedJobsEntity } from 'src/database/entities/savedjobs.entity';
+import { LessThan, Repository } from 'typeorm';
🧰 Tools
🪛 ESLint

[error] 1-1: Replace "@nestjs/common";␍ with '@nestjs/common';

(prettier/prettier)


[error] 2-2: Replace "@nestjs/schedule";␍ with '@nestjs/schedule';

(prettier/prettier)


[error] 3-3: Replace "@nestjs/typeorm";␍ with '@nestjs/typeorm';

(prettier/prettier)


[error] 4-4: Replace "src/database/entities/savedjobs.entity";␍ with 'src/database/entities/savedjobs.entity';

(prettier/prettier)


[error] 5-5: Replace "typeorm";␍ with 'typeorm';

(prettier/prettier)

src/app.module.ts (1)

21-27: Adicione ponto e vírgula nos imports.

Adicione ponto e vírgula após as declarações de importação para manter a consistência.

-import { SavedJobsEntity } from './database/entities/savedjobs.entity'
+import { SavedJobsEntity } from './database/entities/savedjobs.entity';
-import { SavedJobsController } from './modules/savedjobs/savedjobs.controller'
+import { SavedJobsController } from './modules/savedjobs/savedjobs.controller';
-import { JobsEntity } from './database/entities/jobs.entity'; 
+import { JobsEntity } from './database/entities/jobs.entity';
-import { SavedJobsModule } from './modules/savedjobs/savedjobs.module'
+import { SavedJobsModule } from './modules/savedjobs/savedjobs.module';
🧰 Tools
🪛 ESLint

[error] 21-21: Insert ;

(prettier/prettier)


[error] 25-25: Insert ;

(prettier/prettier)


[error] 26-26: Delete ·

(prettier/prettier)


[error] 27-27: Insert ;

(prettier/prettier)

src/modules/savedjobs/services/savedjobs.service.ts (2)

53-56: Timezone consistente para datas

new Date() depende do timezone da instância de aplicação. Para manter coerência com o campo default do banco (que usa now() em UTC), prefira:

const savedAt = new Date(Date.now());

ou gerenciar via banco (DEFAULT now()) e não atribuir manualmente.
Isso evita divergências de horário em servidores com timezones distintos.


66-69: Consulta extra após save pode ser evitada

save() já devolve a entidade recém-persistida. Se você precisa apenas das relações, utilize this.savedJobsRepository.save(newSavedJob, { reload: true }) ou await this.savedJobsRepository.findOne({ ... }) com loadRelationIds em vez de executar outra busca completa.

Menos uma query melhora o throughput do endpoint.

src/database/migrations/1745261990419-migrations.ts (1)

8-8: Índice para expiração melhora o cleaner job

Como estamos utilizando expiresAt para remoção periódica, adicionar um índice (CREATE INDEX idx_saved_jobs_expires ON tb_saved_jobs (expiresAt);) tornará a deleção/consulta muito mais eficiente em grandes volumes.

🧰 Tools
🪛 ESLint

[error] 8-8: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now()·+·interval·'7·days'); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now()·+·interval·'7·days',

(prettier/prettier)

src/modules/savedjobs/repository/savedjobs.repository.ts (1)

40-44: Evite vazar mensagens internas no erro 500

InternalServerErrorException recebe error.message, que muitas vezes contém detalhes do banco. Sugestão:

-throw new InternalServerErrorException(`Erro ao buscar vagas salvas: ${error.message}`);
+throw new InternalServerErrorException('Erro interno ao buscar vagas salvas');

Logue a exception completa em nível de infraestrutura (Interceptor ou Logger), mas devolva mensagem genérica para o cliente.

🧰 Tools
🪛 ESLint

[error] 40-40: Delete

(prettier/prettier)


[error] 41-41: Delete

(prettier/prettier)


[error] 42-42: Delete

(prettier/prettier)


[error] 43-43: Delete

(prettier/prettier)


[error] 44-44: Delete

(prettier/prettier)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dddc8c7 and a09fca4.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • package.json (1 hunks)
  • src/app.module.ts (2 hunks)
  • src/database/migrations/1745261990419-migrations.ts (1 hunks)
  • src/database/migrations/1746107506888-migrations.ts (1 hunks)
  • src/main.ts (1 hunks)
  • src/modules/savedjobs/repository/savedjobs.repository.ts (1 hunks)
  • src/modules/savedjobs/savedjobs.module.ts (1 hunks)
  • src/modules/savedjobs/services/savedjobs-cleaner.service.ts (1 hunks)
  • src/modules/savedjobs/services/savedjobs.service.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • package.json
  • src/main.ts
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/modules/savedjobs/services/savedjobs-cleaner.service.ts (2)
src/modules/savedjobs/repository/savedjobs.repository.ts (1)
  • Injectable (8-46)
src/modules/savedjobs/services/savedjobs.service.ts (1)
  • Injectable (12-71)
src/app.module.ts (1)
src/modules/savedjobs/savedjobs.module.ts (1)
  • Module (11-28)
src/modules/savedjobs/savedjobs.module.ts (1)
src/app.module.ts (1)
  • Module (30-60)
🪛 ESLint
src/database/migrations/1746107506888-migrations.ts

[error] 1-1: Replace "typeorm" with 'typeorm'

(prettier/prettier)


[error] 4-4: Replace ··name·=·'Migrations1746107506888' with name·=·'Migrations1746107506888';

(prettier/prettier)


[error] 6-6: Delete ··

(prettier/prettier)


[error] 7-7: Replace ········await·queryRunner.query(CREATE·INDEX·"IDX_3845b06bfda63ccc1da359b378"·ON·"tb_saved_jobs"·("userId")·); with ····await·queryRunner.query(⏎······CREATE·INDEX·"IDX_3845b06bfda63ccc1da359b378"·ON·"tb_saved_jobs"·("userId")·,

(prettier/prettier)


[error] 8-8: Replace ····await·queryRunner.query(CREATE·INDEX·"IDX_9bbd9a1f3bb4942f0471816b11"·ON·"tb_saved_jobs"·("jobId")·); with );⏎····await·queryRunner.query(⏎······CREATE·INDEX·"IDX_9bbd9a1f3bb4942f0471816b11"·ON·"tb_saved_jobs"·("jobId")·,

(prettier/prettier)


[error] 9-9: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_9bbd9a1f3bb4942f0471816b111"·FOREIGN·KEY·("jobId")·REFERENCES·"tb_jobs"("id")·ON·DELETE·NO·ACTION·ON·UPDATE·NO·ACTION); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_9bbd9a1f3bb4942f0471816b111"·FOREIGN·KEY·("jobId")·REFERENCES·"tb_jobs"("id")·ON·DELETE·NO·ACTION·ON·UPDATE·NO·ACTION,

(prettier/prettier)


[error] 10-11: Replace }⏎ with );

(prettier/prettier)


[error] 12-12: Insert }⏎⏎

(prettier/prettier)


[error] 13-13: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_9bbd9a1f3bb4942f0471816b111"); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_9bbd9a1f3bb4942f0471816b111",

(prettier/prettier)


[error] 14-14: Replace ····await·queryRunner.query(DROP·INDEX·"public"."IDX_9bbd9a1f3bb4942f0471816b11"); with );⏎····await·queryRunner.query(⏎······DROP·INDEX·"public"."IDX_9bbd9a1f3bb4942f0471816b11",

(prettier/prettier)


[error] 15-15: Replace ····await·queryRunner.query(DROP·INDEX·"public"."IDX_3845b06bfda63ccc1da359b378"`` with );⏎····await·queryRunner.query(⏎······DROP·INDEX·"public"."IDX_3845b06bfda63ccc1da359b378"`,⏎····`

(prettier/prettier)


[error] 16-17: Replace ··}⏎ with }

(prettier/prettier)

src/modules/savedjobs/services/savedjobs-cleaner.service.ts

[error] 1-1: Replace "@nestjs/common";␍ with '@nestjs/common';

(prettier/prettier)


[error] 2-2: Replace "@nestjs/schedule";␍ with '@nestjs/schedule';

(prettier/prettier)


[error] 3-3: Replace "@nestjs/typeorm";␍ with '@nestjs/typeorm';

(prettier/prettier)


[error] 4-4: Replace "src/database/entities/savedjobs.entity";␍ with 'src/database/entities/savedjobs.entity';

(prettier/prettier)


[error] 5-5: Replace "typeorm";␍ with 'typeorm';

(prettier/prettier)


[error] 6-6: Delete

(prettier/prettier)


[error] 7-7: Delete

(prettier/prettier)


[error] 8-8: Delete

(prettier/prettier)


[error] 9-9: Delete

(prettier/prettier)


[error] 10-10: Delete

(prettier/prettier)


[error] 11-11: Delete

(prettier/prettier)


[error] 12-12: Delete

(prettier/prettier)


[error] 13-13: Delete

(prettier/prettier)


[error] 14-14: Delete

(prettier/prettier)


[error] 15-15: Delete

(prettier/prettier)


[error] 16-16: Delete

(prettier/prettier)


[error] 17-17: Delete

(prettier/prettier)


[error] 18-18: Delete

(prettier/prettier)


[error] 19-19: Delete

(prettier/prettier)


[error] 20-20: Delete

(prettier/prettier)


[error] 21-21: Delete

(prettier/prettier)


[error] 22-22: Delete

(prettier/prettier)


[error] 23-23: Delete

(prettier/prettier)


[error] 24-24: Delete

(prettier/prettier)


[error] 25-25: Delete

(prettier/prettier)

src/app.module.ts

[error] 21-21: Insert ;

(prettier/prettier)


[error] 25-25: Insert ;

(prettier/prettier)


[error] 26-26: Delete ·

(prettier/prettier)


[error] 27-27: Insert ;

(prettier/prettier)

src/database/migrations/1745261990419-migrations.ts

[error] 1-1: Replace "typeorm" with 'typeorm'

(prettier/prettier)


[error] 4-4: Replace ····name·=·'Migrations1745261990419' with ··name·=·'Migrations1745261990419';

(prettier/prettier)


[error] 6-6: Delete ··

(prettier/prettier)


[error] 7-7: Replace ········await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"); with ····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a",

(prettier/prettier)


[error] 8-8: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now()·+·interval·'7·days'); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now()·+·interval·'7·days',

(prettier/prettier)


[error] 9-9: Insert );⏎

(prettier/prettier)


[error] 10-10: Delete ····

(prettier/prettier)


[error] 11-11: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·SET·NOT·NULL); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·SET·NOT·NULL,

(prettier/prettier)


[error] 12-12: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·CASCADE·ON·UPDATE·NO·ACTION); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·CASCADE·ON·UPDATE·NO·ACTION,

(prettier/prettier)


[error] 13-14: Replace }⏎ with );

(prettier/prettier)


[error] 15-15: Insert }⏎⏎

(prettier/prettier)


[error] 16-16: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a",

(prettier/prettier)


[error] 17-17: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·DROP·NOT·NULL); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·DROP·NOT·NULL,

(prettier/prettier)


[error] 18-18: Insert );⏎

(prettier/prettier)


[error] 19-19: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·"jobId"·character·varying·NOT·NULL); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·"jobId"·character·varying·NOT·NULL,

(prettier/prettier)


[error] 20-20: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·DROP·COLUMN·"expiresAt"); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·DROP·COLUMN·"expiresAt",

(prettier/prettier)


[error] 21-21: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·NO·ACTION·ON·UPDATE·NO·ACTION`` with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·NO·ACTION·ON·UPDATE·NO·ACTION`,⏎····`

(prettier/prettier)


[error] 22-23: Replace ··}⏎ with }

(prettier/prettier)

src/modules/savedjobs/repository/savedjobs.repository.ts

[error] 1-1: Replace "@nestjs/common";␍ with '@nestjs/common';

(prettier/prettier)


[error] 2-2: Replace "@nestjs/typeorm";␍ with '@nestjs/typeorm';

(prettier/prettier)


[error] 3-3: Replace "src/database/entities/savedjobs.entity";␍ with 'src/database/entities/savedjobs.entity';

(prettier/prettier)


[error] 4-4: Replace "src/shared/pagination";␍ with 'src/shared/pagination';

(prettier/prettier)


[error] 5-5: Replace "typeorm";␍ with 'typeorm';

(prettier/prettier)


[error] 6-6: Replace "../dtos/get-all-savedjobs.dto";␍ with '../dtos/get-all-savedjobs.dto';

(prettier/prettier)


[error] 7-7: Delete

(prettier/prettier)


[error] 8-8: Delete

(prettier/prettier)


[error] 9-9: Delete

(prettier/prettier)


[error] 10-10: Delete

(prettier/prettier)


[error] 11-11: Delete

(prettier/prettier)


[error] 12-12: Delete

(prettier/prettier)


[error] 13-13: Delete

(prettier/prettier)


[error] 14-14: Delete

(prettier/prettier)


[error] 15-15: Delete

(prettier/prettier)


[error] 16-16: Delete

(prettier/prettier)


[error] 17-17: Delete

(prettier/prettier)


[error] 18-18: Delete

(prettier/prettier)


[error] 19-19: Delete

(prettier/prettier)


[error] 20-20: Delete

(prettier/prettier)


[error] 21-21: Delete

(prettier/prettier)


[error] 22-22: Delete

(prettier/prettier)


[error] 23-23: Delete

(prettier/prettier)


[error] 24-24: Delete

(prettier/prettier)


[error] 25-25: Delete

(prettier/prettier)


[error] 26-26: Delete

(prettier/prettier)


[error] 27-27: Delete

(prettier/prettier)


[error] 28-28: Delete

(prettier/prettier)


[error] 29-29: Delete

(prettier/prettier)


[error] 30-30: Delete

(prettier/prettier)


[error] 31-31: Delete

(prettier/prettier)


[error] 32-32: Delete

(prettier/prettier)


[error] 33-33: Delete

(prettier/prettier)


[error] 34-34: Delete

(prettier/prettier)


[error] 35-35: Delete

(prettier/prettier)


[error] 36-36: Delete

(prettier/prettier)


[error] 37-37: Delete

(prettier/prettier)


[error] 38-38: Delete

(prettier/prettier)


[error] 39-39: Delete

(prettier/prettier)


[error] 40-40: Delete

(prettier/prettier)


[error] 41-41: Delete

(prettier/prettier)


[error] 42-42: Delete

(prettier/prettier)


[error] 43-43: Delete

(prettier/prettier)


[error] 44-44: Delete

(prettier/prettier)


[error] 45-45: Delete

(prettier/prettier)


[error] 46-46: Insert

(prettier/prettier)

src/modules/savedjobs/savedjobs.module.ts

[error] 13-13: Delete ·

(prettier/prettier)


[error] 18-18: Delete ·

(prettier/prettier)


[error] 19-19: Insert ,

(prettier/prettier)


[error] 24-24: Delete ·

(prettier/prettier)


[error] 25-25: Insert ,

(prettier/prettier)


[error] 28-28: Insert

(prettier/prettier)

src/modules/savedjobs/services/savedjobs.service.ts

[error] 1-4: Replace ⏎··BadRequestException,⏎··Injectable,⏎ with ·BadRequestException,·Injectable·

(prettier/prettier)


[error] 23-24: Delete

(prettier/prettier)


[error] 26-26: Replace createSavedJobDto:·CreateSavedJobDto with ⏎····createSavedJobDto:·CreateSavedJobDto,⏎··

(prettier/prettier)


[error] 29-29: Replace ·where:·{·id:·userId·} with ⏎······where:·{·id:·userId·},⏎···

(prettier/prettier)

🔇 Additional comments (1)
src/modules/savedjobs/repository/savedjobs.repository.ts (1)

24-26: Ordenação default pode gerar SQL inválido

pageOptionsDto.order deve limitar-se a 'ASC' | 'DESC'. Garanta no DTO/enum essa restrição para evitar SQL injection indireto e erros de sintaxe ao chegar valores arbitrários.

🧰 Tools
🪛 ESLint

[error] 24-24: Delete

(prettier/prettier)


[error] 25-25: Delete

(prettier/prettier)


[error] 26-26: Delete

(prettier/prettier)

Comment on lines +16 to +24
@Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)
async cleanExpiredJobs() {
const now = new Date();
const result = await this.savedJobsRepository.delete({
expiresAt: LessThan(now),
});

this.logger.log(`🧹 Removidos ${result.affected} registros expirados.`);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Adicione tratamento de erros ao método cleanExpiredJobs.

O método atual não possui tratamento de erros, o que pode causar falhas silenciosas se a operação de exclusão falhar.

  @Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)
  async cleanExpiredJobs() {
-   const now = new Date();
-   const result = await this.savedJobsRepository.delete({
-     expiresAt: LessThan(now),
-   });
-
-   this.logger.log(`🧹 Removidos ${result.affected} registros expirados.`);
+   try {
+     const now = new Date();
+     const result = await this.savedJobsRepository.delete({
+       expiresAt: LessThan(now),
+     });
+
+     this.logger.log(`🧹 Removidos ${result.affected} registros expirados.`);
+   } catch (error) {
+     this.logger.error(`Erro ao limpar registros expirados: ${error.message}`, error.stack);
+   }
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)
async cleanExpiredJobs() {
const now = new Date();
const result = await this.savedJobsRepository.delete({
expiresAt: LessThan(now),
});
this.logger.log(`🧹 Removidos ${result.affected} registros expirados.`);
}
@Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)
async cleanExpiredJobs() {
try {
const now = new Date();
const result = await this.savedJobsRepository.delete({
expiresAt: LessThan(now),
});
this.logger.log(`🧹 Removidos ${result.affected} registros expirados.`);
} catch (error) {
this.logger.error(
`Erro ao limpar registros expirados: ${error.message}`,
error.stack,
);
}
}
🧰 Tools
🪛 ESLint

[error] 16-16: Delete

(prettier/prettier)


[error] 17-17: Delete

(prettier/prettier)


[error] 18-18: Delete

(prettier/prettier)


[error] 19-19: Delete

(prettier/prettier)


[error] 20-20: Delete

(prettier/prettier)


[error] 21-21: Delete

(prettier/prettier)


[error] 22-22: Delete

(prettier/prettier)


[error] 23-23: Delete

(prettier/prettier)


[error] 24-24: Delete

(prettier/prettier)

Comment on lines +39 to +48
const alreadySaved = await this.savedJobsRepository.exist({
where: {
user: { id: userId },
job: { id: jobId },
},
});

if (alreadySaved) {
throw new BadRequestException('Esta vaga já foi salva por este usuário.');
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Concorrência ainda pode gerar duplicidade de registros

Mesmo com a verificação alreadySaved, duas requisições simultâneas podem passar nessa checagem antes que uma delas persista o registro. Recomenda-se:

  1. Criar uma constraint UNIQUE (userId, jobId) na tabela tb_saved_jobs (atualmente não há).
  2. Envolver o bloco de persistência em transação e capturar a exceção de violação de unicidade, retornando 409/BadRequest apropriado.

Sem isso, continuamos sujeitos a registros duplicados.

Comment on lines +29 to +37
const userExists = await this.usersRepository.exist({ where: { id: userId } });
if (!userExists) {
throw new BadRequestException('Usuário não encontrado.');
}

const jobExists = await this.jobsRepository.exist({ where: { id: jobId } });
if (!jobExists) {
throw new BadRequestException('Vaga não encontrada.');
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Evite consultas redundantes e reduza round-trips ao banco

Os métodos exist() checam a presença de usuário e vaga, mas logo em seguida (linhas 50-52) são feitos dois findOneBy para buscar as mesmas entidades. Podemos economizar duas viagens ao banco buscando o usuário e a vaga diretamente e, a partir delas, validar a existência:

-const userExists = await this.usersRepository.exist({ where: { id: userId } });
-if (!userExists) {
-  throw new BadRequestException('Usuário não encontrado.');
-}
-const jobExists = await this.jobsRepository.exist({ where: { id: jobId } });
-if (!jobExists) {
-  throw new BadRequestException('Vaga não encontrada.');
-}
-
-const user = await this.usersRepository.findOneBy({ id: userId });
-const job = await this.jobsRepository.findOneBy({ id: jobId });
+const user = await this.usersRepository.findOne({ where: { id: userId } });
+if (!user) {
+  throw new BadRequestException('Usuário não encontrado.');
+}
+const job = await this.jobsRepository.findOne({ where: { id: jobId } });
+if (!job) {
+  throw new BadRequestException('Vaga não encontrada.');
+}

Além do ganho de performance, diminuímos a chance de resultados inconsistentes em cenários de replicação.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const userExists = await this.usersRepository.exist({ where: { id: userId } });
if (!userExists) {
throw new BadRequestException('Usuário não encontrado.');
}
const jobExists = await this.jobsRepository.exist({ where: { id: jobId } });
if (!jobExists) {
throw new BadRequestException('Vaga não encontrada.');
}
// Replace redundant exist() + findOneBy() calls with a single findOne() per entity
const user = await this.usersRepository.findOne({ where: { id: userId } });
if (!user) {
throw new BadRequestException('Usuário não encontrado.');
}
const job = await this.jobsRepository.findOne({ where: { id: jobId } });
if (!job) {
throw new BadRequestException('Vaga não encontrada.');
}
🧰 Tools
🪛 ESLint

[error] 29-29: Replace ·where:·{·id:·userId·} with ⏎······where:·{·id:·userId·},⏎···

(prettier/prettier)

Comment on lines +8 to +12
await queryRunner.query(`ALTER TABLE "tb_saved_jobs" ADD "expiresAt" TIMESTAMP NOT NULL DEFAULT now() + interval '7 days'`);
await queryRunner.query(`ALTER TABLE "tb_saved_jobs" DROP COLUMN "jobId"`);
await queryRunner.query(`ALTER TABLE "tb_saved_jobs" ADD "jobId" uuid`);
await queryRunner.query(`ALTER TABLE "tb_saved_jobs" ALTER COLUMN "userId" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "tb_saved_jobs" ADD CONSTRAINT "FK_3845b06bfda63ccc1da359b378a" FOREIGN KEY ("userId") REFERENCES "tb_users"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

jobId foi recriado sem NOT NULL nem chave estrangeira

Ao dropar e adicionar novamente a coluna:

ALTER TABLE "tb_saved_jobs" ADD "jobId" uuid
  1. A coluna agora aceita NULL, mas o domínio da aplicação exige presença do job.
  2. Não há FOREIGN KEY para tb_jobs(id), dificultando integridade referencial e exclusão em cascata.

Sugestão de correção:

ALTER TABLE "tb_saved_jobs"
  ADD "jobId" uuid NOT NULL,
  ADD CONSTRAINT "FK_saved_jobs_job"
      FOREIGN KEY ("jobId") REFERENCES "tb_jobs"("id")
      ON DELETE CASCADE;

Sem esses ajustes, poderemos ter registros órfãos ou falha de insert em runtime.

🧰 Tools
🪛 ESLint

[error] 8-8: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now()·+·interval·'7·days'); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·"expiresAt"·TIMESTAMP·NOT·NULL·DEFAULT·now()·+·interval·'7·days',

(prettier/prettier)


[error] 9-9: Insert );⏎

(prettier/prettier)


[error] 10-10: Delete ····

(prettier/prettier)


[error] 11-11: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·SET·NOT·NULL); with await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ALTER·COLUMN·"userId"·SET·NOT·NULL,

(prettier/prettier)


[error] 12-12: Replace ····await·queryRunner.query(ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·CASCADE·ON·UPDATE·NO·ACTION); with );⏎····await·queryRunner.query(⏎······ALTER·TABLE·"tb_saved_jobs"·ADD·CONSTRAINT·"FK_3845b06bfda63ccc1da359b378a"·FOREIGN·KEY·("userId")·REFERENCES·"tb_users"("id")·ON·DELETE·CASCADE·ON·UPDATE·NO·ACTION,

(prettier/prettier)

Comment on lines +28 to +34
if (filters.userId) {
queryBuilder.andWhere('user.id = :userId', { userId: filters.userId });
}

if (filters.jobId) {
queryBuilder.andWhere('job.id = :jobId', { jobId: filters.jobId });
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Valide UUIDs recebidos nos filtros

Os campos filters.userId e filters.jobId são interpolados direto na query. Ainda que usemos parâmetros, valores inválidos (ex.: strings aleatórias) resultarão em erro 500 do banco. Inclua validação antecipada (class-validator IsUUID) no DTO ou trate aqui lançando BadRequestException.

🧰 Tools
🪛 ESLint

[error] 28-28: Delete

(prettier/prettier)


[error] 29-29: Delete

(prettier/prettier)


[error] 30-30: Delete

(prettier/prettier)


[error] 31-31: Delete

(prettier/prettier)


[error] 32-32: Delete

(prettier/prettier)


[error] 33-33: Delete

(prettier/prettier)


[error] 34-34: Delete

(prettier/prettier)

Copy link
Copy Markdown
Contributor

@MikaelMelo1 MikaelMelo1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tudo certo viu, só uma observação no tratamento de erro no savedjobs-cleaner.service mas não solicitei

Copy link
Copy Markdown
Contributor

@MikaelMelo1 MikaelMelo1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfeito!

Copy link
Copy Markdown
Contributor

@MikaelMelo1 MikaelMelo1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfeito

Copy link
Copy Markdown
Contributor

@MikaelMelo1 MikaelMelo1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfeito

Copy link
Copy Markdown
Contributor

@MikaelMelo1 MikaelMelo1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfeito

Copy link
Copy Markdown
Contributor

@MikaelMelo1 MikaelMelo1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfeito

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Jun 4, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
20.3% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a09fca4 and 078485e.

📒 Files selected for processing (64)
  • src/app.controller.ts (1 hunks)
  • src/app.module.ts (2 hunks)
  • src/app.service.ts (1 hunks)
  • src/database/data-source.ts (1 hunks)
  • src/database/entities/applications.entity.ts (1 hunks)
  • src/database/entities/comments.entity.ts (1 hunks)
  • src/database/entities/curriculum.entity.ts (1 hunks)
  • src/database/entities/jobs.entity.ts (3 hunks)
  • src/database/entities/users.entity.ts (3 hunks)
  • src/database/migrations/1709068822100-migrations.ts (1 hunks)
  • src/database/migrations/1742707816058-migrations.ts (1 hunks)
  • src/database/migrations/1745261990419-migrations.ts (1 hunks)
  • src/database/migrations/1745262789787-migrations.ts (1 hunks)
  • src/database/migrations/1745267234389-migrations.ts (1 hunks)
  • src/database/migrations/1746107506888-migrations.ts (1 hunks)
  • src/main.ts (2 hunks)
  • src/modules/applications/applications.module.ts (1 hunks)
  • src/modules/applications/interfaces/interfaces.ts (1 hunks)
  • src/modules/applications/repository/applications.repository.ts (1 hunks)
  • src/modules/candidacy/service/candidacy.service.spec.ts (1 hunks)
  • src/modules/comment/comment.controller.ts (1 hunks)
  • src/modules/comment/comment.module.ts (1 hunks)
  • src/modules/comment/interfaces/interfaces.ts (1 hunks)
  • src/modules/comment/repository/comment.repository.ts (1 hunks)
  • src/modules/company/company.controller.ts (2 hunks)
  • src/modules/company/company.module.ts (1 hunks)
  • src/modules/company/interfaces/interfaces.ts (1 hunks)
  • src/modules/company/repository/company-repository.ts (6 hunks)
  • src/modules/company/services/create-company.service.ts (1 hunks)
  • src/modules/company/services/update-password-by-email.service.ts (1 hunks)
  • src/modules/curriculum/curriculum.controller.ts (1 hunks)
  • src/modules/curriculum/curriculum.module.ts (1 hunks)
  • src/modules/curriculum/curriculum.service.ts (1 hunks)
  • src/modules/curriculum/interfaces/interfaces.ts (1 hunks)
  • src/modules/curriculum/repository/curriculum-repository.ts (1 hunks)
  • src/modules/jobs/interfaces/interfaces.ts (1 hunks)
  • src/modules/jobs/jobs.controller.ts (2 hunks)
  • src/modules/jobs/jobs.module.ts (1 hunks)
  • src/modules/jobs/repository/job.repository.ts (3 hunks)
  • src/modules/jobs/services/delete-job.service.ts (1 hunks)
  • src/modules/jobs/services/get-all-jobs-from-logged-company.service.ts (1 hunks)
  • src/modules/mails/mail.module.ts (1 hunks)
  • src/modules/reports/reports.module.ts (1 hunks)
  • src/modules/reports/repository/reports.repository.ts (1 hunks)
  • src/modules/savedjobs/dtos/create-savedJob-dto.ts (1 hunks)
  • src/modules/savedjobs/dtos/get-all-savedjobs.dto.ts (1 hunks)
  • src/modules/savedjobs/repository/savedjobs.repository.ts (1 hunks)
  • src/modules/savedjobs/savedjobs.controller.ts (1 hunks)
  • src/modules/savedjobs/savedjobs.module.ts (1 hunks)
  • src/modules/savedjobs/services/find-all-savedjobs.service.ts (1 hunks)
  • src/modules/savedjobs/services/savedjobs-cleaner.service.ts (1 hunks)
  • src/modules/savedjobs/services/savedjobs.service.ts (1 hunks)
  • src/modules/user/dtos/create-user.dto.ts (1 hunks)
  • src/modules/user/interfaces/interfaces.ts (1 hunks)
  • src/modules/user/repository/user.repository.ts (4 hunks)
  • src/modules/user/services/create-user.service.ts (1 hunks)
  • src/modules/user/services/delete-user.service.ts (1 hunks)
  • src/modules/user/user.controller.ts (2 hunks)
  • src/modules/user/user.module.ts (1 hunks)
  • src/shared/Swagger/conflict.swagger.ts (1 hunks)
  • src/shared/Swagger/decorators/app/classes/health-check-response.swagger.ts (1 hunks)
  • src/shared/Swagger/decorators/savedjobs/create-savedjobs.swagger.decorator.ts (1 hunks)
  • src/shared/Swagger/decorators/savedjobs/view-savedjobs.swagger.decorator.ts (1 hunks)
  • src/shared/interfaces/interfaces.ts (1 hunks)
✅ Files skipped from review due to trivial changes (43)
  • src/database/data-source.ts
  • src/modules/applications/repository/applications.repository.ts
  • src/modules/company/services/create-company.service.ts
  • src/modules/jobs/jobs.module.ts
  • src/modules/company/company.module.ts
  • src/modules/user/user.module.ts
  • src/modules/company/services/update-password-by-email.service.ts
  • src/modules/curriculum/curriculum.controller.ts
  • src/modules/applications/applications.module.ts
  • src/database/entities/comments.entity.ts
  • src/modules/candidacy/service/candidacy.service.spec.ts
  • src/modules/user/services/create-user.service.ts
  • src/database/entities/applications.entity.ts
  • src/modules/comment/comment.controller.ts
  • src/app.controller.ts
  • src/modules/curriculum/curriculum.service.ts
  • src/modules/curriculum/curriculum.module.ts
  • src/shared/Swagger/decorators/app/classes/health-check-response.swagger.ts
  • src/modules/comment/interfaces/interfaces.ts
  • src/modules/curriculum/repository/curriculum-repository.ts
  • src/shared/interfaces/interfaces.ts
  • src/database/entities/curriculum.entity.ts
  • src/modules/user/user.controller.ts
  • src/modules/reports/reports.module.ts
  • src/modules/user/dtos/create-user.dto.ts
  • src/modules/user/services/delete-user.service.ts
  • src/modules/curriculum/interfaces/interfaces.ts
  • src/modules/comment/comment.module.ts
  • src/modules/company/company.controller.ts
  • src/modules/reports/repository/reports.repository.ts
  • src/shared/Swagger/conflict.swagger.ts
  • src/modules/comment/repository/comment.repository.ts
  • src/modules/applications/interfaces/interfaces.ts
  • src/modules/jobs/interfaces/interfaces.ts
  • src/modules/jobs/jobs.controller.ts
  • src/modules/jobs/services/delete-job.service.ts
  • src/database/migrations/1709068822100-migrations.ts
  • src/app.service.ts
  • src/modules/jobs/services/get-all-jobs-from-logged-company.service.ts
  • src/modules/jobs/repository/job.repository.ts
  • src/modules/company/interfaces/interfaces.ts
  • src/modules/user/interfaces/interfaces.ts
  • src/modules/savedjobs/services/savedjobs-cleaner.service.ts
🚧 Files skipped from review as they are similar to previous changes (19)
  • src/modules/mails/mail.module.ts
  • src/shared/Swagger/decorators/savedjobs/view-savedjobs.swagger.decorator.ts
  • src/main.ts
  • src/modules/savedjobs/dtos/create-savedJob-dto.ts
  • src/database/migrations/1746107506888-migrations.ts
  • src/database/migrations/1745267234389-migrations.ts
  • src/database/entities/users.entity.ts
  • src/modules/savedjobs/savedjobs.module.ts
  • src/modules/savedjobs/dtos/get-all-savedjobs.dto.ts
  • src/app.module.ts
  • src/shared/Swagger/decorators/savedjobs/create-savedjobs.swagger.decorator.ts
  • src/database/entities/jobs.entity.ts
  • src/modules/savedjobs/services/savedjobs.service.ts
  • src/database/migrations/1745262789787-migrations.ts
  • src/database/migrations/1742707816058-migrations.ts
  • src/database/migrations/1745261990419-migrations.ts
  • src/modules/savedjobs/repository/savedjobs.repository.ts
  • src/modules/savedjobs/services/find-all-savedjobs.service.ts
  • src/modules/savedjobs/savedjobs.controller.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/modules/company/repository/company-repository.ts (2)
src/shared/utils/handle-error.util.ts (1)
  • handleError (3-14)
src/modules/company/dtos/update-my-password.dto.ts (1)
  • UpdateMyPasswordDto (5-39)
src/modules/user/repository/user.repository.ts (1)
src/shared/utils/handle-error.util.ts (1)
  • handleError (3-14)
🪛 Biome (1.9.4)
src/modules/company/repository/company-repository.ts

[error] 154-154: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

src/modules/user/repository/user.repository.ts

[error] 132-132: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🔇 Additional comments (5)
src/modules/company/repository/company-repository.ts (3)

12-15: Melhoria na formatação do construtor aprovada.

A formatação expandida do construtor melhora significativamente a legibilidade do código.


47-56: Formatação aprimorada dos métodos encadeados.

A expansão das chamadas de métodos encadeados em múltiplas linhas melhora a legibilidade e facilita a manutenção do código.


59-70: Aprovação das melhorias de formatação.

As reformatações dos métodos encadeados em múltiplas linhas melhoram consistentemente a legibilidade do código em todo o arquivo.

Also applies to: 82-88, 92-92, 96-107, 116-118, 134-136, 146-163

src/modules/user/repository/user.repository.ts (2)

17-20: Melhoria na formatação do construtor aprovada.

A formatação expandida do construtor melhora a legibilidade do código de forma consistente com outros repositórios.


46-48: Aprovação das melhorias de formatação.

As reformatações dos métodos encadeados em múltiplas linhas melhoram consistentemente a legibilidade e manutenibilidade do código em todo o repositório.

Also applies to: 52-52, 56-56, 76-78, 84-87, 93-95, 104-106, 110-114, 118-120, 124-126, 134-141

return company;
}

async UpdateCompanyById(id: string, data: any) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Corrigir convenção de nomenclatura do método.

O nome do método UpdateCompanyById não segue a convenção camelCase do JavaScript/TypeScript.

-  async UpdateCompanyById(id: string, data: any) {
+  async updateCompanyById(id: string, data: any) {
🤖 Prompt for AI Agents
In src/modules/company/repository/company-repository.ts at line 58, the method
name UpdateCompanyById does not follow JavaScript/TypeScript camelCase naming
conventions. Rename the method to updateCompanyById to comply with standard
naming practices.

password,
};

delete company.password;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Otimizar performance removendo o operador delete.

O operador delete pode impactar a performance. Recomenda-se usar atribuição undefined conforme sugerido pela análise estática.

-    delete company.password;
+    company.password = undefined;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
delete company.password;
company.password = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 154-154: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🤖 Prompt for AI Agents
In src/modules/company/repository/company-repository.ts at line 154, replace the
use of the delete operator on company.password with an assignment of undefined
to company.password to optimize performance and comply with static analysis
recommendations.

password,
};

delete user.password;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Otimizar performance removendo o operador delete.

O operador delete pode impactar a performance. Recomenda-se usar atribuição undefined conforme sugerido pela análise estática.

-    delete user.password;
+    user.password = undefined;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
delete user.password;
user.password = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 132-132: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🤖 Prompt for AI Agents
In src/modules/user/repository/user.repository.ts at line 132, replace the use
of the delete operator on user.password with an assignment of undefined to
user.password. This change avoids the performance cost associated with delete
while effectively removing the password property value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants