Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
84689fd
config: novo teste
nicolasreisdev Nov 20, 2025
4149190
config: atualização de pipeline e novo teste.
nicolasreisdev Nov 20, 2025
27f1b23
config: desconsiderando testes para testar a pipeline.
nicolasreisdev Nov 20, 2025
f79086b
config: adaptando testes para testar pipeline
nicolasreisdev Nov 20, 2025
d430a0a
config: teste apos configuração em qlty.sh
nicolasreisdev Nov 20, 2025
92cd173
config: novo teste
nicolasreisdev Nov 20, 2025
734482a
config: teste
nicolasreisdev Nov 20, 2025
8b23e3f
config: teste comments
nicolasreisdev Nov 20, 2025
28cc71d
config: teste criação de issues.
nicolasreisdev Nov 20, 2025
2c41ceb
fix pipe config
nicolasreisdev Nov 20, 2025
d292b6d
fix qlty error
nicolasreisdev Nov 20, 2025
5a6ed84
pelo amor de Deus funciona
nicolasreisdev Nov 20, 2025
121953b
por favor
nicolasreisdev Nov 20, 2025
ab54d11
agora acho que o comando esta certo
nicolasreisdev Nov 20, 2025
fa68c67
ta quase
nicolasreisdev Nov 20, 2025
eaa563c
por favor
nicolasreisdev Nov 20, 2025
b8d4a96
ultima tentativa
nicolasreisdev Nov 20, 2025
d62e93d
vamo
nicolasreisdev Nov 20, 2025
7c27468
fui burro e esqueci de tirar o bgl da pipe
nicolasreisdev Nov 20, 2025
2c21a79
pls
nicolasreisdev Nov 20, 2025
8fa7203
pls
nicolasreisdev Nov 20, 2025
5b1cc6b
new test
nicolasreisdev Nov 21, 2025
5a468d6
new command in CLI
nicolasreisdev Nov 21, 2025
fe73e67
CLI funcionando, tentar criar issues.
nicolasreisdev Nov 21, 2025
b8de83d
fix issues create
nicolasreisdev Nov 21, 2025
16136c5
fix create
nicolasreisdev Nov 21, 2025
e6b1c05
fix erros: new test
nicolasreisdev Nov 21, 2025
9d45c6b
Merge branch 'main' of https://github.com/nicolasreisdev/CTable into …
nicolasreisdev Nov 21, 2025
4d92fc8
config issues create and fix #86, Close #86
nicolasreisdev Nov 21, 2025
c33617c
Refactor: Implementação completa das correções de validação e estabil…
nicolasreisdev Nov 21, 2025
04c2802
Merge branch 'back/ceci' of https://github.com/nicolasreisdev/CTable …
nicolasreisdev Nov 21, 2025
36036ce
adicionando lógica de criação de comunidade e iniciando endpoint
nicolasreisdev Nov 21, 2025
709b988
adicionando funcionalidade de criar comunidade.
nicolasreisdev Nov 21, 2025
568d691
add novos endpoints válidos para comunidades.
nicolasreisdev Nov 22, 2025
c781ca1
Merge branch 'main' of https://github.com/nicolasreisdev/CTable into …
nicolasreisdev Nov 22, 2025
3ecf31f
feature: adicionando endpoints de retorno de comunidades do usuário e…
nicolasreisdev Nov 25, 2025
31baaec
feature: new features for community
nicolasreisdev Nov 25, 2025
3ae528b
resolve merge
nicolasreisdev Nov 29, 2025
12f3e7f
adicionando lógica de comentários em projetos.
nicolasreisdev Nov 29, 2025
e936fe7
adicionando lógica para sair de comunidade.
nicolasreisdev Nov 29, 2025
9088a47
finalizando endpoints e features
nicolasreisdev Nov 30, 2025
917df18
fix errors and new feature for feed
nicolasreisdev Nov 30, 2025
af8bfe3
Merge branch 'main' of https://github.com/nicolasreisdev/CTable into …
nicolasreisdev Nov 30, 2025
85fccc6
teste no backend e frontend. Criação de issues e pipeline atualizados.
nicolasreisdev Nov 30, 2025
03d775f
fix errors in pipeline
nicolasreisdev Nov 30, 2025
daedf85
Merge branch 'main' into deploy/nicolas
nicolasreisdev Nov 30, 2025
5153a0f
fix errors in pipeline
nicolasreisdev Nov 30, 2025
b52fa43
fix errors in pipeline
nicolasreisdev Nov 30, 2025
e00b482
config visualization
nicolasreisdev Dec 1, 2025
7de8658
Merge branch 'main' into deploy/nicolas
nicolasreisdev Dec 1, 2025
6e537d4
fix error
nicolasreisdev Dec 1, 2025
df6f42d
Merge branch 'deploy/nicolas' of https://github.com/nicolasreisdev/CT…
nicolasreisdev Dec 1, 2025
8cf13db
test for deploy
nicolasreisdev Dec 1, 2025
10af266
fix errors
nicolasreisdev Dec 1, 2025
210cec3
Merge branch 'main' into deploy/nicolas
nicolasreisdev Dec 1, 2025
9b4360d
fix vercel error
nicolasreisdev Dec 1, 2025
55d4f8e
Merge branch 'deploy/nicolas' of https://github.com/nicolasreisdev/CT…
nicolasreisdev Dec 1, 2025
f79620e
refatoração para deploy do frontend
nicolasreisdev Dec 1, 2025
13764f4
feature de rotas públicas e privadas
nicolasreisdev Dec 1, 2025
a270960
refatoração para deploy
nicolasreisdev Dec 1, 2025
64912f8
Merge branch 'main' of https://github.com/nicolasreisdev/CTable into …
nicolasreisdev Dec 1, 2025
f69c198
update
nicolasreisdev Dec 2, 2025
9bf2c86
Merge branch 'main' of https://github.com/nicolasreisdev/CTable into …
nicolasreisdev Dec 2, 2025
b536912
Merge branch 'main' of https://github.com/nicolasreisdev/CTable into …
nicolasreisdev Dec 2, 2025
2564de3
update README
nicolasreisdev Dec 5, 2025
8ccf97a
fix coverage merge and errors
nicolasreisdev Dec 7, 2025
f63581d
adicionando componente common de loading, para melhor fluidez dos pro…
nicolasreisdev Dec 7, 2025
774e80c
fix vercel error
nicolasreisdev Dec 7, 2025
4af79c3
fix errors in test
nicolasreisdev Dec 7, 2025
6414548
Merge branch 'main' of https://github.com/nicolasreisdev/CTable into …
nicolasreisdev Dec 9, 2025
07f9424
add avatars and icons
nicolasreisdev Dec 9, 2025
ab59c11
updated
nicolasreisdev Dec 9, 2025
0bb1b8e
Merge branch 'main' into maintenance/front/nicolasreis
nicolasreisdev Dec 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions backend/src/business/businessLogicProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ class BusinessLogicProject{
if (keywordsToInsert.length > 0) {
await trx('ProjectsKeywords').insert(keywordsToInsert);

// --- NOVA LÓGICA DE ASSOCIAÇÃO AUTOMÁTICA ---

// 3. Busca Comunidades que usam essas mesmas Keywords
// Usamos .distinct() para evitar duplicatas (caso uma comunidade tenha React E Node, por exemplo)
const matchingCommunities = await trx('CommunitiesKeywords')
.whereIn('keywordID', keywordIDs.map(k => k.keywordID))
.distinct('communityID');
Expand Down Expand Up @@ -226,7 +222,6 @@ class BusinessLogicProject{
}

async getProjectById(projectId: string) {
// Busca o projeto com dados do autor (join)
const project = await knex('Projects')
.join('User', 'Projects.creatorID', '=', 'User.id')
.where('Projects.projectID', projectId)
Expand All @@ -242,13 +237,11 @@ class BusinessLogicProject{
throw new Error("Projeto não encontrado.");
}

// Busca as tecnologias (keywords) associadas
const keywords = await knex('ProjectsKeywords')
.join('Keywords', 'ProjectsKeywords.keywordID', '=', 'Keywords.keywordID')
.where('ProjectsKeywords.projectID', projectId)
.select('Keywords.tag');

// Retorna o objeto formatado
return {
...project,
technologies: keywords.map((k: any) => k.tag)
Expand Down
1 change: 0 additions & 1 deletion backend/src/data/migrations/20251121192246_Communities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export async function up(knex: Knex): Promise<void> {
table.timestamp('createdAt').defaultTo(knex.fn.now());
table.timestamp('updatedAt');

// Chave estrangeira para o criador (User)
table.integer('creatorID').unsigned();
table.foreign('creatorID')
.references('id')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ export async function up(knex: Knex): Promise<void> {
table.integer('userID').unsigned();
table.integer('communityID').unsigned();

table.string('role', 255).defaultTo('member'); // ex: 'admin', 'member'
table.string('role', 255).defaultTo('member');
table.timestamp('joinedAt').defaultTo(knex.fn.now());

// Chaves Estrangeiras
table.foreign('userID')
.references('id')
.inTable('User')
Expand All @@ -18,8 +17,7 @@ export async function up(knex: Knex): Promise<void> {
.references('communityID')
.inTable('Communities')
.onDelete('CASCADE');

// Chave Primária Composta (Um usuário só pode entrar na mesma comunidade uma vez)

table.primary(['userID', 'communityID']);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export async function up(knex: Knex): Promise<void> {
table.integer('communityID').unsigned();
table.integer('keywordID').unsigned();

// Chaves Estrangeiras
table.foreign('communityID')
.references('communityID')
.inTable('Communities')
Expand All @@ -16,7 +15,6 @@ export async function up(knex: Knex): Promise<void> {
.inTable('Keywords')
.onDelete('CASCADE');

// Chave Primária Composta
table.primary(['communityID', 'keywordID']);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export async function up(knex: Knex): Promise<void> {

table.timestamp('associatedAt').defaultTo(knex.fn.now());

// Chaves Estrangeiras
table.foreign('projectID')
.references('projectID')
.inTable('Projects')
Expand All @@ -18,7 +17,7 @@ export async function up(knex: Knex): Promise<void> {
.inTable('Communities')
.onDelete('CASCADE');

// Chave Primária Composta (Um projeto não pode ser linkado duas vezes na mesma comunidade)

table.primary(['projectID', 'communityID']);
});
}
Expand Down
3 changes: 1 addition & 2 deletions backend/src/middleware/errorHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';

export function errorHandler(err: unknown, req: Request, res: Response, next: NextFunction) {
// Verifica se o erro é do Zod

if (err instanceof z.ZodError) {
return res.status(400).json({
message: 'Erro de validação',
Expand All @@ -18,7 +18,6 @@ export function errorHandler(err: unknown, req: Request, res: Response, next: Ne

console.error(err);

// Retorna erro genérico para o usuário
return res.status(500).json({
message: 'Erro interno do servidor',
});
Expand Down
9 changes: 2 additions & 7 deletions backend/src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { request } from 'http';

const routes = express.Router();

// Endpoint para CADASTRAR um novo usuário
routes.post('/api/register', async (request, response) => {
console.log("Recebendo requisição de cadastro:", request.body);
const {user, token} = await RequestController.createUser(request.body);
Expand All @@ -17,7 +16,6 @@ routes.post('/api/register', async (request, response) => {
});
});

// Endpoint para verificar a existência de usuário
routes.post('/api/login', async(request, response) => {
const { user, token } = await RequestController.enterUser(request.body);
return response.status(200).json({
Expand All @@ -28,14 +26,13 @@ routes.post('/api/login', async(request, response) => {
});


// Endpoint para enviar ao fronend os keywords disponíveis

routes.get('/api/keywords', async(request, response) => {
const tags = await RequestController.getKeywords();

return response.status(200).json(tags);
});

// Endpoint para criar projeto
routes.post('/api/user/newproject', authMiddleware, async(request, response) =>{
const projectData = request.body;

Expand All @@ -50,7 +47,7 @@ routes.post('/api/user/newproject', authMiddleware, async(request, response) =>
});


// Endpoint para enviar ao frontend os projetos de determinado usuário

routes.get('/api/user/projects', authMiddleware, async(request, response) => {
const creatorID = request.user.id;
const projects = await RequestController.getUserProjects(creatorID);
Expand All @@ -59,7 +56,6 @@ routes.get('/api/user/projects', authMiddleware, async(request, response) => {
})
});

// Endpoint para atualizar um projeto existente
routes.put('/api/user/updateproject/:projectId', authMiddleware, async(request, response) => {
const { projectId } = request.params;
const updatedData = request.body;
Expand Down Expand Up @@ -92,7 +88,6 @@ routes.delete('/api/user/leavecommunity/:communityID', authMiddleware, async(req
return response.status(200).json(result);
})

// Endpoint para criar uma comunidade
routes.post('/api/newcommunity', authMiddleware, async(request, response) => {

const newCommunity = await RequestController.newCommunity(request.body, request.user.id);
Expand Down
4 changes: 2 additions & 2 deletions backend/src/test/community.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import request from 'supertest';
import app from '../app';
import knex from '../data';

let tokenAdmin: string; // Criador
let tokenUser: string; // Membro
let tokenAdmin: string;
let tokenUser: string;
let user1Id: number;
let user2Id: number;

Expand Down
4 changes: 2 additions & 2 deletions backend/src/test/profile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ describe('Fluxo de Perfil de Usuário', () => {
const response = await request(app)
.put('/api/user/editprofile')
.set('Authorization', `Bearer ${token}`)
.send({}); // Objeto vazio
.send({});

// O controller deve lançar erro "Nenhum dado para atualizar"

expect(response.status).not.toBe(200);
});
});
Expand Down
18 changes: 6 additions & 12 deletions backend/src/test/project.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ describe('Fluxo de Projetos', () => {
expect(response.body.project).toHaveProperty('projectID');
expect(response.body.project.title).toBe('Meu Projeto React');

// Verifica se salvou no banco
const projectDb = await knex('Projects').where({ title: 'Meu Projeto React' }).first();
expect(projectDb).toBeDefined();
});
Expand All @@ -90,15 +89,14 @@ describe('Fluxo de Projetos', () => {
});

it('deve atualizar um projeto existente (Status 200)', async () => {
// Cria projeto

const resCreate = await request(app)
.post('/api/user/newproject')
.set('Authorization', `Bearer ${tokenUser1}`)
.send({ title: 'Antigo', description: 'Desc', status: 'Aberto', startDate: new Date() });

const projectId = resCreate.body.project.projectID;

// Atualiza
const response = await request(app)
.put(`/api/user/updateproject/${projectId}`)
.set('Authorization', `Bearer ${tokenUser1}`)
Expand Down Expand Up @@ -217,19 +215,18 @@ describe('Fluxo de Projetos', () => {
});

it('deve impedir exclusão de comentário por quem não é o autor', async () => {
// User 1 cria projeto

const resProj = await request(app).post('/api/user/newproject')
.set('Authorization', `Bearer ${tokenUser1}`)
.send({ title: 'Post', description: '...', status: 'Aberto', startDate: new Date() });
const pId = resProj.body.project.projectID;

// User 1 comenta

const resComment = await request(app).post(`/api/project/${pId}/comments`)
.set('Authorization', `Bearer ${tokenUser1}`)
.send({ content: 'Meu comentário' });
const cId = resComment.body.commentID;

// User 2 tenta deletar
const response = await request(app)
.delete(`/api/project/${cId}/deletecomment`)
.set('Authorization', `Bearer ${tokenUser2}`);
Expand All @@ -239,7 +236,7 @@ describe('Fluxo de Projetos', () => {

it('deve retornar 404 ao buscar projeto inexistente', async () => {
const response = await request(app)
.get('/api/projects/999999') // ID que não existe
.get('/api/projects/999999')
.set('Authorization', `Bearer ${tokenUser1}`);

expect(response.status).toBe(404);
Expand Down Expand Up @@ -298,29 +295,26 @@ describe('Fluxo de Projetos', () => {
.set('Authorization', `Bearer ${tokenUser2}`)
.send({ content: 'Segundo!' });

// Busca comentários
const response = await request(app).get(`/api/project/${projectId}/comments`);

expect(response.status).toBe(200);
expect(response.body).toHaveLength(2);
});

it('deve deletar um comentário próprio com sucesso', async () => {
// Cria comentário

const commRes = await request(app).post(`/api/project/${projectId}/comments`)
.set('Authorization', `Bearer ${tokenUser1}`)
.send({ content: 'Vou deletar' });
const commentId = commRes.body.commentID;

// Deleta
const response = await request(app)
.delete(`/api/project/${commentId}/deletecomment`)
.set('Authorization', `Bearer ${tokenUser1}`);

expect(response.status).toBe(200);
expect(response.body.message).toBe('Comentário deletado com sucesso.');

// Verifica no banco
const comments = await request(app).get(`/api/project/${projectId}/comments`);
expect(comments.body).toHaveLength(0);
});
Expand All @@ -346,7 +340,7 @@ describe('Fluxo de Projetos', () => {
expect(response.status).toBe(200);
expect(response.body).toHaveLength(2);

// Verifica se o título do projeto vem junto (conforme businessLogicProject.getUserComments)

const titulos = response.body.map((c: any) => c.projectTitle);
expect(titulos).toContain('Discussão');
expect(titulos).toContain('Outro Projeto');
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/utils/getAvatarurl.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Aceita um segundo parâmetro opcional 'style'

export function getAvatarUrl(seed: string, style: 'bottts' | 'identicon' = 'bottts') {
// Se não passar nada, usa 'bottts' (robôs)
// Se passar 'identicon', usa os padrões geométricos

return `https://api.dicebear.com/9.x/${style}/svg?seed=${seed}`;
}
Loading