Kanban - Murilo Henrique Beraldo#489
Conversation
…corretamente e corrigido/adicionado novas animações
… melhoras no visual e usabilidade
Signed-off-by: Murilo Beraldo <murilohenriqueberaldo@gmail.com>
There was a problem hiding this comment.
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
/tasksAPI, 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.
| import { Component, signal } from '@angular/core'; | ||
| import { Board } from './components/board/board' |
There was a problem hiding this comment.
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).
|
|
||
| async function bootstrap() { | ||
| const app = await NestFactory.create(AppModule); | ||
| app.enableCors(); |
There was a problem hiding this comment.
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.
| 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, | |
| }); |
| @@ -0,0 +1,4 @@ | |||
| <div class="card"> | |||
| <span>{{ text() }}</span> | |||
| <button class="delete-btn" (click)="delete()">×</button> | |||
There was a problem hiding this comment.
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.
| describe('User Actions', () => { | ||
| it('should add a column', () => { | ||
| const newCol = { id: '6', name: 'New Col', order: 5, tasks: [] }; | ||
| mockTaskService.createColumn.mockReturnValue(of(newCol)); | ||
|
|
There was a problem hiding this comment.
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.
| beforeEach(async () => { | ||
| const moduleFixture: TestingModule = await Test.createTestingModule({ | ||
| imports: [AppModule], | ||
| }).compile(); | ||
|
|
||
| app = moduleFixture.createNestApplication(); | ||
| await app.init(); | ||
| }); |
There was a problem hiding this comment.
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().
| export class TaskService { | ||
| private apiUrl = 'http://localhost:3000/tasks'; | ||
|
|
There was a problem hiding this comment.
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.
| //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) { |
There was a problem hiding this comment.
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.
| "@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" | ||
| }, |
There was a problem hiding this comment.
@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.
| "@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" | |
| }, |
| # Diagnostic reports (https://nodejs.org/api/report.html) | ||
| report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json | ||
|
|
||
| /generated/prisma |
There was a problem hiding this comment.
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.
| /generated/prisma | |
| src/generated/prisma/ |
| async deleteTask(id: string) { | ||
| return this.prisma.task.delete({ | ||
| where: { id }, | ||
| }); | ||
| } |
There was a problem hiding this comment.
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).
Framework, linguagem e ferramentas
Tecnologias
Princípios de software
Desafios e problemas
Melhorias e próximas implementações
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