Skip to content

Kanban - Murilo Henrique Beraldo#489

Open
mhbs12 wants to merge 16 commits intoFieldControl:masterfrom
mhbs12:master
Open

Kanban - Murilo Henrique Beraldo#489
mhbs12 wants to merge 16 commits intoFieldControl:masterfrom
mhbs12:master

Conversation

@mhbs12
Copy link

@mhbs12 mhbs12 commented Mar 3, 2026

Framework, linguagem e ferramentas

  • Frontend: Angular 21 (Signals, Standalone Components, Angular CDK para Drag & Drop, Vitest para testes).
  • Backend: NestJS (Node.js framework), Prisma (ORM), SQLite (Banco de dados), Jest (Testes).
  • Estilização: CSS puro com variáveis e layout responsivo (Flexbox/Grid).
  • IA: Utilizada para acelerar a escrita de testes unitários, refatoração de código (Clean Code), sugestões de otimização de CSS e me ajudar em solução de bugs e implementações.

Tecnologias

  • Angular 21 (Signals) vs RxJS: Optei por usar Signals para o gerenciamento de estado local por ser a abordagem mais moderna e performática do Angular, reduzindo a complexidade e boilerplate comparado ao RxJS tradicional (BehaviorSubject).
  • NestJS vs Express puro: Escolhi NestJS pela sua arquitetura modular e robusta (Injeção de Dependência, Decorators) que facilita a escalabilidade e manutenção, além de já vir configurado com TypeScript.
  • SQLite vs Postgres: Para este desafio, o SQLite foi escolhido pela simplicidade de configuração (arquivo local) e portabilidade, eliminando a necessidade de containers Docker para rodar o banco.

Princípios de software

  • SOLID: Aplicado especialmente no Backend, com a separação clara de responsabilidades entre Controllers (interface) e Services (regras de negócio).
  • Clean Code: Foco em nomes de variáveis descritivos (em inglês), funções pequenas e remoção de código morto.
  • DRY (Don't Repeat Yourself): Reutilização de componentes no frontend ( Card , Column ) e serviços compartilhados.

Desafios e problemas

  1. Layout das Colunas: O CSS Grid padrão deixava espaços vazios indesejados quando as colunas tinham alturas diferentes.
    • Solução: Implementei uma lógica de Masonry Layout no frontend ( board.ts ), distribuindo matematicamente as colunas em 4 "faixas" verticais usando computed signals.
  2. Drag & Drop com Persistência: Sincronizar a animação visual instantânea com a atualização no banco de dados.
    • Solução: Usei o Angular CDK para o feedback visual imediato e, em segundo plano, chamei o endpoint PATCH do backend. No backend, usei Transações do Prisma para garantir que a reordenação dos índices (order) fosse atômica e consistente.
      Melhorias e próximas implementações
  • Autenticação: Adicionar login e usuários para que cada um tenha seu próprio quadro.
  • Websockets (Socket.io): Implementar atualizações em tempo real para que dois usuários vendo o mesmo quadro vejam as mudanças do outro instantaneamente.
  • Testes E2E: Adicionar testes ponta a ponta com Cypress ou Playwright.

Vídeo de apresentação

(Link do vídeo)

Sobre

Meu nome é Murilo Beraldo, atualmente estou finalizando meu contrato de jovem aprendiz na Cobb Vantress, e gostaria de entrar na área de desenvolvimento. Sempre gostei de computadores, celulares e tecnologia em geral, devido a isso entrei na UNIRP em SJRP para cursar Engenharia da Computação, desde o ano passado comecei a me interessar por desenvolvimento Web3 e pude aprender algumas linguagens usadas nos smart contracts como Sui Move, e Solidity, mas, para realizar a implementação eu precisava saber desenvolver também na Web2, então, comecei a ver um curso de desenvolvimento com React(fullstackopen)(em andamento) e acabei aprendendo sobre frontend e backend, eu aprendo rápido então vi a vaga de vocês, aceitei o desafio e fiz minha inscrição.

Contato
E-mail: murilohenriqueberaldo@gmail.com
LinkedIn: https://www.linkedin.com/in/muriloberaldo

Copilot AI review requested due to automatic review settings March 3, 2026 21:00
@mhbs12 mhbs12 requested a review from a team as a code owner March 3, 2026 21:00
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements a full-stack Kanban board application, adding an Angular (Signals + CDK drag/drop) frontend and a NestJS + Prisma + SQLite backend, plus project configs and basic unit/e2e tests.

Changes:

  • Add Angular frontend with Board/Column/Card components, drag & drop UI behavior, and HTTP service to the backend.
  • Add NestJS backend with /tasks API, Prisma schema/migrations for Column/Task ordering, and service logic for reordering.
  • Add initial test scaffolding (Vitest-driven Angular unit tests; Jest unit + e2e tests for backend) and update project documentation.

Reviewed changes

Copilot reviewed 62 out of 75 changed files in this pull request and generated 17 comments.

Show a summary per file
File Description
README.md Replaces challenge README with run instructions/tech stack notes
frontend/tsconfig.spec.json TS config for spec build (vitest globals types)
frontend/tsconfig.json Base TS + Angular compiler strict settings
frontend/tsconfig.app.json TS config for app build (excludes specs)
frontend/src/styles.css Global CDK drag/drop placeholder/preview styles
frontend/src/main.ts Bootstraps standalone Angular app
frontend/src/index.html App HTML shell
frontend/src/app/services/task.ts Frontend API client + Task/Column interfaces
frontend/src/app/components/column/column.ts Column component (edit/add task, drop handling)
frontend/src/app/components/column/column.spec.ts Column unit test scaffold
frontend/src/app/components/column/column.html Column template with edit/add UI + drop list
frontend/src/app/components/column/column.css Column styling
frontend/src/app/components/card/card.ts Card component (text + delete output)
frontend/src/app/components/card/card.spec.ts Card unit test scaffold
frontend/src/app/components/card/card.html Card template
frontend/src/app/components/card/card.css Card styling
frontend/src/app/components/board/board.ts Board state mgmt + drag/drop persistence calls
frontend/src/app/components/board/board.spec.ts Board tests (masonry + add column)
frontend/src/app/components/board/board.html Board template (lane distribution + add column UI)
frontend/src/app/components/board/board.css Board/lane/add-column styling
frontend/src/app/app.ts Root app component wiring board
frontend/src/app/app.spec.ts Root component test
frontend/src/app/app.routes.ts Router routes placeholder
frontend/src/app/app.html Header + links + board placement
frontend/src/app/app.css App layout styling
frontend/src/app/app.config.ts App providers (router/http/animations)
frontend/public/favicon.ico App favicon asset
frontend/package.json Frontend deps/scripts (Angular + Vitest)
frontend/angular.json Angular project/build/test configuration
frontend/README.md Frontend run/test documentation
frontend/.vscode/tasks.json VS Code tasks for start/test
frontend/.vscode/mcp.json Angular CLI MCP server config
frontend/.vscode/launch.json VS Code debug launch configs
frontend/.vscode/extensions.json VS Code extension recommendations
frontend/.prettierrc Prettier settings
frontend/.gitignore Frontend ignore rules
frontend/.editorconfig EditorConfig formatting rules
backend/tsconfig.json Backend TS compiler options
backend/tsconfig.build.json Backend build TS config exclude globs
backend/test/jest-e2e.json Jest e2e config
backend/test/app.e2e-spec.ts Basic e2e “Hello World” test
backend/src/tasks/tasks.service.ts Prisma-backed task/column CRUD + reorder transaction
backend/src/tasks/tasks.service.spec.ts Unit tests for service reorder logic
backend/src/tasks/tasks.module.ts Tasks module wiring
backend/src/tasks/tasks.controller.ts REST controller for tasks/columns
backend/src/tasks/tasks.controller.spec.ts Controller unit test scaffold
backend/src/tasks/prisma.service.ts PrismaClient wrapper for Nest DI
backend/src/tasks/dto/update-task.dto.ts Update DTO scaffold
backend/src/tasks/dto/create-task.dto.ts Create DTO scaffold
backend/src/main.ts Nest bootstrap + CORS + listen port
backend/src/generated/prisma/models/Task.ts Generated Prisma model/types output
backend/src/generated/prisma/models/Column.ts Generated Prisma model/types output
backend/src/generated/prisma/models.ts Generated Prisma barrel exports
backend/src/generated/prisma/internal/prismaNamespaceBrowser.ts Generated Prisma internal browser namespace
backend/src/generated/prisma/internal/prismaNamespace.ts Generated Prisma internal namespace
backend/src/generated/prisma/internal/class.ts Generated Prisma client class/runtime glue
backend/src/generated/prisma/enums.ts Generated Prisma enums output
backend/src/generated/prisma/commonInputTypes.ts Generated Prisma common input/filter types
backend/src/generated/prisma/client.ts Generated Prisma server entrypoint
backend/src/generated/prisma/browser.ts Generated Prisma browser types entrypoint
backend/src/app.service.ts Default Nest service
backend/src/app.module.ts App module wiring (+ tasks module)
backend/src/app.controller.ts Default controller (Hello World)
backend/src/app.controller.spec.ts Default controller test
backend/prisma/schema.prisma Prisma schema for Column/Task
backend/prisma/migrations/migration_lock.toml Prisma migrations lockfile
backend/prisma/migrations/20260228190750_init_kanban/migration.sql Initial SQLite schema migration
backend/package.json Backend deps/scripts (Nest + Prisma + Jest)
backend/nest-cli.json Nest CLI configuration
backend/eslint.config.mjs ESLint + TS + Prettier config
backend/README.md Nest starter README
backend/.prettierrc Backend Prettier settings
backend/.gitignore Backend ignore rules

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +2
import { Component, signal } from '@angular/core';
import { Board } from './components/board/board'
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

signal is imported but not used in this component. Consider removing the unused import to keep the file clean (and avoid future lint/TS noUnusedLocals issues if enabled).

Copilot uses AI. Check for mistakes.

async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors();
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

app.enableCors() enables CORS for all origins/methods/headers. If this is intended only for local development, consider restricting allowed origins (e.g. http://localhost:4200) and/or reading allowed origins from env to avoid accidentally shipping an overly-permissive CORS policy.

Suggested change
app.enableCors();
const allowedOrigins =
process.env.CORS_ORIGINS?.split(',')
.map(origin => origin.trim())
.filter(origin => origin.length > 0) ||
['http://localhost:4200'];
app.enableCors({
origin: allowedOrigins,
});

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,4 @@
<div class="card">
<span>{{ text() }}</span>
<button class="delete-btn" (click)="delete()">×</button>
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The delete button is icon-only ("×") and has no accessible name. Add an aria-label (or visually hidden text) so screen readers can announce what the button does; relying on the glyph alone is not accessible.

Copilot uses AI. Check for mistakes.
Comment on lines +88 to +92
describe('User Actions', () => {
it('should add a column', () => {
const newCol = { id: '6', name: 'New Col', order: 5, tasks: [] };
mockTaskService.createColumn.mockReturnValue(of(newCol));

Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

Board drag/drop persistence logic (onTaskMoved + backend sync) is a key behavior but currently untested. Consider adding tests that simulate a CdkDragDrop event (same column and cross-column) and assert that the local signal updates and updateTaskPosition is called with the expected args, including the reload-on-error path.

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +17
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();

app = moduleFixture.createNestApplication();
await app.init();
});
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The e2e test creates a Nest application in beforeEach but never closes it. This can leave open handles and make Jest hang/flaky as more tests are added. Consider adding an afterEach/afterAll that calls await app.close().

Copilot uses AI. Check for mistakes.
Comment on lines +22 to +24
export class TaskService {
private apiUrl = 'http://localhost:3000/tasks';

Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

apiUrl is hardcoded to http://localhost:3000/tasks, which makes builds/deployments and environment switching harder. Prefer configuring the API base URL via Angular environment files (or a runtime config) and composing endpoints from that, so prod/staging/dev can differ without code changes.

Copilot uses AI. Check for mistakes.
Comment on lines +119 to +121
//Atualiza a ordem das tarefas quando elas são movidas entre colunas
onTaskMoved(event: CdkDragDrop<Task[]>, columnId: string) {
if (event.previousContainer === event.container && event.previousIndex === event.currentIndex) {
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

onTaskMoved receives columnId but never uses it (the method uses event.container.id instead). This unused parameter is misleading and can cause confusion about which value is authoritative. Remove the parameter from the method/template binding, or use it consistently.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +59
"@prisma/client": "^6.4.1",
"@types/better-sqlite3": "^7.6.13",
"better-sqlite3": "^12.6.2",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.18.0",
"@nestjs/cli": "^11.0.0",
"@nestjs/schematics": "^11.0.0",
"@nestjs/testing": "^11.0.1",
"@types/express": "^5.0.0",
"@types/jest": "^30.0.0",
"@types/node": "^22.10.7",
"@types/supertest": "^6.0.2",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-prettier": "^5.2.2",
"globals": "^16.0.0",
"jest": "^30.0.0",
"prettier": "^3.4.2",
"prisma": "^6.4.1",
"source-map-support": "^0.5.21",
"supertest": "^7.0.0",
"ts-jest": "^29.2.5",
"ts-loader": "^9.5.2",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0"
},
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

@prisma/client/prisma versions are ^6.4.1, but the checked-in generated Prisma client code under src/generated/prisma indicates client v7.4.2. This version mismatch is likely to break runtime/build (generated client and runtime must match). Align all Prisma-related packages to the same major/minor version and regenerate the client from that version, or stop committing the generated client and generate it during install/build instead.

Suggested change
"@prisma/client": "^6.4.1",
"@types/better-sqlite3": "^7.6.13",
"better-sqlite3": "^12.6.2",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.18.0",
"@nestjs/cli": "^11.0.0",
"@nestjs/schematics": "^11.0.0",
"@nestjs/testing": "^11.0.1",
"@types/express": "^5.0.0",
"@types/jest": "^30.0.0",
"@types/node": "^22.10.7",
"@types/supertest": "^6.0.2",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-prettier": "^5.2.2",
"globals": "^16.0.0",
"jest": "^30.0.0",
"prettier": "^3.4.2",
"prisma": "^6.4.1",
"source-map-support": "^0.5.21",
"supertest": "^7.0.0",
"ts-jest": "^29.2.5",
"ts-loader": "^9.5.2",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0"
},
"@prisma/client": "^7.4.2",
"@types/better-sqlite3": "^7.6.13",
"better-sqlite3": "^12.6.2",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.18.0",
"@nestjs/cli": "^11.0.0",
"@nestjs/schematics": "^11.0.0",
"@nestjs/testing": "^11.0.1",
"@types/express": "^5.0.0",
"@types/jest": "^30.0.0",
"@types/node": "^22.10.7",
"@types/supertest": "^6.0.2",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-prettier": "^5.2.2",
"globals": "^16.0.0",
"jest": "^30.0.0",
"prettier": "^3.4.2",
"prisma": "^7.4.2",
"source-map-support": "^0.5.21",
"supertest": "^7.0.0",
"ts-jest": "^29.2.5",
"ts-loader": "^9.5.2",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0"
},

Copilot uses AI. Check for mistakes.
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

/generated/prisma
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The .gitignore entry /generated/prisma does not match the committed generated Prisma client path (src/generated/prisma). As-is, generated code will continue to be tracked. Either update the ignore rule to the actual path (e.g. src/generated/prisma/) and remove generated files from the repo, or intentionally commit them and remove the misleading ignore entry.

Suggested change
/generated/prisma
src/generated/prisma/

Copilot uses AI. Check for mistakes.
Comment on lines +99 to +103
async deleteTask(id: string) {
return this.prisma.task.delete({
where: { id },
});
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

deleteTask removes the task but does not reindex/decrement the order of tasks below it in the same column. Because the frontend sends event.currentIndex as the new order, gaps in stored order values will eventually desync UI indexes from DB ordering and can make updateTaskPosition reorder the wrong rows. Consider performing a transaction that (1) finds the deleted task’s columnId/order, (2) deletes it, and (3) decrements order for tasks with order > deletedOrder in that column (or switch to a fractional ordering strategy).

Copilot uses AI. Check for mistakes.
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.

2 participants