From a6bc28bbe3135212ccfd0e6fdbc28d44539a9abe Mon Sep 17 00:00:00 2001 From: Karina Date: Tue, 18 Aug 2026 12:34:14 -0300 Subject: [PATCH] =?UTF-8?q?docs:=20atualiza=C3=A7=C3=A3o=20e=20melhorias?= =?UTF-8?q?=20na=20documenta=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../governanca-dados/governanca-dados-lgpd.md | 314 ++++++- docs/01 - estrategia/visao/visao-produto.md | 201 +++-- .../adminstrativo/painel-administrativo.md | 206 ++++- .../dashboard-membro/dashboard-membro.md | 215 +++++ .../estado-das-funcionalidades.md | 248 +++--- .../feedback/feedback-reputacao.md | 766 +++++++++++++----- docs/02 - produto/portfolio/portfolio.md | 497 ++++++------ docs/03 - tecnico/adrs/adrs.md | 275 ++++++- .../arquitetura-geral-atualizado.md | 145 ---- .../arquitetura/arquitetura-geral.md | 227 +++++- .../03 - tecnico/modelagem/modelagem-dados.md | 419 +++++----- 11 files changed, 2440 insertions(+), 1073 deletions(-) create mode 100644 docs/02 - produto/dashboard-membro/dashboard-membro.md delete mode 100644 docs/03 - tecnico/arquitetura/arquitetura-geral-atualizado.md diff --git a/docs/01 - estrategia/governanca-dados/governanca-dados-lgpd.md b/docs/01 - estrategia/governanca-dados/governanca-dados-lgpd.md index 73d51fb2..8010d6af 100644 --- a/docs/01 - estrategia/governanca-dados/governanca-dados-lgpd.md +++ b/docs/01 - estrategia/governanca-dados/governanca-dados-lgpd.md @@ -1,37 +1,279 @@ -# Documento Estratégico --- Governança de Dados e LGPD - -Classificação: Documento Estratégico\ -Camada: 1 --- Estratégia - +# Documento Estratégico — Governança de Dados e LGPD + +**Classificação:** Documento Estratégico +**Camada:** 1 — Documentos Estratégicos +**Status:** Versão 2 — expandido para cobrir dados de reputação + +> ⚠️ **Este documento não é parecer jurídico.** Ele registra decisões de produto e +> engenharia sobre tratamento de dados pessoais e a interpretação adotada pelo +> projeto. Antes de a plataforma operar com base ampla de usuários reais, o +> conteúdo deve ser revisado por profissional habilitado — especialmente as +> seções 4 (bases legais) e 7 (direitos do titular). + +--- + ## 1. Objetivo - -Estabelecer princípios de proteção de dados e conformidade com LGPD. - -## 2. Dados Coletados - -- Dados cadastrais básicos. -- Dados de participação em projetos. -- Feedbacks vinculados a projetos. - -## 3. Princípios - -- Minimização de dados. -- Finalidade explícita. -- Transparência. -- Registro de auditoria. - -## 4. Segurança - -- Autenticação segura. -- Controle de permissões por papel. -- Logs de ações críticas. - -## 5. Direitos do Usuário - -- Solicitação de exclusão de conta. -- Acesso aos próprios dados. -- Correção de dados pessoais. - -## 6. Evolução - -A maturidade de conformidade será ampliada progressivamente. + +Estabelecer os princípios de proteção de dados do TryCatch e as regras concretas +de tratamento, retenção e exclusão, com atenção particular aos **dados de +reputação** — que são a categoria mais sensível da plataforma, por serem +informação pessoal produzida por terceiros sobre uma pessoa identificada. + +Este documento governa decisões de produto, arquitetura e comunicação. Ele não +descreve implementação. + +--- + +## 2. Escopo + +Cobre: + +- Categorias de dados tratados; +- Finalidade de cada tratamento; +- Regras de retenção e exclusão; +- Direitos do titular e como são atendidos; +- Tratamento de dados de reputação e feedback; +- Compromissos de segurança e auditoria. +Fora de escopo: + +- Implementação técnica de criptografia, backup ou infraestrutura; +- Redação final de termos de uso e política de privacidade (derivam deste + documento); +- Contratos com operadores e subprocessadores. +--- + +## 3. Categorias de dados tratados + +| Categoria | Exemplos | Origem | Sensibilidade | +|---|---|---|---| +| Cadastrais | nome, e-mail, username, avatar | Titular | Média | +| Perfil profissional | bio, skills, certificados, GitHub, LinkedIn | Titular | Baixa (publicação voluntária) | +| Disponibilidade | dias e horários | Titular | Baixa | +| Participação | projetos, stacks assumidas, entregas | Sistema | Média | +| **Reputação** | **corroborações e feedback escrito recebidos** | **Terceiros** | **Alta** | +| Acesso e auditoria | logs estruturados com identificadores | Sistema | Média | +| Convites | e-mail, quem convidou, data de uso | Titular e ADMIN | Média | + +**A categoria de reputação recebe tratamento diferenciado ao longo deste +documento** porque combina três características que nenhuma outra reúne: é +produzida por outra pessoa, descreve conduta de um indivíduo identificado, e pode +ter efeito sobre oportunidades profissionais. + +--- + +## 4. Bases legais adotadas + +| Tratamento | Base legal adotada | +|---|---| +| Cadastro e autenticação | Execução de contrato (uso da plataforma) | +| Perfil e portfólio público | Consentimento — controlado por toggles granulares | +| Participação em projetos | Execução de contrato | +| Feedback e corroborações | Legítimo interesse, com salvaguardas descritas na seção 6 | +| Logs e auditoria | Legítimo interesse (segurança e rastreabilidade) | +| E-mails transacionais | Execução de contrato | + +> ⚠️ A base de legítimo interesse para feedback é a que mais exige validação +> jurídica. Ela pressupõe: finalidade legítima e informada, mínimo necessário, +> expectativa razoável do titular e possibilidade de oposição. As salvaguardas da +> seção 6 existem justamente para sustentá-la. + +--- + +## 5. Princípios + +- **Minimização** — coletar apenas o necessário para a finalidade declarada; +- **Finalidade explícita** — nenhum dado coletado para um fim é reaproveitado em + outro sem nova base; +- **Transparência** — a pessoa sabe o que é coletado, por quem é visto e o que + acontece se ela sair; +- **Controle do titular** — visibilidade pública é sempre opt-in ou reversível; +- **Não exposição de identificador interno** — `id` nunca aparece em rota pública; +- **Rastreabilidade** — ações críticas registradas em log estruturado, sem + conteúdo pessoal; +- **Não punitividade** — dado de reputação não é usado para restringir acesso. +--- + +## 6. Regras específicas de dados de reputação + +Esta seção resolve a contradição existente entre a garantia de exclusão de conta +e a regra de imutabilidade do feedback. + +### 6.1 O conflito + +- Este documento garante ao titular a exclusão de sua conta. +- O documento de Feedback determina que feedback não é editável nem excluível. +Ambas as regras são corretas isoladamente e incompatíveis se aplicadas ao mesmo +conjunto de dados sem distinção. + +### 6.2 A distinção que resolve + +**Um registro de feedback contém dados pessoais de duas pessoas diferentes, com +titularidades distintas:** + +- para o **avaliado**, o conteúdo é dado sobre si; +- para o **avaliador**, a autoria é dado sobre si. +A pessoa que sai da plataforma é titular do que **recebeu**, não do que **deu** +sobre outras pessoas. + +### 6.3 Regra adotada — anonimização assimétrica + +Ao excluir a conta: + +| Dado | Destino | Por quê | +|---|---|---| +| Feedbacks recebidos (texto) | **Excluídos** | São dados sobre o titular | +| Corroborações recebidas | **Excluídas** | Idem | +| Feedbacks dados a terceiros (texto) | **Preservados**, autoria anonimizada | São dados sobre outras pessoas | +| Corroborações dadas a terceiros | **Preservadas**, autoria anonimizada | Idem | +| Contadores das outras pessoas | **Recalculados** | O atestado continua contando como "1 pessoa", sem vínculo | + +O campo `fromUserId` é substituído por marcador de conta removida. **A +anonimização é irreversível.** + +### 6.4 Por que a autoria não pode simplesmente ser apagada junto + +Apagar as avaliações que a pessoa deu implicaria que qualquer participante pode +destruir a reputação construída por seus colegas apenas encerrando a própria +conta. Isso transformaria a exclusão de conta em vetor de dano a terceiros. + +### 6.5 Dever de informação prévia + +**Esta regra deve ser comunicada antes da avaliação, não no momento da saída.** + +Obrigatório constar em: + +- Termos de uso; +- FAQ (`conteudos-informativos-e-educacionais.md`); +- Tela de avaliação, em texto curto e visível. +Texto de referência: + +> As avaliações que você deixa para outras pessoas permanecem na plataforma mesmo +> que você encerre sua conta, sem sua identificação. As avaliações que você +> recebeu são apagadas junto com a conta. + +### 6.6 Identidade do avaliador + +- Registrada de forma permanente enquanto a conta existir; +- **Nunca exibida publicamente**; +- **Nunca exibida ao avaliado**; +- Acessível a ADMIN somente mediante denúncia ou apuração de conduta, com o acesso + registrado em log. +### 6.7 Direito de oposição + +O titular pode: + +- desativar a exibição pública de toda a reputação (`showFeedback = false`); +- solicitar apuração de feedback que considere abusivo, desrespeitoso ou falso. +Feedback que viole as regras da plataforma é **ocultado** por ADMIN, com registro +de motivo — nunca editado. Ocultação remove o registro de qualquer agregação +pública. + +O titular **não pode** excluir seletivamente feedback verdadeiro que não lhe +agrade: isso esvaziaria a finalidade do sistema. O controle disponível é ligar ou +desligar o bloco inteiro. + +### 6.8 Publicação de texto + +Texto de feedback só se torna público quando **as duas condições** se cumprem: + +1. o autor autorizou a publicação no momento da escrita; +2. o avaliado optou por exibi-lo. +Nenhuma das duas partes publica sozinha. + +--- + +## 7. Direitos do titular e como são atendidos + +| Direito | Como é atendido | Status | +|---|---|---| +| Acesso aos próprios dados | Dashboard privado + exportação | 🔴 exportação não implementada | +| Correção | Edição de perfil e portfólio | 🟢 | +| Exclusão de conta | Fluxo de exclusão com regra da seção 6.3 | 🔴 não implementado | +| Portabilidade | Exportação em formato legível | 🔴 não implementado | +| Oposição | Toggles de visibilidade; denúncia de feedback | 🟡 parcial | +| Informação sobre tratamento | Termos, FAQ, avisos em tela | 🟡 parcial | + +> ⚠️ **Divergência conhecida, registrada conforme Documento 0, seção 4:** a versão +> anterior deste documento afirmava que a exclusão de conta era um direito +> atendido. **Ela não está implementada.** A afirmação foi corrigida acima. +> Enquanto o fluxo não existir, pedidos de exclusão devem ser tratados +> manualmente por ADMIN, seguindo a regra 6.3, com registro da execução. + +--- + +## 8. Retenção + +| Dado | Retenção | +|---|---| +| Conta ativa | Enquanto durar o vínculo | +| Dados de conta excluída | Removidos, exceto o previsto em 6.3 | +| Feedback anonimizado | Indeterminado (deixou de ser dado pessoal do autor) | +| Logs estruturados | Prazo a definir — **decisão em aberto** | +| Convites usados | Mantidos para auditoria, com e-mail anonimizável a pedido | +| InviteRequest rejeitada | Prazo a definir — **decisão em aberto** | + +--- + +## 9. Segurança + +- Autenticação via NextAuth com senha em hash; +- Controle de permissão por papel (`ADMIN`, `USER`, `MENTOR`) verificado no + backend em toda rota; +- Logs estruturados sem senha, token, e-mail completo ou conteúdo pessoal — + registram identificadores, não conteúdo; +- Portfólio privado retorna 404 idêntico ao de usuário inexistente, não revelando + existência de conta; +- Objeto `User` do Prisma nunca retornado íntegro em resposta de API. +> ⚠️ **Dívida conhecida:** nenhuma rota usa `select`/`omit` do Prisma atualmente, +> e objetos `User` saem com hash de senha (ver SEC-03). Isso **contradiz o +> compromisso acima** e é falha de segurança ativa, não apenas dívida técnica. +> Correção prioritária. + +--- + +## 10. Relação com outros documentos + +Orienta: + +- `docs/02 - produto/feedback/feedback-reputacao.md` +- `docs/02 - produto/portfolio/portfolio.md` +- `docs/02 - produto/conteudos/conteudos-informativos-e-educacionais.md` +- `docs/03 - tecnico/modelagem/modelagem-dados.md` +Alinhado a: + +- Documento 0 — Visão Geral, Governança e Arquitetura da Documentação; +- Documento Estratégico — Planejamento de Qualidade de Software; +- Documento Estratégico — Acessibilidade e Inclusão Digital. +--- + +## 11. Antipadrões + +- Coletar dado "porque pode ser útil depois"; +- Publicar dado pessoal por padrão sem opt-in; +- Tratar feedback como dado exclusivo do avaliado ou exclusivo do avaliador; +- Permitir que a saída de uma pessoa apague reputação de terceiros; +- Informar regra de retenção apenas no momento da exclusão; +- Registrar conteúdo pessoal em log; +- Prometer direito não implementado. +--- + +## 12. Decisões em aberto + +- Prazo de retenção de logs; +- Prazo de retenção de `InviteRequest` rejeitada; +- Formato da exportação de dados; +- Existe fluxo de denúncia de feedback pelo avaliado? (afeta painel admin) +- Validação jurídica das bases legais da seção 4. +--- + +## 13. Histórico de decisões + +| Versão | Decisão | +|---|---| +| v1 | Princípios gerais de minimização, finalidade e auditoria | +| v2 | Reputação reconhecida como categoria de sensibilidade alta | +| v2 | Adotada anonimização assimétrica na exclusão de conta | +| v2 | Definido dever de informação prévia sobre permanência do feedback dado | +| v2 | Publicação de texto exige consentimento das duas partes | +| v2 | Corrigida afirmação sobre exclusão de conta — direito ainda não implementado | +| v2 | Registrada contradição entre compromisso de proteção e a dívida SEC-03 | \ No newline at end of file diff --git a/docs/01 - estrategia/visao/visao-produto.md b/docs/01 - estrategia/visao/visao-produto.md index 9560c3ca..c48c1c3e 100644 --- a/docs/01 - estrategia/visao/visao-produto.md +++ b/docs/01 - estrategia/visao/visao-produto.md @@ -1,121 +1,160 @@ -# Documento Estratégico --- Visão e Hipótese do Produto - -**Classificação:** Documento Estratégico\ -**Camada:** 1 --- Documentos Estruturais\ -**Status:** Versão inicial consolidada - +# Documento Estratégico — Visão e Hipótese do Produto + +**Classificação:** Documento Estratégico +**Camada:** 1 — Documentos Estruturais +**Status:** Versão 2 — escopo negativo esclarecido + --- - + ## 1. Objetivo do Documento - -Este documento define a visão estratégica do TryCatch e formaliza sua -hipótese principal de produto. - + +Este documento define a visão estratégica do TryCatch e formaliza sua hipótese +principal de produto. + Ele estabelece: - + - O problema central que o produto busca resolver; - O público prioritário; - A proposta de valor; - As hipóteses que deverão ser validadas por meio de métricas. - -Este documento é estrutural e orienta todas as decisões de produto, -arquitetura, comunicação e qualidade. - +Este documento é estrutural e orienta todas as decisões de produto, arquitetura, +comunicação e qualidade. + --- - + ## 2. Visão do Produto - -O TryCatch é uma plataforma colaborativa que conecta desenvolvedores em -diferentes níveis de experiência para desenvolver projetos reais de -forma estruturada, com mentoria, rastreabilidade e foco em qualidade. - -A plataforma busca unir: -- Desenvolvedores iniciantes; -- Desenvolvedores intermediários; -- Mentores experientes; + +O TryCatch é uma plataforma colaborativa que conecta desenvolvedores em diferentes +níveis de experiência para desenvolver projetos reais de forma estruturada, com +mentoria, rastreabilidade e foco em qualidade. + +A plataforma busca unir: + +- Desenvolvedores iniciantes; +- Desenvolvedores intermediários; +- Mentores experientes; - Projetos reais com propósito claro. - -A visão é criar um ambiente onde aprendizado prático, colaboração -profissional e desenvolvimento técnico coexistam com governança e -documentação estruturada. - +A visão é criar um ambiente onde aprendizado prático, colaboração profissional e +desenvolvimento técnico coexistam com governança e documentação estruturada. + --- - + ## 3. Público Prioritário - -O público principal do TryCatch é composto por: - + - Desenvolvedores iniciantes em busca de experiência prática; - Desenvolvedores intermediários que desejam evoluir tecnicamente; - Desenvolvedores experientes interessados em mentoria; - Organizações interessadas em acompanhar talentos em formação. - --- - + ## 4. Problema Central Identificado - -Desenvolvedores iniciantes frequentemente enfrentam dificuldades para: - + +Desenvolvedores iniciantes frequentemente enfrentam dificuldade para: + - Encontrar projetos reais para praticar; - Trabalhar em equipe com processos organizados; - Receber feedback estruturado e confiável; - Demonstrar evolução profissional com evidências concretas. - -Simultaneamente, mentores carecem de ambientes estruturados para -orientar iniciantes com rastreabilidade e critérios claros. - +Simultaneamente, mentores carecem de ambientes estruturados para orientar +iniciantes com rastreabilidade e critérios claros. + +### 4.1 Agravante recente — a erosão do código como evidência + +Ferramentas de IA generativa produzem projetos completos com pouco esforço. O +repositório deixou de distinguir quem sabe colaborar de quem soube pedir. + +Isso **aumenta** a relevância da hipótese do produto: o que passa a ter valor +demonstrável não é o artefato, é a **conduta observável em trabalho conjunto** — +comunicar impedimento, cumprir o combinado, apoiar a equipe, perguntar antes de +decidir. Nada disso uma ferramenta faz pela pessoa. + +O sistema de reputação da plataforma existe para registrar exatamente isso. Ver +`docs/02 - produto/feedback/feedback-reputacao.md`. + --- - + ## 5. Hipótese Principal do Produto - -Acreditamos que desenvolvedores em diferentes níveis de experiência -precisam de um ambiente estruturado para colaborar em projetos reais, e -que ao utilizar o TryCatch conseguirão desenvolver habilidades técnicas -e comportamentais com maior evidência prática, medido por: - + +Acreditamos que desenvolvedores em diferentes níveis de experiência precisam de um +ambiente estruturado para colaborar em projetos reais, e que ao utilizar o +TryCatch conseguirão desenvolver habilidades técnicas e comportamentais com maior +evidência prática, medido por: + - Participação recorrente em projetos; -- Evolução de reputação ao longo do tempo; +- Acúmulo de evidências de conduta colaborativa ao longo do tempo; - Retenção ativa na plataforma; -- Feedbacks positivos relacionados à colaboração e entrega. - +- Volume e consistência de corroborações relacionadas a colaboração e entrega. +> ⚠️ **Correção de linguagem.** A v1 falava em "evolução de reputação" e +> "feedbacks positivos", o que sugeria escala e nota. O modelo adotado não produz +> nota. A métrica é acúmulo de evidência, não elevação de pontuação. + --- - -## 6. Escopo Estratégico (O que o TryCatch é) - -- Uma plataforma colaborativa para desenvolvimento de projetos reais; -- Um ambiente estruturado com governança e documentação; -- Um modelo replicável de organização de projetos colaborativos. - + +## 6. Escopo Estratégico (o que o TryCatch é) + +- Plataforma colaborativa para desenvolvimento de projetos reais; +- Ambiente estruturado com governança e documentação; +- Modelo replicável de organização de projetos colaborativos. --- - -## 7. Escopo Negativo (O que o TryCatch não é) - + +## 7. Escopo Negativo (o que o TryCatch não é) + - Não é uma plataforma freelance aberta; - Não é uma rede social genérica; - Não é um marketplace de vagas; - Não é um curso formal ou LMS tradicional. - +### 7.1 Esclarecimento sobre projetos remunerados + +Havia divergência entre este documento e o produto: aqui se declarava que o +TryCatch não é marketplace, enquanto a entidade `Project` possui `totalValue` e o +template de cadastro externo pergunta forma de pagamento e responsabilidade por +custos. + +**Não é contradição, é falta de distinção. A distinção é esta:** + +| O TryCatch faz | O TryCatch não faz | +|---|---| +| Registra que um projeto tem valor associado, quando tem | Intermediar pagamento | +| Torna transparente se há remuneração, mentoria ou apoio | Garantir remuneração a participante | +| Permite divisão transparente de responsabilidades | Processar transação financeira | +| Deixa a negociação entre as partes, com regras visíveis | Atuar como marketplace ou empregador | + +**Regras derivadas:** + +1. `totalValue` é **informação declarada**, não transação; +2. A plataforma não processa pagamento nem retém valor; +3. Nenhuma comunicação pode prometer remuneração, contratação ou vaga; +4. A ausência de remuneração é o caso comum e deve ser tratada como normal, nunca + como projeto inferior; +5. Responsabilidade por custos externos é declarada no cadastro e é das partes. +Isso mantém o escopo negativo válido: registrar valor não é intermediar valor. + --- - + ## 8. Relação com Outros Documentos - -Este documento orienta diretamente: - -- Documento 0 --- Visão Geral e Governança da Documentação; + +Orienta diretamente: + +- Documento 0 — Visão Geral e Governança da Documentação; - Planejamento de Qualidade de Software; - Documentos de Produto (Camada 2); - Documentos Técnicos (Camada 3); - Plano Geral de Comunicação. - --- - + ## 9. Evolução do Documento - -Este documento pode evoluir caso: - -- O público prioritário seja alterado; -- O modelo estratégico mude; -- A hipótese principal seja invalidada ou refinada com base em - métricas. - -Mudanças estruturais exigem registro formal de decisão. + +Pode evoluir caso o público prioritário mude, o modelo estratégico se altere ou a +hipótese principal seja invalidada ou refinada por métricas. Mudanças estruturais +exigem registro formal. + +--- + +## 10. Histórico + +| Versão | Alteração | +|---|---| +| v1 | Versão inicial consolidada | +| v2 | Esclarecida a relação entre `totalValue` e o escopo negativo de marketplace | +| v2 | Registrado o agravante da erosão do código como evidência | +| v2 | Corrigida a linguagem de métrica: acúmulo de evidência, não elevação de nota | \ No newline at end of file diff --git a/docs/02 - produto/adminstrativo/painel-administrativo.md b/docs/02 - produto/adminstrativo/painel-administrativo.md index e37b5b01..31a5b337 100644 --- a/docs/02 - produto/adminstrativo/painel-administrativo.md +++ b/docs/02 - produto/adminstrativo/painel-administrativo.md @@ -1,22 +1,186 @@ -# Documento de Produto --- Painel Administrativo - -Classificação: Documento de Produto\ -Camada: 2 --- Produto - -**Status do documento:** consolidado -**Status da implementação:** 🟢 completa — painel e subtelas em uso +# Documento de Produto — Painel Administrativo + +**Classificação:** Documento de Produto / Funcionalidade +**Camada:** 2 — Documentos de Produto e Funcionalidades +**Status do documento:** Expandido — versão anterior tinha 12 linhas +**Status da implementação:** 🟢 completa para o escopo atual — moderação de feedback pendente **Estado consolidado:** ver [estado-das-funcionalidades.md](../estado-das-funcionalidades.md) - -## 1. Objetivo - -Centralizar gestão de usuários, convites e cadastros. - -## 2. Funcionalidades - -- Criar e invalidar convites. -- Gerenciar usuários. -- Cadastrar skills e stacks. - -## 3. Segurança - -Acesso restrito a administradores. + +--- + +## 1. Identificação + +- **Nome:** Painel Administrativo +- **Rota base:** `/dashboard/admin` +- **Domínio:** Governança e operação da plataforma +- **Papel exigido:** `ADMIN` +- **Documentos relacionados:** Convites; Solicitação de Convite; Permissões e + Papéis; Gestão de Skills; Gestão de Stacks; Feedback e Reputação; Governança de + Dados e LGPD +--- + +## 2. Contexto e objetivo + +O TryCatch tem acesso controlado por convite. Isso significa que existe uma +camada operacional permanente — aprovar solicitações, emitir convites, manter os +cadastros de referência — sem a qual a plataforma não recebe ninguém. + +O painel centraliza essa operação. Ele existe para: + +- controlar a entrada de novos membros; +- manter os catálogos de skills e stacks que sustentam a formação de equipes; +- apurar conduta quando houver denúncia; +- dar rastreabilidade a ações administrativas. +**O painel não é ferramenta de vigilância.** Ele não expõe atividade de membro +além do necessário para a operação e para a apuração de conduta. + +--- + +## 3. Escopo + +### 3.1 O que faz + +**Convites** + +- Criar convite com código único, vinculado a e-mail e papel inicial; +- Listar convites com estado (ativo, utilizado); +- Invalidar convite não utilizado; +- Consultar quem criou cada convite (`invitedBy`) e quando foi usado (`usedAt`). +**Solicitações de convite** + +- Listar solicitações com status `PENDING`, `APPROVED`, `REJECTED`; +- Aprovar ou rejeitar, preservando o registro histórico; +- Gerar convite a partir de solicitação aprovada. +**Usuários** + +- Listar e consultar membros; +- Ativar e desativar conta (`isActive`); +- Aprovar solicitação de mudança de papel (`RoleRequest`). +**Catálogos** + +- CRUD de `Skill`; +- CRUD de `Stack`. +### 3.2 O que não faz + +- Não edita perfil, bio, portfólio ou configuração de visibilidade de terceiros; +- Não edita nem exclui conteúdo de feedback (ver 3.3); +- Não altera papel sem registro; +- Não acessa senha (armazenada apenas em hash); +- Não exibe métrica de membro individual sem finalidade operacional; +- Não exclui projeto de terceiro sem procedimento formal. +### 3.3 Escopo pendente — moderação de feedback + +🔴 **Não implementado. Requer decisão de produto.** + +O modelo de feedback v2 pressupõe que ADMIN possa: + +- consultar a autoria de um feedback **mediante denúncia**, com o acesso + registrado em log; +- **ocultar** feedback que viole as regras da plataforma, com motivo registrado — + nunca editar o conteúdo; +- ver o efeito da ocultação nas agregações públicas. +**Decisões em aberto:** existe fluxo de denúncia acionado pelo avaliado? Quem +apura? Há direito de resposta do avaliador? Prazo? + +Ver `docs/02 - produto/feedback/feedback-reputacao.md`, seções 7 e 16. + +--- + +## 4. Permissões + +| Ação | Papel | +|---|---| +| Acessar o painel | `ADMIN` | +| Criar e invalidar convite | `ADMIN` | +| Aprovar solicitação de convite | `ADMIN` | +| Aprovar mudança de papel | `ADMIN` | +| CRUD de skills e stacks | `ADMIN` | +| Consultar autoria de feedback | `ADMIN`, mediante denúncia | +| Ocultar feedback | `ADMIN`, com motivo | + +Verificação de papel via `checkAuth` no backend, em toda rota. **Ocultar o link no +frontend não é controle de acesso.** + +--- + +## 5. Regras de negócio + +1. Toda ação administrativa é registrada em log estruturado com identificador do + ADMIN, ação e alvo — nunca com conteúdo pessoal. +2. Convite é vinculado a um e-mail; `code` é único; `used = true` impede reuso. +3. Rejeição de solicitação preserva o registro — não apaga. +4. Mudança de papel exige registro e é reversível apenas por novo registro. +5. Desativar conta (`isActive = false`) torna o portfólio inacessível (404) e + **não** exclui dados — exclusão segue o fluxo da LGPD. +6. ADMIN não edita conteúdo produzido por membro. Pode ocultar, nunca reescrever. +7. Consulta de autoria de feedback exige motivo registrado. +--- + +## 6. Impactos em dados + +Entidades: `Invite`, `InviteRequest`, `User`, `RoleRequest`, `Skill`, `Stack`, +`Feedback` (somente ocultação). + +Rastreabilidade: `invitedBy`, `usedAt`, status de solicitação, histórico de +mudança de papel, motivo de ocultação de feedback. + +--- + +## 7. Segurança e riscos + +| Risco | Mitigação | +|---|---| +| Convite `ADMIN` usado indevidamente | Criação restrita; monitoramento de convites com papel elevado | +| Elevação indevida de privilégio | Aprovação exclusiva de ADMIN, com registro | +| Acesso a autoria de feedback sem motivo | Exige denúncia; acesso logado | +| Ação administrativa sem rastro | Log obrigatório | +| Desativação usada como punição informal | Motivo registrado; não substitui apuração | + +--- + +## 8. Comunicação com o usuário + +- Aprovação de solicitação gera e-mail com o convite; +- Rejeição deve ser comunicada de forma respeitosa e sem julgamento — o Plano + Geral de Comunicação proíbe tom punitivo; +- Ocultação de feedback deve ser comunicada às duas partes, com motivo objetivo; +- Mudança de papel deve ser comunicada ao titular. +> 🔴 Nem todas essas comunicações existem hoje. Verificar contra +> `docs/03 - tecnico/adrs.md` (ADR-004) antes de assumir que o template existe. + +--- + +## 9. Antipadrões evitados + +- ADMIN editando conteúdo de membro; +- Ação administrativa sem log; +- Controle de acesso baseado em esconder botão no frontend; +- Exclusão de registro histórico de solicitação; +- Exposição de atividade de membro sem finalidade operacional; +- Desativação silenciosa de conta. +--- + +## 10. Métricas relacionadas + +- Taxa de aprovação de solicitações; +- Tempo médio entre solicitação e resposta; +- Conversão convite → cadastro; +- Distribuição de papel inicial; +- Volume de denúncias de feedback (quando existir). +--- + +## 11. Decisões em aberto + +- Fluxo de denúncia de feedback; +- Direito de resposta do avaliador em caso de ocultação; +- Existe papel de moderador distinto de `ADMIN`? +- Exclusão de conta: executada manualmente por ADMIN até o fluxo existir — falta + procedimento documentado. +--- + +## 12. Histórico + +| Versão | Alteração | +|---|---| +| Inicial | Três seções, doze linhas | +| Atual | Expandido: permissões, regras, riscos, comunicação, antipadrões; registrada a lacuna de moderação de feedback | \ No newline at end of file diff --git a/docs/02 - produto/dashboard-membro/dashboard-membro.md b/docs/02 - produto/dashboard-membro/dashboard-membro.md new file mode 100644 index 00000000..e6686a11 --- /dev/null +++ b/docs/02 - produto/dashboard-membro/dashboard-membro.md @@ -0,0 +1,215 @@ +# Documento de Produto — Dashboard do Membro + +**Classificação:** Documento de Produto / Funcionalidade +**Camada:** 2 — Documentos de Produto e Funcionalidades +**Status do documento:** Versão inicial proposta — requer validação +**Status da implementação:** 🔴 não iniciada — `/dashboard` é placeholder de 24 linhas +**Estado consolidado:** ver [estado-das-funcionalidades.md](../estado-das-funcionalidades.md) + +> 📌 **Este documento preenche uma lacuna.** Existe o épico +> [#630](https://github.com/TryCatch-ForMatch/trycatch/issues/630) com as issues +> #631, #635, #636 e #637, mas nenhum documento de produto correspondente — o que +> viola o Documento 0, seção 4 ("nenhuma funcionalidade deve existir sem +> documentação mínima"). + +--- + +## 1. Identificação + +- **Nome:** Dashboard do Membro +- **Rota:** `/dashboard` +- **Domínio:** Experiência do membro autenticado +- **Épico:** #630 +- **Documentos relacionados:** Feedback e Reputação; Gestão de Projetos; + Portfólio; Perfis de Usuário; Jornada de Entrada +--- + +## 2. Contexto e objetivo + +`/dashboard` é a **primeira tela que a pessoa vê ao entrar na plataforma** e hoje +é um placeholder. + +O impacto disso é maior do que parece. Alguém que solicitou convite, esperou +aprovação, criou conta e fez login chega a uma tela vazia. Todo o esforço de +comunicação institucional — Home, How-to-Join, textos de CTA — desemboca aqui. + +**Objetivo:** responder três perguntas, nesta ordem de prioridade: + +1. **O que eu preciso fazer agora?** (pendências acionáveis) +2. **Onde eu estou?** (projetos ativos, participação) +3. **Como estou sendo percebido?** (feedback recebido, estado do portfólio) +**Antiobjetivo:** o dashboard não é painel de métricas nem vitrine de progresso +gamificada. Ele orienta ação. + +--- + +## 3. Escopo + +### 3.1 O que faz + +- Exibe pendências que dependem de ação da pessoa; +- Lista projetos em que ela participa, com status; +- Mostra estado de completude do perfil e do portfólio; +- Indica feedback novo recebido (contagem, respeitado o blind duplo); +- Oferece atalhos para as áreas privadas. +### 3.2 O que não faz + +- Não exibe pontuação, nível, streak ou qualquer elemento de gamificação; +- Não exibe ranking nem comparação com outros membros; +- Não exibe métricas de plataforma (isso é painel administrativo); +- Não substitui `/dashboard/portfolio`, `/dashboard/feedbacks` ou a listagem de + projetos — apenas aponta para elas; +- Não expõe conteúdo de feedback (apenas a existência dele). +--- + +## 4. Estrutura proposta + +### 4.1 Bloco de pendências (topo, prioridade máxima) + +Só aparece quando existe pendência. **Dashboard sem pendência não mostra bloco +vazio** — mostra o estado de "tudo em dia". + +Pendências previstas: + +| Pendência | Origem | Ação | +|---|---|---| +| Avaliações pendentes | Projeto concluído sem feedback enviado | Ir para `/dashboard/feedbacks` | +| Perfil incompleto | Campos mínimos ausentes | Ir para perfil | +| Projeto pronto para encerrar | Owner, todas as stacks assumidas | Ir para o projeto | +| Convite não utilizado | Convite emitido pela pessoa, não usado | Informativo | + +> ⚠️ **Regra de tom.** Pendência é convite, não cobrança. A comunicação segue o +> Plano Geral de Comunicação: sem urgência artificial, sem contagem regressiva, +> sem linguagem de culpa. "Você tem 2 avaliações para enviar" — não "Você está +> atrasado". + +### 4.2 Bloco de projetos + +Projetos em que a pessoa participa, agrupados por status: + +- `BUSCANDO` — projetos que ela criou e aguardam equipe; +- `EM_ANDAMENTO` — participação ativa, com a stack assumida em destaque; +- `CONCLUIDO` — últimos concluídos, com link para o feedback daquele projeto. +Estado vazio: quem não participa de nenhum projeto vê um caminho, não um vazio — +link para a listagem de projetos abertos e para o cadastro de projeto próprio. + +### 4.3 Bloco de reputação e portfólio + +- Contagem de feedbacks novos (**sem conteúdo**, respeitado o blind duplo); +- Estado do portfólio: público ou privado, com link para configuração; +- Corroborações já exibidas publicamente. +> Este bloco **nunca** exibe nota, média ou barra de progresso. Ver +> `feedback-reputacao.md`, seção 5.4. + +### 4.4 Bloco de primeiros passos (condicional) + +Aparece apenas para conta recém-criada, e some quando os passos são cumpridos: + +1. Complete seu perfil; +2. Cadastre suas skills e disponibilidade; +3. Configure seu portfólio; +4. Encontre um projeto. +Isso cobre parcialmente a lacuna de onboarding pós-cadastro apontada em +`jornada-de-entrada-how-to-join.md` (status 🟡 — a página pública existe, o +onboarding não). + +--- + +## 5. Permissões + +- Rota privada: exige sessão ativa; +- Cada pessoa vê exclusivamente os próprios dados; +- `MENTOR` vê a mesma estrutura (diferenciação de mentoria é decisão futura); +- `ADMIN` vê a mesma estrutura — administração fica no painel administrativo. +--- + +## 6. Regras de negócio + +1. Nenhum bloco exibe dado de terceiro. +2. Contagem de feedback respeita o blind duplo definido em `feedback-reputacao.md`, + seção 8 — antes da liberação, só o número, nunca o conteúdo. +3. Pendência de avaliação só existe para projeto com status `CONCLUIDO`. +4. Bloco vazio não é renderizado; cada estado vazio tem texto e ação próprios. +5. Nenhum elemento de gamificação, pontuação ou comparação. +6. Toda agregação é feita no backend. +--- + +## 7. Acessibilidade + +Conforme o Documento Estratégico — Acessibilidade e Inclusão Digital: + +- Um único `H1`; +- Ordem semântica de headings entre blocos; +- Pendência **não** sinalizada apenas por cor — sempre com texto; +- Contagens com rótulo textual completo, legível por leitor de tela; +- Foco visível e áreas clicáveis confortáveis; +- Layout mobile-first, coluna única em telas pequenas. +--- + +## 8. Comunicação com o usuário + +- Estados vazios são orientadores, nunca em branco; +- Sem linguagem de urgência ou culpa; +- Sem promessa que a plataforma não sustenta (participação em projeto não é + garantida); +- Mensagens em `MESSAGES`, nunca string solta. +--- + +## 9. Antipadrões evitados + +- Placeholder permanente (situação atual); +- Gamificação (pontos, níveis, streaks) — contradiz "não competitivo"; +- Métrica de plataforma em tela de membro; +- Exposição de conteúdo de feedback antes da liberação; +- Bloco vazio renderizado sem propósito; +- Barra de progresso de perfil que sugira que a pessoa está "incompleta". +--- + +## 10. Relação com implementação técnica + +- Depende de agregações novas (pendências, contagem de feedback, projetos por + status); +- Recomendado um `dashboard.service.ts` seguindo o padrão de + `portfolio.service.ts`; +- Server Component chamando o serviço diretamente, sem fetch interno; +- Rota `GET /api/dashboard/feedbacks` já existe e pode ser reaproveitada. +--- + +## 11. Dependências + +| Depende de | Situação | +|---|---| +| Encerramento manual de projeto (#553) | 🔴 bloqueia a pendência de avaliação | +| Modelo de feedback v2 | 🔴 bloqueia o bloco de reputação | +| Perfil e portfólio | 🟢 prontos | +| Projetos | 🟡 parcial | + +**O dashboard pode ser construído em partes.** Blocos de projeto, perfil e +primeiros passos não dependem do feedback e podem ir ao ar antes. + +--- + +## 12. Decisões em aberto + +- `MENTOR` precisa de bloco próprio (equipes que orienta)? +- Notificações in-app fazem parte do dashboard ou são funcionalidade separada? +- O bloco de primeiros passos some por conclusão ou pode ser dispensado? +- Quais campos definem "perfil completo"? +--- + +## 13. Critérios de aceite + +- A pessoa entende, sem rolar, se há algo a fazer; +- Toda pendência leva a uma ação concreta; +- Nenhum bloco vazio é renderizado; +- Nenhum elemento de comparação ou pontuação; +- Conteúdo de feedback não vaza antes da liberação; +- Um `H1`, hierarquia semântica correta, funcional em mobile. +--- + +## 14. Histórico + +| Versão | Alteração | +|---|---| +| Inicial | Criação do documento para cobrir a lacuna do épico #630 | + \ No newline at end of file diff --git a/docs/02 - produto/estado-das-funcionalidades.md b/docs/02 - produto/estado-das-funcionalidades.md index 516899cb..8f2bb2b5 100644 --- a/docs/02 - produto/estado-das-funcionalidades.md +++ b/docs/02 - produto/estado-das-funcionalidades.md @@ -1,40 +1,39 @@ # Estado das Funcionalidades - + **Classificação:** Documento de Produto / Consolidado **Camada:** 2 — Documentos de Produto e Funcionalidades **Status do documento:** consolidado **Última verificação contra o código:** 16/08/2026 - +**Última revisão documental:** 18/08/2026 + --- - + ## 1. Para que serve - + Este documento responde a uma pergunta só: **o que já está funcionando e o que ainda falta.** - + Ele existe porque os documentos de produto descrevem como cada funcionalidade -*deve* se comportar, mas não dizem se ela está no ar. Quem precisa decidir o que -construir em seguida teria que abrir treze arquivos e conferir cada um contra o -código. - -> ⚠️ **Este documento não substitui os documentos de produto.** Ele aponta para -> eles. As regras de negócio, os critérios e os detalhes continuam lá. - +*deve* se comportar, mas não dizem se ela está no ar. + +> ⚠️ **Não substitui os documentos de produto.** Aponta para eles. As regras de +> negócio, os critérios e os detalhes continuam lá. + --- - + ## 2. Legenda - + | Situação | Significa | |---|---| | 🟢 **Completa** | Backend e interface prontos, em uso | -| 🟡 **Parcial** | Parte funciona; falta algo para a pessoa conseguir usar de ponta a ponta | +| 🟡 **Parcial** | Parte funciona; falta algo para usar de ponta a ponta | | 🔴 **Não iniciada** | Especificada em documento, sem implementação utilizável | | ⚪ **Só documento** | Especificação escrita, sem contrapartida no código | - + --- - + ## 3. Visão geral - + | Funcionalidade | Situação | O que falta | Documento | |---|---|---|---| | Autenticação e sessão | 🟢 | — | [permissoes.md](permissoes-papeis/permissoes.md) | @@ -42,28 +41,50 @@ código. | Solicitação de convite | 🟢 | — | [invite-request.md](convite/invite-request.md) | | Skills | 🟢 | — | [gestao-skills.md](skills/gestao-skills.md) | | Tech stacks | 🟢 | — | [gestao-stacks.md](tech-stacks/gestao-stacks.md) | -| Painel administrativo | 🟢 | — | [painel-administrativo.md](adminstrativo/painel-administrativo.md) | -| Portfólio público | 🟢 | — | [portfolio.md](portfolio/portfolio.md) | -| Perfil de usuário | 🟢 | — | [perfis-usuario.md](usuario/perfis-usuario.md) | -| Projetos em equipe | 🟡 | Encerramento manual e notificação da equipe | [gestao-projetos.md](projetos/gestao-projetos.md) | -| Certificados | 🟡 | Tela para a pessoa cadastrar os próprios certificados | [portfolio.md](portfolio/portfolio.md) | -| Jornada de entrada | 🟡 | Página existe; onboarding pós-cadastro não | [how-to-join.md](jornada-de-entrada/jornada-de-entrada-how-to-join.md) | -| **Feedback e reputação** | 🔴 | **A tela onde se avalia o colega** | [feedback-reputacao.md](feedback/feedback-reputacao.md) | -| Dashboard do membro | 🔴 | A tela inteira | — | +| Painel administrativo | 🟢 | Moderação de feedback (escopo novo) | [painel-administrativo.md](adminstrativo/painel-administrativo.md) | +| Perfil de usuário | 🟡 | Tela de certificados | [perfis-usuario.md](usuario/perfis-usuario.md) | +| Portfólio público | 🟡 | Bloco de corroborações (era 🟢) | [portfolio.md](portfolio/portfolio.md) | +| **Encerramento de projeto** | 🔴 | **Bloqueia o feedback inteiro** | [gestao-projetos.md](projetos/gestao-projetos.md) | +| Projetos em equipe (resto) | 🟡 | Notificação da equipe | [gestao-projetos.md](projetos/gestao-projetos.md) | +| Certificados | 🟡 | Tela de cadastro | [portfolio.md](portfolio/portfolio.md) | +| Jornada de entrada | 🟡 | Onboarding pós-cadastro | [how-to-join.md](jornada-de-entrada/jornada-de-entrada-how-to-join.md) | +| **Feedback e reputação** | 🔴 | Migration + tela de avaliação | [feedback-reputacao.md](feedback/feedback-reputacao.md) | +| Dashboard do membro | 🔴 | A tela inteira | [dashboard-membro.md](dashboard/dashboard-membro.md) | +| Exclusão de conta (LGPD) | 🔴 | O fluxo inteiro | [governanca-dados-lgpd.md](../01%20-%20estrategia/governanca/governanca-dados-lgpd.md) | | Conteúdos informativos (FAQ) | 🔴 | A tela inteira | [conteudos-informativos-e-educacionais.md](conteudos/conteudos-informativos-e-educacionais.md) | | Fórum | ⚪ | Tudo | — | - + --- - -## 4. O que exige decisão agora - + +## 4. A ordem de execução + +> 🔗 **A dependência que muda tudo.** `feedback-reputacao.md` exige +> `Project.status = CONCLUIDO`. `gestao-projetos.md` informa que o encerramento +> manual não existe. **Nenhum projeto chega a `CONCLUIDO` hoje — logo, nenhum +> feedback pode ser gerado.** Construir a tela de avaliação antes do encerramento +> produz uma tela que nunca dispara. + +**Sequência recomendada:** + +| # | Item | Por quê | +|---|---|---| +| 1 | Encerramento manual de projeto (#553) | Destrava o domínio de feedback inteiro | +| 2 | Spike de schema do feedback | Decisão de estrutura antes da migration | +| 3 | Migration + rotas de feedback | Base do modelo v2 | +| 4 | Tela `/dashboard/feedbacks` | O meio que falta entre API e portfólio | +| 5 | Bloco de corroborações no portfólio | Onde o sinal se torna público | +| 6 | Dashboard do membro (parcial) | Blocos de projeto e perfil não dependem do feedback | +| 7 | Fluxo de exclusão de conta | Direito prometido e não implementado | +| 8 | FAQ | Depende de as regras estarem estáveis | + +--- + +## 5. O que exige decisão agora + ### 🔴 Feedback e reputação - -**É a funcionalidade mais avançada entre as não concluídas — e a que menos -parece.** - + O que já existe: - + ``` ✅ POST/GET /api/feedback criar e listar ✅ GET /api/feedback/[id] consultar @@ -71,96 +92,107 @@ O que já existe: ✅ PortfolioFeedbackSection exibição no portfólio público ✅ Modelo Feedback no schema.prisma com rating, comment, anonymous ``` - + O que falta: - + ``` +⛔ Project.status = CONCLUIDO inalcançável hoje +⛔ Migration do modelo v2 atributos de corroboração ⛔ /dashboard/feedbacks — 10 linhas +⛔ Bloco de corroborações exibição atual pressupõe rating ``` - -Ou seja: **dá para gravar feedback pela API e ele aparece no portfólio, mas não -existe tela onde a pessoa avalia o colega.** O caminho está construído dos dois -lados e falta o meio. - -**Decisões pendentes de produto**, registradas no documento da funcionalidade mas -ainda não fechadas: - -- a avaliação é granular por competência ou uma nota única? -- o que fica visível no portfólio público — média, distribuição, comentários? -- como evitar que uma nota baixa desmotive, dado que o objetivo é formar pessoas? -- feedback anônimo é opcional ou padrão? - -> 💡 O modelo `Feedback` já tem os campos `rating`, `comment` e `anonymous`. -> Granularidade por competência exigiria mudança de schema — vale decidir **antes** -> de construir a tela. - + +**As decisões de produto que estavam pendentes foram fechadas** em +`feedback-reputacao.md` v2: + +| Pergunta | Decisão | +|---|---| +| Granular por competência ou nota única? | Granular, por eixos fixos — sem nota | +| O que fica público? | Corroborações agregadas + texto com dupla autorização | +| Como não desmotivar? | Não existe sinal negativo público; ausência ≠ nota baixa | +| Anônimo é opcional ou padrão? | Público sempre anônimo; identidade registrada internamente | + +**Ainda em aberto:** estrutura final do schema (spike), prazo do blind duplo +(14 dias proposto), N mínimo (3 proposto), destino definitivo do `rating`. + ### 🔴 Dashboard do membro - -`/dashboard` é a **primeira tela que a pessoa vê ao entrar**, e hoje é um -placeholder de 24 linhas. Não há documento de produto para ela. - -Existe o épico [#630](https://github.com/TryCatch-ForMatch/trycatch/issues/630) -com as issues #631, #635, #636 e #637, mas nenhum documento na camada 2. - + +`/dashboard` é a **primeira tela pós-login** e hoje é placeholder de 24 linhas. +Agora possui documento de produto — a lacuna apontada na revisão anterior foi +preenchida. + +### 🔴 Exclusão de conta + +Direito garantido em documento estratégico e **não implementado**. Até existir o +fluxo, pedidos são tratados manualmente por ADMIN seguindo a regra de +anonimização assimétrica. + ### 🟡 Projetos em equipe - -O grosso funciona: criar, listar, detalhar, editar, assumir stack. Falta o -encerramento manual, previsto no épico -[#553](https://github.com/TryCatch-ForMatch/trycatch/issues/553). - -> ⚠️ **A regra de bloqueio de edição após formação da equipe está desativada.** -> Ela travava a edição por completo por um defeito na comparação de datas. A -> direção acordada é **notificar as pessoas envolvidas** em vez de bloquear — -> decisão de produto ainda a desenhar. - + +Criar, listar, detalhar, editar e assumir stack funcionam. Falta o encerramento +manual (#553). + +> ⚠️ **A regra de bloqueio de edição após formação de equipe está desativada** por +> defeito na comparação de datas. A direção acordada é notificar em vez de +> bloquear — decisão de produto ainda a desenhar. + --- - -## 5. Onde a documentação diverge do código - -Levantado em 16/08/2026. O Documento 0, seção 4, trata divergência entre -documentação e código como falha de qualidade. - -| Documento | Diz | Realidade | + +## 6. Divergências entre documentação e código + +O Documento 0, seção 4, trata divergência como falha de qualidade. + +### 6.1 Corrigidas na revisão de 18/08/2026 + +| Documento | Divergência | Resolução | +|---|---|---| +| `arquitetura-geral.md` + `arquitetura-geral-atualizado.md` | Dois arquivos concorrentes | Consolidados em um; remover o `-atualizado` | +| `adr-email-templates.md` | "ADR-XXX", fora do registro | Incorporado como ADR-004; remover o arquivo | +| `modelagem-dados.md` | "reputação é média simples dos ratings" | Afirmação revogada | +| `governanca-dados-lgpd.md` | Garantia de exclusão de conta não implementada | Corrigida com status real | +| `governanca-dados-lgpd.md` × `feedback-reputacao.md` | Exclusão × imutabilidade | Anonimização assimétrica | +| `visao-produto.md` × `Project.totalValue` | "não é marketplace" × valor no schema | Distinção registrar ≠ intermediar | +| `feedback-reputacao.md` | Princípios anti-nota × `rating` agregado | Modelo de corroborações | +| Dashboard do membro | Épico sem documento | Documento criado | +| `painel-administrativo.md` | 12 linhas para função crítica | Expandido | + +### 6.2 Abertas + +| Documento | Divergência | Ação | |---|---|---| -| `feedback-reputacao.md` | *"Versão consolidada alinhada ao schema.prisma"* | Sem tela de avaliação | -| `conteudos-informativos-e-educacionais.md` | *"Documento inicial consolidado"* | FAQ é placeholder | -| `jornada-de-entrada-how-to-join-ux.md` | *"Estrutura proposta para validação de UX"* | Página pública existe | - -A causa não é descuido: **o campo `Status` desses documentos descreve o estado do -documento, não o da funcionalidade.** "Alinhada ao schema" significa que o texto -bate com o banco — não que exista tela. - -Por isso os documentos de produto passam a ter **dois campos** (ver seção 6). - +| `conteudos-informativos-e-educacionais.md` | "consolidado", FAQ é placeholder | Ajustar header | +| `jornada-de-entrada-how-to-join-ux.md` | "proposta para validação", página existe | Ajustar header | +| Nome da marca | *TryCatch*, *TryCatch For Match*, *TryCatch 4Match* circulando | Padronizar conforme `decisao-marca.md` | +| Vários | Skills gerenciadas dentro da rota de disponibilidade | Avaliar separação | +| Código | SEC-03 — `User` retornado com hash de senha | **Prioridade de segurança** | + --- - -## 6. Como manter isto atualizado - -Cada documento de produto deve declarar os dois estados no cabeçalho: - + +## 7. Como manter isto atualizado + +Cada documento de produto declara dois estados: + ```markdown **Status do documento:** consolidado · alinhado ao schema.prisma **Status da implementação:** 🟡 parcial — API pronta, tela de avaliação pendente ``` - + O primeiro responde *"este texto é confiável?"*. O segundo, *"isto está no ar?"*. - -**Quando atualizar:** - -- ao mergear um PR que conclui ou avança uma funcionalidade; -- ao criar um documento de produto novo; -- ao descobrir divergência entre documento e código. - + +**Quando atualizar:** ao mergear PR que conclui ou avança funcionalidade; ao criar +documento de produto novo; ao descobrir divergência. + **Quem atualiza:** quem abre o PR que muda o estado. A revisão confere. - -> 💡 Este documento é um índice, não a fonte da verdade. A fonte é o código. Ao + +> 💡 Este documento é índice, não fonte da verdade. A fonte é o código. Ao > encontrar divergência, corrija aqui **e** avise — divergência costuma indicar > que algo mudou sem passar pela documentação. - + --- - -## 7. Histórico de Revisão - + +## 8. Histórico de Revisão + | Data | Alteração | |---|---| -| 16/08/2026 | Criação, a partir de levantamento das rotas de API, telas e componentes | +| 16/08/2026 | Criação, a partir de levantamento de rotas, telas e componentes | +| 18/08/2026 | Encerramento de projeto isolado como bloqueio do feedback; ordem de execução; decisões de feedback fechadas; divergências corrigidas registradas; adicionados Dashboard do Membro e Exclusão de Conta \ No newline at end of file diff --git a/docs/02 - produto/feedback/feedback-reputacao.md b/docs/02 - produto/feedback/feedback-reputacao.md index e5ced984..46b46b9f 100644 --- a/docs/02 - produto/feedback/feedback-reputacao.md +++ b/docs/02 - produto/feedback/feedback-reputacao.md @@ -1,207 +1,567 @@ -# Documento de Produto --- Sistema de Feedback e Reputação - -Classificação: Documento de Produto / Funcionalidade\ -Camada: 2 --- Produto\ -**Status do documento:** Versão consolidada alinhada ao schema.prisma -**Status da implementação:** 🔴 não iniciada — API e exibição prontas, falta a tela de avaliação +# Documento de Produto — Sistema de Feedback e Reputação + +**Classificação:** Documento de Produto / Funcionalidade +**Camada:** 2 — Documentos de Produto e Funcionalidades +**Status do documento:** Versão 2 — modelo de reputação definido, pendente de migration +**Status da implementação:** 🔴 não iniciada — API antiga (`rating`) existe; modelo desta versão exige mudança de schema **Estado consolidado:** ver [estado-das-funcionalidades.md](../estado-das-funcionalidades.md) - ------------------------------------------------------------------------- - + +> ⚠️ **Esta versão substitui a v1.** A v1 previa `rating` numérico agregado como +> média simples exibida publicamente. Essa decisão foi revertida — o motivo está +> na seção 15. + +--- + ## 1. Identificação da Funcionalidade - -- Nome da funcionalidade: Sistema de Feedback e Reputação -- Domínio do produto: Reputação, Qualidade e Governança -- Entidade principal: Feedback -- Entidades relacionadas: Project, User, StackTaken -- Documentos relacionados: Gestão de Projetos; Perfis de Usuário; - Permissões e Papéis; Gestão de Stacks - ------------------------------------------------------------------------- - + +- **Nome da funcionalidade:** Sistema de Feedback e Reputação +- **Domínio do produto:** Reputação, Qualidade e Governança +- **Entidade principal:** `Feedback` +- **Entidades relacionadas:** `Project`, `User`, `StackTaken`, `FeedbackAttribute` (nova) +- **Documentos relacionados:** Gestão de Projetos; Perfis de Usuário; Portfólio; + Permissões e Papéis; Governança de Dados e LGPD +--- + ## 2. Contexto e Objetivo - -O TryCatch é uma plataforma colaborativa onde desenvolvedores participam -de projetos reais em equipe. - -Ao final de cada projeto concluído, os participantes podem avaliar uns -aos outros com base em comportamentos observáveis durante a execução do -trabalho. - -A funcionalidade existe para: - -- Incentivar aprendizado contínuo; -- Valorizar colaboração e postura profissional; -- Construir confiança baseada em evidência real de participação; -- Proteger usuários iniciantes contra exposição pública inadequada; -- Criar um sistema de reputação progressivo e não competitivo. - -O sistema é acionado exclusivamente após o projeto atingir status -CONCLUIDO. - ------------------------------------------------------------------------- - -## 3. Estrutura da Entidade Feedback (schema.prisma) - -Campos: - -- id -- projectId -- fromUserId -- toUserId -- rating (Int) -- comment (opcional) -- anonymous (Boolean) -- stackTakenId (opcional) -- createdAt -- updatedAt - ------------------------------------------------------------------------- - -## 4. Escopo da Funcionalidade - -### 4.1 O que a funcionalidade faz - -- Permite que participantes de um mesmo projeto avaliem uns aos - outros; -- Vincula feedback obrigatoriamente a um projeto concluído; -- Permite rating numérico (escala definida pelo produto, ex: 1 a 5); -- Permite comentário opcional; -- Permite anonimato apenas no frontend; -- Permite vinculação a uma contribuição específica via stackTakenId; -- Consolida sinais agregados no perfil público. - -### 4.2 O que a funcionalidade não faz - -- Não cria ranking público de usuários; -- Não gera nota pública única de reputação; -- Não permite edição ou exclusão de feedback após envio; -- Não permite avaliação fora de contexto de projeto; -- Não expõe comentários negativos publicamente. - ------------------------------------------------------------------------- - -## 5. Usuários Envolvidos e Permissões - -- Avaliador: participante confirmado de projeto CONCLUIDO; -- Avaliado: participante do mesmo projeto; -- Sistema: consolida dados e controla visibilidade. - + +### 2.1 O problema que esta funcionalidade resolve + +Código deixou de ser evidência confiável de competência. Uma ferramenta de IA +escreve um projeto inteiro em uma tarde, e o repositório resultante não distingue +quem sabe trabalhar em equipe de quem apenas soube pedir. + +O que uma IA **não** faz: + +- avisar a equipe que vai atrasar; +- revisar o trabalho de outra pessoa; +- perguntar antes de decidir uma regra de negócio que não estava escrita; +- aparecer na semana seguinte. +**A funcionalidade existe para registrar exatamente o que sobra quando o código +deixa de provar alguma coisa: comportamento colaborativo observável.** + +Isso reposiciona a feature. Não é avaliação de competência técnica — para isso +existem os projetos concluídos e as skills no portfólio. É **atestado de conduta +em trabalho real, dado por quem estava lá.** + +### 2.2 Quando é acionada + +Exclusivamente após um projeto atingir status `CONCLUIDO`. + +> 🔗 **Dependência bloqueante.** O encerramento manual de projeto (épico #553) +> ainda não está implementado. Nenhum projeto alcança `CONCLUIDO` hoje, portanto +> **nenhum feedback pode ser gerado até que aquele épico seja concluído.** +> Ver `docs/02 - produto/projetos/gestao-projetos.md`. + +--- + +## 3. Princípios que governam esta funcionalidade + +Derivados do Documento Estratégico — Plano Geral de Comunicação e dos Textos +Institucionais de Qualidade, Avaliação e Feedback: + +1. **Não existe lado negativo público.** A camada pública registra apenas o que + foi observado de positivo. Ausência de atestado significa ausência de + evidência, nunca avaliação ruim. +2. **Sem ranking, sem nota, sem média pública.** Duas médias lado a lado são um + ranking, independentemente de como sejam rotuladas. +3. **Sem teto.** Nenhum indicador comunica "70% preenchido". Quem tem poucos + atestados aparece com poucos, não aparece incompleto. +4. **Comportamento, não personalidade.** "Avisa antes de travar" é testemunhável. + "É comunicativo" não é. +5. **Anonimato público, identificação interna.** Ver seção 7. +6. **Iniciante nunca aparece pior por ser iniciante.** Quem entrou agora tem + poucos sinais — o que é honesto — e nunca um sinal de baixa qualidade. +--- + +## 4. Arquitetura da funcionalidade: duas camadas + +A funcionalidade tem **duas camadas de natureza diferente**. A separação não é um +toggle de visibilidade: são coisas distintas, com finalidade, formato e regras +próprias. + +| | Camada A — Corroborações | Camada B — Feedback de desenvolvimento | +|---|---|---| +| **O que é** | Atestados de comportamento observado | Texto livre construtivo | +| **Formato** | Seleção de até 3 eixos | Texto aberto | +| **Onde vive** | Portfólio público (agregado) | Área privada do avaliado | +| **Quem vê** | Qualquer visitante, se habilitado | Só o avaliado — e só ele decide publicar | +| **Tem lado negativo?** | Não. Só existe atestado positivo | Sim, pode conter crítica construtiva | +| **Vira número?** | Nunca | Nunca | + +--- + +## 5. Camada A — Corroborações + +### 5.1 Os eixos + +Seis eixos fixos, todos redigidos como **comportamento observável em projeto +real**. A lista é fechada por decisão de produto: eixo livre viraria elogio +genérico e destruiria a comparabilidade entre perfis. + +| Chave interna | Selo público | O que a pessoa atesta ao marcar | +|---|---|---| +| `COMUNICA_IMPEDIMENTOS` | 🗣️ Avisa antes de travar | Comunicou bloqueio ou atraso com antecedência útil | +| `ENTREGA_O_COMBINADO` | 📦 Entrega o que assume | Cumpriu o escopo da stack que assumiu | +| `APOIA_A_EQUIPE` | 🤝 Puxa a equipe junto | Ajudou colega, revisou trabalho de outro, destravou alguém | +| `PERGUNTA_ANTES_DE_DECIDIR` | 🧭 Pergunta antes de decidir | Não inventou regra de negócio por conta própria | +| `RECEBE_REVISAO_BEM` | 🔄 Recebe revisão bem | Absorveu crítica técnica sem travar o fluxo do time | +| `AUTONOMIA_NA_STACK` | 🛠️ Resolve sem ser conduzido | Avançou na própria stack sem precisar ser conduzido | + +**Regra dos rótulos:** todo selo começa com verbo na terceira pessoa e descreve +ação. É proibido rótulo com superlativo (*"Mestre em..."*), com traço inato +(*"...nato"*) ou que implique escala (*"nível avançado em..."*). Superlativo +pressupõe hierarquia, e hierarquia é ranking. + +### 5.2 Como se avalia + +- O avaliador seleciona **no máximo 3 eixos** por pessoa avaliada. +- O limite de 3 é deliberado: obriga escolha e impede marcar tudo por gentileza, + o que esvaziaria o sinal. +- Selecionar zero eixos é permitido — ver seção 5.6. +### 5.3 Como aparece no portfólio + +Formato de exibição: + +``` +🗣️ Avisa antes de travar 4 pessoas · 3 projetos +📦 Entrega o que assume 5 pessoas · 3 projetos +🤝 Puxa a equipe junto 3 pessoas · 2 projetos +``` + +Regras de exibição: + +1. **N mínimo de 3.** Um eixo só aparece publicamente a partir de **3 atestados + de pessoas distintas**. Abaixo disso, o eixo não é exibido. Isso impede que + uma avaliação isolada vire rótulo permanente. +2. **Duplo denominador obrigatório.** Sempre exibir *pessoas* **e** *projetos*. + Atestado espalhado por projetos diferentes é muito mais difícil de combinar + que quatro do mesmo time — é o que devolve credibilidade ao sinal anônimo. +3. **Intensidade sem teto.** O selo pode ganhar destaque visual conforme acumula + (peso tipográfico, opacidade, tamanho), mas **nunca exibe percentual, barra + preenchida, termômetro, estrelas ou qualquer elemento com máximo implícito.** +4. **Ordenação por volume de atestados**, nunca por "força" ou "pontuação". +5. Exibição condicionada a `showFeedback = true` no perfil. +### 5.4 Antipadrões visuais explicitamente proibidos + +- Barra de progresso, termômetro, medidor ou gauge; +- Estrelas, notas, percentuais; +- Comparação com média da plataforma ("acima da média"); +- Badge de nível (bronze/prata/ouro, iniciante/avançado); +- Qualquer elemento que sugira que falta algo para completar. +### 5.5 O que a corroboração **não** faz + +- Não gera nota única; +- Não gera ranking nem listagem ordenada de pessoas; +- Não é usada para bloquear participação em projeto; +- Não expira nem decai com o tempo (mas o contexto — projeto e data — fica + registrado). +### 5.6 Avaliação sem atestado + +O avaliador pode concluir o fluxo sem marcar nenhum eixo para determinada pessoa. +Nesse caso o registro existe internamente (com os campos de contexto), mas não +produz sinal público. **Isso é intencional:** obrigar atestado positivo produziria +atestado de cortesia, que é ruído. + +--- + +## 6. Camada B — Feedback de desenvolvimento + +### 6.1 Natureza + +Texto livre, escrito para a pessoa avaliada. É aqui que cabe o construtivo — o +que poderia ter sido melhor, o que travou, o que ela pode observar na próxima. + +### 6.2 Onde vive + +**Fonte da verdade: área privada no dashboard do membro** (`/dashboard/feedbacks`, +aba "Recebidos"). Somente o avaliado acessa. + +O e-mail é **notificação, não canal de entrega**: + +> Assunto: Você recebeu um feedback do projeto [Nome] +> +> Corpo: aviso de que existe feedback novo + link para a área privada. +> **O conteúdo do feedback não vai no corpo do e-mail.** + +Motivos para não entregar por e-mail: + +- e-mail some, cai em spam, a pessoa troca de endereço — e o feedback é o + instrumento de desenvolvimento, precisa continuar acessível; +- conteúdo pessoal sobre alguém trafegando só por e-mail é difícil de auditar e + impossível de excluir a pedido (ver LGPD); +- o Documento Estratégico de Comunicação Transacional determina que e-mail + comunica ação e contexto, sem excesso de narrativa. +### 6.3 Publicação do texto: consentimento na origem + +O avaliado **pode** exibir feedback escrito no portfólio, mas apenas textos que o +autor autorizou previamente. + +Fluxo: + +1. Ao escrever, o avaliador marca (opcional, desmarcado por padrão): + ☐ *Este texto pode ser exibido no portfólio dele/dela* +2. Textos **não** marcados: permanecem privados para sempre. Nem o avaliado nem + um ADMIN podem publicá-los. +3. Textos marcados: entram no conjunto publicável. O avaliado escolhe quais + exibir no portfólio. +4. O texto público é exibido **sem identificar o autor**, com contexto de projeto. +**Por que consentimento na origem e não no destino:** o texto foi escrito sob +expectativa de privacidade. Publicá-lo depois muda o acordo após o fato. Além +disso, a identidade do autor fica registrada internamente — publicar sem seu +conhecimento é exposição indireta. + +**Limitação assumida e registrada:** como o avaliado escolhe o que publicar, o +texto público é uma vitrine selecionada e tem menos valor probatório que as +corroborações. Ele é complemento narrativo, não evidência. **As corroborações não +são selecionáveis individualmente** — o toggle `showFeedback` liga ou desliga o +bloco inteiro. É isso que preserva o valor do sinal. + +--- + +## 7. Anonimato e responsabilização + +**Decisão:** anonimato **na exibição pública**, identificação **completa e +permanente no banco**. + +| Camada | Identidade do avaliador | +|---|---| +| Banco de dados (`fromUserId`) | Sempre registrada, obrigatória, nunca nula em registro ativo | +| Painel administrativo | Visível para ADMIN em caso de denúncia ou apuração | +| Área privada do avaliado | **Não exibida** | +| Portfólio público | **Não exibida** | + +**Justificativa:** avaliador que teme ser julgado por ser sincero não é sincero. +O anonimato na interface protege a honestidade do feedback; o registro interno +impede que ele vire escudo para desrespeito. + +**Consequência assumida:** para um observador externo, o sinal anônimo é menos +verificável. A mitigação é o duplo denominador (seção 5.3) e o N mínimo, não a +quebra do anonimato. + +**Regra de comunicação:** a interface deve deixar explícito para o avaliador, no +momento da avaliação, que a identidade dele não aparece publicamente **mas fica +registrada na plataforma**. Omitir isso seria enganoso. + +--- + +## 8. Blind duplo (anti-retaliação) + +O documento v1 listava "retaliação entre participantes" como risco sem mitigação +real. Esta versão define uma: + +**O avaliado só vê o que recebeu quando qualquer uma destas condições se cumpre:** + +1. ele enviou as próprias avaliações daquele projeto; **ou** +2. passaram-se **14 dias** do encerramento do projeto. +Antes disso, o dashboard mostra apenas a contagem de feedbacks pendentes de +liberação, sem conteúdo. + +Isso impede o padrão "vi que me avaliaram mal, agora avalio mal de volta", que é +o principal vetor de distorção em sistemas de avaliação recíproca. + +O prazo de 14 dias existe para que quem não avalia não fique bloqueado +indefinidamente de receber seu próprio retorno — a avaliação é um direito da +pessoa avaliada, não uma recompensa por participação. + +--- + +## 9. Usuários envolvidos e permissões + +| Papel | Pode | +|---|---| +| Participante confirmado de projeto `CONCLUIDO` | Avaliar os demais participantes do mesmo projeto | +| Pessoa avaliada | Ver os próprios feedbacks (respeitado o blind duplo); escolher publicar textos autorizados; ligar/desligar `showFeedback` | +| ADMIN | Consultar autoria em caso de denúncia; ocultar feedback que viole as regras da plataforma | +| Visitante | Ver corroborações agregadas e textos publicados, se `showFeedback = true` | + Restrições: - -- Usuário não pode avaliar a si mesmo; -- Apenas participantes confirmados podem avaliar; -- Feedback não pode ser alterado após criação; -- Identidade do avaliador sempre armazenada internamente. - ------------------------------------------------------------------------- - -## 6. Fluxo de Uso (UX) - -1. Projeto é marcado como CONCLUIDO; -2. Participantes recebem acesso ao fluxo de avaliação; -3. Usuário seleciona participante a ser avaliado; -4. Define rating; -5. Opcionalmente adiciona comentário; -6. Define se deseja anonimato no frontend; -7. Feedback é registrado; -8. Sistema consolida sinais agregados no perfil. - -Estados relevantes: - -- Feedback pendente; -- Feedback enviado; -- Projeto concluído sem feedback; -- Feedback contextualizado por stack. - ------------------------------------------------------------------------- - -## 7. Regras de Negócio - -- Feedback só pode ocorrer após status CONCLUIDO; -- Feedback é sempre vinculado a projectId; -- rating deve respeitar escala definida; -- anonymous não oculta identidade no banco de dados; -- stackTakenId é opcional, mas se informado deve existir e pertencer - ao mesmo projeto; -- Feedbacks não podem ser editados nem excluídos; -- Um usuário pode receber múltiplos feedbacks por projeto. - ------------------------------------------------------------------------- - -## 8. Impactos em Dados - -- Criação de registro na tabela Feedback; -- Relação com User (fromUser e toUser); -- Relação com Project; -- Relação opcional com StackTaken; -- Dados utilizados para consolidação de reputação agregada. - -Os dados são utilizados para: - -- Desenvolvimento do usuário; -- Consolidação de sinais de reputação; -- Auditoria interna e rastreabilidade. - ------------------------------------------------------------------------- - -## 9. Impactos em Reputação e Confiança - -A reputação no TryCatch não é uma nota isolada. - -Ela representa um sinal construído a partir de múltiplas evidências de -participação real. - -Decisões estruturais adotadas: - -- Separação entre feedback privado e sinal público agregado; -- Ênfase em evolução ao longo do tempo; -- Proibição explícita de ranking competitivo; -- Redução de incentivos a comportamento estratégico de avaliação. - ------------------------------------------------------------------------- - -## 10. Riscos Identificados - -- Retaliação entre participantes; -- Avaliações estratégicas para prejudicar reputação; -- Concentração de avaliações entre grupos fechados; -- Viés inconsciente. - -Mitigações incluem: - -- Registro interno de avaliador; -- Contextualização por projeto; -- Ausência de ranking público; -- Consolidação agregada em vez de exposição isolada. - ------------------------------------------------------------------------- - -## 11. Métricas Relacionadas - -- Taxa de envio de feedback por projeto concluído; -- Média de rating por projeto; -- Correlação entre stackTaken e rating; -- Evolução temporal de reputação por usuário. - ------------------------------------------------------------------------- - -## 12. Relação com Implementação Técnica - -- Depende do status do Project; -- Depende da entidade StackTaken; -- Integra-se ao perfil do usuário; -- Requer controle de permissão baseado em participação real. - -Este documento descreve comportamento esperado e decisões de produto, -não detalhes de implementação técnica. - ------------------------------------------------------------------------- - -## 13. Histórico de Decisões - -- Adoção de rating contextualizado; -- Permissão de anonimato apenas na interface; -- Proibição de ranking público; -- Separação entre feedback privado e reputação agregada; -- Integração opcional com StackTaken para avaliação específica. + +- Ninguém avalia a si mesmo; +- Somente participantes confirmados (com `StackTaken` no projeto) avaliam; +- Um avaliador produz **no máximo um registro de feedback por pessoa avaliada por + projeto**; +- Feedback não é editável pelo autor após envio; +- ADMIN não edita conteúdo de feedback — apenas oculta, com registro do motivo. +--- + +## 10. Fluxo de uso (UX) + +### 10.1 Avaliar + +1. Owner marca o projeto como `CONCLUIDO`; +2. Todos os participantes recebem notificação por e-mail e pendência no dashboard; +3. A pessoa acessa `/dashboard/feedbacks`, aba "Pendentes"; +4. Vê a lista dos colegas daquele projeto, com a stack que cada um assumiu; +5. Para cada colega: + - seleciona até 3 eixos (ou nenhum), + - opcionalmente escreve o feedback de desenvolvimento, + - se escreveu, decide se autoriza publicação; +6. Envia. **Não há edição depois.** A interface deve avisar disso antes do envio. +### 10.2 Receber + +1. Notificação por e-mail: existe feedback novo (sem conteúdo); +2. Acessa `/dashboard/feedbacks`, aba "Recebidos"; +3. Se o blind duplo ainda bloqueia, vê apenas a contagem e a condição para + liberar; +4. Liberado: lê os textos e vê os eixos que recebeu; +5. Escolhe quais textos autorizados exibir no portfólio; +6. Controla a exibição do bloco inteiro via `showFeedback`. +### 10.3 Estados relevantes + +- Projeto concluído com avaliações pendentes; +- Avaliação enviada, aguardando liberação por blind duplo; +- Feedback liberado; +- Eixo com atestados abaixo do N mínimo (existe internamente, não exibe); +- Projeto concluído sem nenhuma avaliação enviada. +--- + +## 11. Regras de negócio + +1. Feedback só pode ser criado se `Project.status = CONCLUIDO`. +2. Feedback é sempre vinculado a `projectId`. +3. Avaliador e avaliado devem ter participação registrada no mesmo projeto. +4. `fromUserId ≠ toUserId`. +5. Máximo um registro por par (avaliador, avaliado, projeto). +6. Máximo 3 atributos por registro de feedback. +7. Atributos pertencem à lista fechada da seção 5.1. +8. Um eixo só é exibido publicamente com ≥ 3 atestados de pessoas distintas. +9. `anonymous` deixa de ser opcional do avaliador: **a exibição pública é sempre + anônima**. O campo passa a ser irrelevante para o público (ver seção 14). +10. `publicationAllowed = false` por padrão no texto escrito. +11. Texto só pode ser publicado pelo avaliado se `publicationAllowed = true`. +12. Feedback não é editável nem excluível pelo autor. +13. Exclusão de conta segue a regra de anonimização da seção 13. +14. `stackTakenId` é opcional; se informado, deve pertencer ao mesmo projeto. +15. Todas as regras aplicadas no backend e testáveis. +--- + +## 12. Impactos em dados + +### 12.1 Mudança de schema necessária + +O modelo atual não comporta os eixos. É necessária migration. + +**Estrutura proposta** (a validar em spike técnico — ver seção 16): + +```prisma +model Feedback { + id String @id @default(cuid()) + projectId String + fromUserId String + toUserId String + stackTakenId String? + + comment String? // Camada B + publicationAllowed Boolean @default(false) + publishedByReceiver Boolean @default(false) + + rating Int? // legado — ver seção 14 + anonymous Boolean @default(true) // legado — ver seção 14 + + hiddenByAdmin Boolean @default(false) + hiddenReason String? + + attributes FeedbackAttribute[] + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@unique([projectId, fromUserId, toUserId]) +} + +model FeedbackAttribute { + id String @id @default(cuid()) + feedbackId String + attribute FeedbackAttrEnum + feedback Feedback @relation(fields: [feedbackId], references: [id], onDelete: Cascade) + + @@unique([feedbackId, attribute]) +} + +enum FeedbackAttrEnum { + COMUNICA_IMPEDIMENTOS + ENTREGA_O_COMBINADO + APOIA_A_EQUIPE + PERGUNTA_ANTES_DE_DECIDIR + RECEBE_REVISAO_BEM + AUTONOMIA_NA_STACK +} +``` + +> ⚠️ Este bloco é **proposta de produto**, não especificação técnica final. A +> decisão entre tabela relacional e array de enum deve sair da spike da seção 16, +> considerando o custo da query de agregação por perfil. + +### 12.2 Agregação para o portfólio + +A consulta pública precisa devolver, por eixo: + +- contagem de avaliadores distintos; +- contagem de projetos distintos; +- filtrando `hiddenByAdmin = false`; +- aplicando o corte de N mínimo **no backend**, nunca no frontend. +--- + +## 13. Privacidade, LGPD e exclusão de conta + +Esta seção existe porque a v1 continha contradição direta com o Documento +Estratégico de Governança de Dados: lá se garante exclusão de conta, aqui se +determinava que feedback é imutável e indelével. + +**Resolução adotada — anonimização assimétrica.** Ao excluir a conta: + +| Dado | Destino | +|---|---| +| Feedbacks **recebidos** pela pessoa | Excluídos. São dados sobre ela. | +| Corroborações **recebidas** | Excluídas junto. | +| Feedbacks **dados** por ela a terceiros | **Preservados**, com `fromUserId` substituído por marcador de conta removida. São dados sobre outras pessoas — a saída dela não pode apagar a reputação alheia. | +| Contadores de outras pessoas | Recalculados: aquele atestado continua contando como "1 pessoa", agora sem vínculo. | + +**Consequência a comunicar:** os textos e atestados que a pessoa deixou para +outras permanecem. Isso deve estar explícito nos termos de uso e na FAQ, **antes** +de a pessoa avaliar — não é aceitável descobrir isso na hora de sair. + +Detalhamento completo em +`docs/01 - estrategia/governanca/governanca-dados-lgpd.md`. + +--- + +## 14. Destino dos campos legados + +### `rating` + +**Decisão: despublicado, não removido.** + +- Deixa de ser exibido publicamente; +- Deixa de ser agregado como média em qualquer superfície pública; +- A afirmação de `modelagem-dados.md` — *"a reputação é calculada como média + simples dos ratings recebidos"* — **fica revogada por este documento**; +- Permanece no schema como sinal operacional interno, consultável por ADMIN, útil + para detectar equipe em conflito; +- Passa a ser opcional (`Int?`). +Manter em vez de dropar evita migration destrutiva sobre dados já existentes. + +> 🔓 **Decisão em aberto:** se após dois ou três ciclos o `rating` interno não +> gerar decisão operacional real, ele deve ser removido. Reavaliar formalmente. + +### `anonymous` + +O anonimato deixa de ser escolha do avaliador e passa a ser regra fixa da camada +pública. O campo perde função de produto. Mantido apenas por compatibilidade com +registros existentes; **código novo não deve lê-lo para decidir exibição.** + +--- + +## 15. Por que a v1 não fechava + +Registro do raciocínio, para que a decisão não seja revertida sem contexto. + +A v1 declarava, simultaneamente: + +- "não cria ranking público"; +- "não gera nota pública única"; +- "foco em aprendizado, não em nota"; +- e um campo `rating` agregado como **média simples exibida no portfólio**. +**Uma média de notas é uma nota. Duas médias lado a lado são um ranking.** Os +princípios eram bons e o mecanismo os contradizia — por isso o formato de +exibição nunca fechava. A v2 não muda os princípios; troca o mecanismo por um que +os sustenta. + +--- + +## 16. Riscos identificados e mitigações + +| Risco | Mitigação | +|---|---| +| Retaliação | Blind duplo (seção 8) | +| Conluio em grupo fechado | Duplo denominador pessoas × projetos; N mínimo | +| Atestado de cortesia (marcar tudo) | Limite de 3 eixos por pessoa | +| Desrespeito sob anonimato | Identidade registrada; denúncia; ocultação por ADMIN | +| Vitrine selecionada no texto público | Corroborações não são selecionáveis; texto é complemento, não evidência | +| Viés inconsciente | Eixos comportamentais e observáveis, não traços de personalidade | +| Iniciante desmotivado | Não existe sinal negativo público; ausência ≠ nota baixa | +| Encerramento prematuro para gerar feedback | Regra de encerramento em `gestao-projetos.md` (todas as stacks assumidas) | + +--- + +## 17. Métricas relacionadas + +- Taxa de envio de feedback por projeto concluído; +- Distribuição de atestados por eixo (eixo que ninguém marca deve ser revisto ou + removido); +- Número médio de eixos marcados por avaliação (se convergir para 3, o limite + está sendo tratado como formulário a preencher e precisa de revisão); +- Percentual de textos com `publicationAllowed = true`; +- Percentual de avaliados que publicam texto; +- Tempo entre conclusão do projeto e envio da avaliação. +Nenhuma dessas métricas deve ser exibida publicamente por usuário. + +--- + +## 18. Relação com implementação técnica + +- Depende de `Project.status = CONCLUIDO` → **bloqueado pelo épico #553**; +- Depende de `StackTaken` para validar participação; +- Integra-se ao portfólio via `showFeedback`; +- Exige migration (seção 12.1); +- Exige nova rota de agregação por eixo; +- Notificação por e-mail segue `docs/03 - tecnico/adrs.md` (ADR-004, React Email). +Documentos técnicos relacionados: + +- `docs/03 - tecnico/modelagem/modelagem-dados.md` +- `docs/03 - tecnico/arquitetura/arquitetura-geral.md` +- `docs/02 - produto/portfolio/portfolio.md` +--- + +## 19. Antipadrões evitados + +- Média pública de notas (v1) — vira ranking; +- Termômetro, barra ou gauge — implicam teto e "incompletude"; +- Rótulos com superlativo ou traço inato ("Mestre em...", "...nato") — reintroduzem + hierarquia e não são testemunháveis; +- Eixo de texto livre — vira elogio genérico, destrói comparabilidade; +- Entrega de feedback só por e-mail — perde-se, não se audita, não se exclui; +- Publicação de texto sem consentimento do autor; +- Corte de N mínimo aplicado no frontend; +- Avaliação obrigatória com atestado obrigatório — produz cortesia, não sinal. +--- + +## 20. Status e próximos passos + +**Status:** modelo de produto definido; implementação bloqueada. + +**Ordem de execução:** + +1. ⛔ **Encerramento manual de projeto** (épico #553) — bloqueia tudo +2. 🔬 **Spike de schema** — estrutura dos atributos e custo da agregação +3. 🛠️ Migration + rotas (criação, agregação, publicação de texto) +4. 🖥️ Tela `/dashboard/feedbacks` (abas Pendentes e Recebidos) +5. 🎨 Bloco de corroborações no portfólio público +6. ✉️ E-mail de notificação (sem conteúdo) +7. 📄 FAQ e termos: o que acontece com o feedback ao excluir a conta +**Decisões ainda em aberto:** + +- Estrutura final do schema dos atributos (spike); +- Prazo do blind duplo — 14 dias é proposta, não validada; +- N mínimo = 3 — proposta, revisar com dados reais; +- Manutenção ou remoção definitiva do `rating` interno; +- Existe fluxo de denúncia de feedback pelo avaliado? (afeta painel admin) +--- + +## 21. Histórico de decisões + +| Data | Decisão | +|---|---| +| v1 | Rating contextualizado; anonimato opcional; proibição de ranking; separação entre feedback privado e reputação agregada | +| v2 | **Revogada** a média pública de ratings — contradizia os princípios do próprio documento | +| v2 | Adotado modelo de corroborações por eixos comportamentais fechados | +| v2 | Rótulos com verbo e lastro; proibidos superlativos e traços inatos | +| v2 | Proibida representação com teto (termômetro, barra, estrelas) | +| v2 | Anonimato público fixo; identificação interna permanente | +| v2 | Blind duplo como mitigação de retaliação | +| v2 | N mínimo de 3 atestados para exibição pública | +| v2 | Duplo denominador (pessoas × projetos) | +| v2 | Feedback escrito entregue na área privada; e-mail apenas notifica | +| v2 | Publicação de texto por consentimento na origem | +| v2 | Anonimização assimétrica na exclusão de conta | +| v2 | `rating` despublicado; `anonymous` sem função de produto | \ No newline at end of file diff --git a/docs/02 - produto/portfolio/portfolio.md b/docs/02 - produto/portfolio/portfolio.md index 744b39e5..e21130df 100644 --- a/docs/02 - produto/portfolio/portfolio.md +++ b/docs/02 - produto/portfolio/portfolio.md @@ -1,274 +1,299 @@ # Documento de Produto — Portfólio Público e Privado - -**Classificação:** Documento de Produto / Funcionalidade\ -**Camada:** 2 — Documentos de Produto e Funcionalidades\ -**Status do documento:** Implementado (versão consolidada com visibilidade e segurança) -**Status da implementação:** 🟢 completa — portfólio público, listagem e controle de visibilidade + +**Classificação:** Documento de Produto / Funcionalidade +**Camada:** 2 — Documentos de Produto e Funcionalidades +**Status do documento:** Consolidado — seção de Feedback atualizada para o modelo v2 +**Status da implementação:** 🟡 parcial — portfólio, listagem e visibilidade prontos; bloco de corroborações pendente **Estado consolidado:** ver [estado-das-funcionalidades.md](../estado-das-funcionalidades.md) - + +> 🔄 **Mudança de status.** A versão anterior marcava 🟢 completa. Com a revisão do +> modelo de reputação, o bloco de feedback do portfólio precisa ser reconstruído — +> a exibição atual pressupõe `rating`, que deixou de ser público. + --- - + ## 1. Identificação da Funcionalidade - -- **Nome da funcionalidade:** Portfólio Público por Username + Configuração Privada -- **Domínio do produto:** Usuários / Reputação / Exposição Profissional -- **Documento relacionado:** Documento 0 — Visão Geral, Governança e Arquitetura da Documentação - + +- **Nome:** Portfólio Público por Username + Configuração Privada +- **Domínio:** Usuários / Reputação / Exposição Profissional +- **Documentos relacionados:** Feedback e Reputação; Perfis de Usuário; + Governança de Dados e LGPD; Documento 0 --- - + ## 2. Contexto e Objetivo - -O Portfólio permite que usuários exponham suas informações profissionais dentro da plataforma TryCatch, com controle granular sobre o que é visível para visitantes externos. - -Resolve os seguintes problemas: - + +O Portfólio permite que membros exponham informações profissionais com controle +granular sobre o que é visível externamente. + +Resolve: + - Apresentação estruturada de habilidades e experiências; -- Facilita formação de equipes por meio de transparência profissional; -- Possibilita compartilhamento externo do perfil via link público; -- Garante que cada usuário controle exatamente o que é exposto publicamente. - +- Transparência profissional que facilita formação de equipes; +- Compartilhamento externo do perfil via link público; +- Controle preciso do que cada pessoa expõe. +**Com a erosão do código como evidência de competência, o portfólio ganha uma +função nova:** reunir sinais que uma ferramenta de IA não produz — projetos +concluídos em equipe real e corroborações de conduta dadas por quem trabalhou +junto. + --- - + ## 3. Rotas - -### Rotas Públicas (sem autenticação) - + +### Públicas (sem autenticação) + | Rota | Descrição | -|------|-----------| -| `/portfolios` | Listagem pública paginada de portfólios com filtros | -| `/portfolio/{username}` | Portfólio público individual do usuário | - -### Rotas Privadas (autenticação obrigatória) - +|---|---| +| `/portfolios` | Listagem pública paginada com filtros | +| `/portfolio/{username}` | Portfólio público individual | + +### Privadas (autenticação obrigatória) + | Rota | Descrição | -|------|-----------| -| `/dashboard/portfolio` | Configuração privada do portfólio (visibilidade, bio, links) | - +|---|---| +| `/dashboard/portfolio` | Configuração de visibilidade, bio e links | + --- - + ## 4. Escopo da Funcionalidade - -### 4.1 O que a funcionalidade faz - -- Exibe dados públicos configurados pelo usuário; -- Permite controle granular de visibilidade por meio de toggles; -- Exibe apenas projetos com status **CONCLUIDO**; -- Agrupa múltiplas stacks assumidas pelo usuário dentro de um mesmo projeto; -- Permite listagem pública resumida em `/portfolios` com busca e filtros; -- Permite compartilhamento externo via URL baseada em `username`; + +### 4.1 O que faz + +- Exibe dados públicos configurados pelo titular; +- Controle granular de visibilidade por toggles; +- Exibe apenas projetos `CONCLUIDO`; +- Agrupa múltiplas stacks do mesmo projeto em um card; +- Listagem pública resumida em `/portfolios` com busca e filtros; +- Compartilhamento externo via URL baseada em `username`; - Retorna 404 quando o portfólio não deve ser exibido; -- Permite que o usuário configure bio, GitHub, LinkedIn e visibilidade via dashboard privado. - -### 4.2 O que a funcionalidade não faz - +- Permite configurar bio, GitHub, LinkedIn e visibilidade no dashboard privado. +### 4.2 O que não faz + - Não exibe projetos em andamento ou em busca de equipe; -- Não exibe email no resumo público (`/portfolios`); -- Não expõe dados privados quando toggles estão desativados; -- Não permite edição pública (edição apenas via `/dashboard/portfolio`); -- Não permite descobrir se um usuário existe quando o portfólio é privado. - +- Não exibe email no resumo público; +- Não expõe dados com toggle desativado; +- Não permite edição pública; +- Não revela se um usuário existe quando o portfólio é privado; +- **Não exibe nota, média, ranking ou comparação entre membros.** --- - -## 5. Usuários Envolvidos e Permissões - -### Visitante (não autenticado) - -- Pode acessar `/portfolio/{username}`; -- Pode acessar `/portfolios`. - -### Usuário Autenticado - -- Pode acessar `/dashboard/portfolio`; -- Pode alterar bio, GitHub, LinkedIn e todas as configurações de visibilidade. - -### Restrições - -- Se `portfolioPublic = false`, a rota pública retorna 404. -- Se `isActive = false`, a rota pública retorna 404. -- A resposta 404 é idêntica para usuário inexistente e portfólio privado (não revela existência do usuário). - + +## 5. Usuários e Permissões + +**Visitante:** acessa `/portfolio/{username}` e `/portfolios`. + +**Autenticado:** acessa `/dashboard/portfolio` e altera bio, links e visibilidade. + +**Restrições:** + +- `portfolioPublic = false` → 404; +- `isActive = false` → 404; +- 404 idêntico para usuário inexistente e portfólio privado. --- - + ## 6. Fluxo de Uso (UX) - -### Fluxo público — Listagem - + +### 6.1 Listagem pública + 1. Visitante acessa `/portfolios`; -2. Visualiza cards resumidos com nome, skills e role; -3. Pode filtrar por nome, username, role ou skill; -4. Clica em um card e é direcionado para `/portfolio/{username}`; -5. Visualiza apenas os dados permitidos pelos toggles do usuário. - -### Fluxo público — Portfólio individual - -A página pública é composta pelas seguintes seções (exibidas apenas se o toggle correspondente estiver ativo e o portfólio for público): - +2. Vê cards resumidos com nome, skills e papel; +3. Filtra por nome, username, papel ou skill; +4. Clica e vai para `/portfolio/{username}`. +### 6.2 Portfólio individual + +Seções, exibidas conforme os toggles: + 1. **Identidade** — avatar, nome, bio, email, GitHub, LinkedIn 2. **Tecnologias** — skills cadastradas -3. **Projetos Concluídos** — projetos com status CONCLUIDO +3. **Projetos Concluídos** — apenas status `CONCLUIDO` 4. **Certificados** -5. **Feedback** *(implementado, exibição configurável)* - -### Fluxo privado — Configuração - -1. Usuário autenticado acessa `/dashboard/portfolio`; -2. Visualiza formulário com seus dados e toggles atuais; -3. Altera bio, GitHub, LinkedIn e configurações de visibilidade; -4. Salva via `PATCH /api/portfolio/me`; -5. Mudanças são refletidas imediatamente na rota pública (sem cache). - -### Estados da página pública - -- **404** — usuário inexistente ou portfólio privado; -- **Exibição parcial** — seções ocultas quando toggle desativado; -- **SEO** — metadados dinâmicos (`generateMetadata`) populados com nome e bio do usuário. - +5. **Corroborações** — ver seção 7 +### 6.3 Configuração privada + +1. Acessa `/dashboard/portfolio`; +2. Altera dados e toggles; +3. Salva via `PATCH /api/portfolio/me`; +4. Mudanças refletidas imediatamente na rota pública (sem cache). --- - -## 7. Regras de Negócio - -1. O portfólio público é identificado exclusivamente por `username`. -2. O campo `username` é único no sistema. -3. Se `portfolioPublic = false` → retornar 404. -4. Se `isActive = false` → retornar 404. -5. Email só é exibido se `showEmail = true`. -6. GitHub só é exibido se `showGithub = true`. -7. LinkedIn só é exibido se `showLinkedin = true`. -8. Certificados só são exibidos se `showCertificates = true`. -9. Feedback só é exibido se `showFeedback = true`. -10. Projetos exibidos apenas se `showProjects = true` **e** `ProjectStatus = CONCLUIDO`. -11. O resumo (`/portfolios`) nunca exibe email, certificados ou projetos. -12. Feedback exibe identificação do avaliador no frontend apenas se não for anônimo (`anonymous = false`). -13. O sistema utiliza logging estruturado em todas as rotas de portfólio. -14. Quando um usuário assume múltiplas stacks em um mesmo projeto, o sistema agrupa em um único card (lógica no backend). -15. A rota pública chama o serviço diretamente (sem fetch interno), eliminando latência de cache. - -Todas as regras são aplicadas no backend e testáveis. - + +## 7. Seção de Corroborações — especificação + +> Substitui integralmente a exibição de feedback baseada em `rating`. +> Fonte: `docs/02 - produto/feedback/feedback-reputacao.md`. + +### 7.1 Formato + +``` +🗣️ Avisa antes de travar 4 pessoas · 3 projetos +📦 Entrega o que assume 5 pessoas · 3 projetos +🤝 Puxa a equipe junto 3 pessoas · 2 projetos +``` + +### 7.2 Regras de exibição + +1. Exibida apenas com `showFeedback = true`; +2. Eixo só aparece com **≥ 3 atestados de pessoas distintas** (corte no backend); +3. Sempre com **duplo denominador**: pessoas **e** projetos; +4. Ordenação por volume de atestados; +5. Identidade do avaliador **nunca** exibida; +6. Feedback ocultado por ADMIN não entra na agregação. +### 7.3 Proibições visuais + +Não usar: barra de progresso, termômetro, gauge, estrelas, percentual, nota, +badge de nível, comparação com média da plataforma, ou qualquer elemento com teto +implícito. + +Intensidade pode ser sinalizada por peso tipográfico, opacidade ou tamanho — +nunca por preenchimento. + +### 7.4 Texto de feedback publicado + +Exibido apenas quando **ambas** as condições se cumprem: + +- `publicationAllowed = true` (autor autorizou na escrita); +- `publishedByReceiver = true` (avaliado escolheu exibir). +Exibido sem identificação do autor, com contexto de projeto. + +### 7.5 Estado vazio + +Quem ainda não tem corroborações suficientes **não exibe a seção** — não exibe +seção vazia, nem "0 avaliações", nem mensagem de incompletude. Ausência de +evidência não é sinal negativo. + +### 7.6 Acessibilidade + +- Cada selo tem rótulo textual completo, independente do emoji; +- O emoji é decorativo (`aria-hidden`), nunca portador único de significado; +- Contagens legíveis por leitor de tela em frase completa. --- - -## 8. Impactos em Dados - -### Entidades impactadas - -- `User` — campos de visibilidade e perfil -- `UserSkill` — skills do usuário -- `UserCertificate` — certificados -- `Feedback` — feedbacks recebidos -- `StackTaken` — participação em projetos -- `Project` — projetos com status CONCLUIDO - -### Dados sensíveis e proteção - + +## 8. Regras de Negócio + +1. Portfólio identificado exclusivamente por `username` (único); +2. `portfolioPublic = false` → 404; +3. `isActive = false` → 404; +4. Email exibido só se `showEmail = true`; +5. GitHub só se `showGithub = true`; +6. LinkedIn só se `showLinkedin = true`; +7. Certificados só se `showCertificates = true`; +8. Corroborações só se `showFeedback = true` **e** N mínimo atingido; +9. Projetos só se `showProjects = true` **e** status `CONCLUIDO`; +10. O resumo (`/portfolios`) nunca exibe email, certificados, projetos ou + corroborações; +11. Texto de feedback exige dupla autorização (seção 7.4); +12. Identidade do avaliador nunca é exposta publicamente; +13. Logging estruturado em todas as rotas de portfólio; +14. Múltiplas stacks no mesmo projeto agrupadas em um card, no backend; +15. A rota pública chama o serviço diretamente, sem fetch interno. +Todas aplicadas no backend e testáveis. + +--- + +## 9. Impactos em Dados + +**Entidades:** `User`, `UserSkill`, `UserCertificate`, `Feedback`, +`FeedbackAttribute`, `StackTaken`, `Project`. + | Dado | Controle | -|------|----------| -| Email | Toggle `showEmail`; nunca exposto no resumo | -| GitHub | Toggle `showGithub` | -| LinkedIn | Toggle `showLinkedin` | -| Feedback | Toggle `showFeedback`; avaliador anonimizado se `anonymous = true` | -| Senha | Nunca selecionada em nenhuma query de portfólio | -| `id` interno | Nunca exposto na URL pública (usa `username`) | - +|---|---| +| Email | `showEmail`; nunca no resumo | +| GitHub / LinkedIn | `showGithub` / `showLinkedin` | +| Corroborações | `showFeedback` + N mínimo; avaliador sempre anônimo | +| Texto de feedback | Dupla autorização; autor sempre anônimo | +| Senha | Nunca selecionada em query de portfólio | +| `id` interno | Nunca exposto na URL | + --- - -## 9. Impactos em Reputação e Confiança - -O portfólio público impacta diretamente: - -- Percepção de competência entre membros; -- Formação de equipes; -- Confiança e transparência na plataforma; -- Exposição profissional externa. - + +## 10. Impactos em Reputação e Confiança + +O portfólio é a superfície onde a reputação se torna pública. Isso o torna o ponto +de maior risco de dano involuntário. + Riscos mitigados: - + - Controle granular de visibilidade; -- Exibição apenas de projetos concluídos; -- Impossibilidade de detectar existência de usuário privado via 404 uniforme; -- Logging estruturado para rastreabilidade de acessos. - +- Apenas projetos concluídos; +- 404 uniforme impede detectar existência de conta; +- Sem sinal negativo público; +- N mínimo impede que uma avaliação isolada vire rótulo; +- Duplo denominador dificulta conluio; +- Logging para rastreabilidade. --- - -## 10. Comunicação com o Usuário - + +## 11. Comunicação com o Usuário + - 404 para portfólio inexistente ou privado; -- Mensagens de erro padronizadas via `MESSAGES`; -- Toast de sucesso/erro no dashboard privado ao salvar configurações. - -Não há comunicação transacional (email) associada nesta versão. - +- Mensagens padronizadas via `MESSAGES`; +- Toast de sucesso/erro no dashboard privado; +- Ao ativar `showFeedback`, a interface deve explicar **o que exatamente ficará + visível** — corroborações agregadas e anônimas, nunca notas. --- - -## 11. Antipadrões Evitados - -- Uso de `id` interno na URL pública (substituído por `username`); -- Exposição automática de dados pessoais sem consentimento; + +## 12. Antipadrões Evitados + +- `id` interno na URL pública; +- Exposição de dados pessoais sem consentimento; - Exposição de projetos em andamento; -- `console.log` / `console.error` em produção (substituídos por logger estruturado); -- Retorno 403 para portfólio privado (substituído por 404 por segurança); -- Lógica de agrupamento de projetos no frontend (realizada no backend); -- Fetch HTTP interno com cache no Server Component (substituído por chamada direta ao serviço); -- URL hardcoded `localhost` em produção. - +- `console.*` em runtime; +- 403 para portfólio privado (substituído por 404); +- Agrupamento de projetos no frontend; +- Fetch HTTP interno com cache no Server Component; +- URL `localhost` hardcoded; +- **Média de notas exibida publicamente;** +- **Termômetro, barra ou estrelas na seção de reputação;** +- **Seção de reputação vazia sugerindo perfil incompleto.** --- - -## 12. Relação com Implementação Técnica - -### Documentos técnicos relacionados - + +## 13. Relação com Implementação Técnica + - `docs/03 - tecnico/modelagem/modelagem-dados.md` - `docs/03 - tecnico/arquitetura/arquitetura-geral.md` -- `docs/03 - tecnico/arquitetura/auditoria-logging-backend.md` - -### Templates relacionados - +- `docs/02 - produto/feedback/feedback-reputacao.md` - `docs/templates/02 - template-dados-portfolio.md` - -### Pontos técnicos relevantes - -- `username` é o único identificador público do portfólio; -- A página `/portfolio/{username}` é um Server Component que chama `getPublicPortfolio()` diretamente; -- A página `/dashboard/portfolio` separa server wrapper (auth + layout) de client component (formulário); -- O formulário privado usa React Hook Form + Zod com hook dedicado `usePortfolioSettings`; -- Logger estruturado com timestamp, nível, contexto e metadados em todas as rotas; -- Filtro `ProjectStatus.CONCLUIDO` aplicado na query Prisma; -- A resposta pública retorna projetos já agrupados por `projectId`. - +Pontos relevantes: + +- `username` é o único identificador público; +- `/portfolio/{username}` é Server Component chamando `getPublicPortfolio()`; +- `/dashboard/portfolio` separa server wrapper de client component; +- Formulário privado usa React Hook Form + Zod com `usePortfolioSettings`; +- Filtro `ProjectStatus.CONCLUIDO` na query Prisma; +- Resposta pública retorna projetos já agrupados por `projectId`; +- **Nova:** agregação de corroborações por eixo, com corte de N mínimo no backend. --- - -## 13. Histórico de Decisões - -- Substituição de busca por `id` para `username` na URL pública; -- Retorno 404 (em vez de 403) para portfólio privado; -- Implementação de toggles de visibilidade granulares; -- Restrição de exibição a projetos com status CONCLUIDO; -- Adoção de logging estruturado em todas as rotas; -- Agrupamento de stacks por projeto realizado no backend; -- Chamada direta ao serviço no Server Component (elimina cache e dependência de URL local); -- Separação de server component e client component na rota privada. - + +## 14. Histórico de Decisões + +- Substituição de `id` por `username` na URL pública; +- 404 em vez de 403 para portfólio privado; +- Toggles de visibilidade granulares; +- Exibição restrita a projetos `CONCLUIDO`; +- Logging estruturado; +- Agrupamento de stacks no backend; +- Chamada direta ao serviço no Server Component; +- Separação server/client na rota privada; +- **Substituída a exibição de feedback por nota pelo bloco de corroborações;** +- **Proibida qualquer representação com teto na seção de reputação;** +- **Texto de feedback só publicado com dupla autorização.** --- - -## 14. Status e Próximos Passos - -### Status atual - -Implementado — visibilidade, segurança, logging e separação público/privado concluídos. - -### Itens concluídos nesta iteração - -- ✅ Controle de visibilidade por toggle (backend + frontend) -- ✅ Logging estruturado em todas as rotas de portfólio -- ✅ SEO com `generateMetadata` dinâmico -- ✅ Separação clara entre rota pública e privada -- ✅ Eliminação de cache e URL hardcoded no Server Component -- ✅ Correção do PATCH (dados não estavam sendo persistidos) -- ✅ Suporte a GitHub e LinkedIn no PATCH - -### Próximos passos - -- Criar geração automática de `username` no cadastro; -- Permitir edição de `username` pelo usuário; -- Definir modelo definitivo de reputação e média de feedback; -- Implementar versão interna ampliada para formação de equipes; -- Revisar padronização visual do portfólio. + +## 15. Status e Próximos Passos + +### Concluído + +- ✅ Controle de visibilidade por toggle +- ✅ Logging estruturado +- ✅ SEO com `generateMetadata` +- ✅ Separação pública/privada +- ✅ Eliminação de cache e URL hardcoded +- ✅ Correção do PATCH +- ✅ Suporte a GitHub e LinkedIn +### Pendente + +- 🔴 Bloco de corroborações (depende do modelo de feedback v2) +- 🔴 Exibição de texto de feedback com dupla autorização +- 🟡 Tela para cadastro de certificados pelo próprio membro +- 🟡 Geração automática de `username` no cadastro +- 🟡 Edição de `username` pelo titular +- ⚪ Versão interna ampliada para formação de equipes +- ⚪ Revisão de padronização visual + \ No newline at end of file diff --git a/docs/03 - tecnico/adrs/adrs.md b/docs/03 - tecnico/adrs/adrs.md index 6b4c0d70..d9a3ac36 100644 --- a/docs/03 - tecnico/adrs/adrs.md +++ b/docs/03 - tecnico/adrs/adrs.md @@ -1,19 +1,256 @@ -# Documento Técnico --- ADRs (Architecture Decision Records) - -Classificação: Documento Técnico\ -Camada: 3 --- Técnico - -## ADR-001 - -Decisão: Uso de Next.js com App Router.\ -Motivo: Integração frontend/backend simplificada. - -## ADR-002 - -Decisão: Uso de Prisma ORM.\ -Motivo: Tipagem forte e produtividade. - -## ADR-003 - -Decisão: Monólito modular.\ -Motivo: Simplicidade inicial e controle de complexidade. +# Documento Técnico — ADRs (Architecture Decision Records) + +**Classificação:** Documento Técnico +**Camada:** 3 — Técnico +**Status:** Consolidado — registro único de decisões arquiteturais + +> 🔀 **Consolidação.** O arquivo `adr-email-templates.md` existia solto, sem +> número ("ADR-XXX") e fora deste registro. Ele foi incorporado como **ADR-004** e +> **deve ser removido do repositório.** + +--- + +## Como usar este documento + +Uma ADR registra uma decisão arquitetural: o contexto que a exigiu, a decisão +tomada, as alternativas descartadas e as consequências aceitas. + +**Regras:** + +- ADR recebe número sequencial no momento da criação. Nunca "ADR-XXX"; +- ADR não é apagada. Decisão superada recebe status `Substituída por ADR-NNN`; +- Toda decisão arquitetural relevante gera ADR — ver Documento Estratégico — + Modelo de Gestão de Trabalho, seção 7; +- ADR extensa pode viver em arquivo próprio, desde que **listada aqui** com número, + título, status e link. +**Status possíveis:** `Proposta` · `Aprovada` · `Substituída por ADR-NNN` · +`Revogada` + +--- + +## Índice + +| ADR | Título | Status | Data | +|---|---|---|---| +| 001 | Next.js com App Router | Aprovada | — | +| 002 | Prisma ORM | Aprovada | — | +| 003 | Monólito modular | Aprovada | — | +| 004 | Templates de e-mail com React Email | Aprovada | 2026-02-25 | +| 005 | Logger estruturado centralizado | Aprovada | 2026-06-14 | +| 006 | `username` como identificador público e 404 uniforme | Aprovada | — | +| 007 | Camada de serviço separada do route handler | Aprovada | — | +| 008 | Modelo de reputação por corroborações | Proposta | — | + +--- + +## ADR-001 — Next.js com App Router + +**Status:** Aprovada + +**Contexto.** O projeto precisa de frontend e backend em uma base única, com +renderização no servidor e boa experiência de desenvolvimento. + +**Decisão.** Adotar Next.js com App Router. + +**Alternativas.** SPA React + API Node separada (mais peças, mais deploy); Remix +(menor familiaridade da comunidade-alvo). + +**Consequências.** Integração simplificada; acoplamento ao ciclo de releases do +Next; particularidades do App Router (como `params` assíncrono no Next 16) viram +armadilha para quem chega. + +--- + +## ADR-002 — Prisma ORM + +**Status:** Aprovada + +**Contexto.** Acesso a PostgreSQL com tipagem forte e migrations controladas. + +**Decisão.** Adotar Prisma ORM. + +**Alternativas.** SQL direto (mais controle, menos produtividade); TypeORM, +Drizzle. + +**Consequências.** Tipagem forte e produtividade; `prisma generate` obrigatório +após instalação (resolvido via `postinstall`); atenção permanente a `select`/`omit` +para não vazar campos sensíveis. + +--- + +## ADR-003 — Monólito modular + +**Status:** Aprovada + +**Contexto.** Projeto em estágio inicial, equipe variável, sem carga que +justifique distribuição. + +**Decisão.** Monólito modular evolutivo, com separação lógica por domínio. + +**Alternativas.** Microsserviços (complexidade sem benefício no estágio atual). + +**Consequências.** Simplicidade de deploy e onboarding; disciplina de fronteira +entre domínios fica por conta da equipe. Critérios de separação futura em +`arquitetura-geral.md`, seção 12. + +--- + +## ADR-004 — Templates de e-mail com React Email + +**Status:** Aprovada +**Data:** 2026-02-25 + +**Contexto.** A plataforma possui múltiplos e-mails transacionais (solicitação de +convite para admin, confirmação para o usuário, reset de senha, contato). Parte +usava HTML inline dentro do service, gerando duplicação de estrutura, dificuldade +de manutenção, inconsistência visual e acoplamento entre layout e lógica. + +**Decisão.** Adotar **React Email** como padrão oficial de templates. + +Definições: + +- Todo template usa `EmailLayout`; +- Nenhum HTML inline em service; +- Envio centralizado via `lib/mail`; +- SDK Resend; +- Cliente Resend instanciado por factory `getResend()` (lazy initialization). +Estrutura: + +``` +lib/ + mail/ + templates/ + layout/ + layout.tsx + emails-styles.ts + contact-sender.tsx + invite-request-confirmation.tsx + invite-request-receiver.tsx + invite-request-sender.tsx + reset-password.tsx + resend.ts + send-invite-request-confirmation-email.ts + send-invite-request-email.ts + send-reset-password-email.ts +``` + +**Sobre a factory.** O cliente **não** é instanciado no nível do módulo. +`resend.ts` exporta `getResend()`, que cria a instância sob demanda durante o +runtime da requisição: + +```ts +export function getResend(): Resend { + // inicializa apenas quando chamado, não no import +} +``` + +Isso evita que a verificação de `RESEND_API_KEY` ocorra durante o build do Next +(fase de coleta de dados das páginas), que causava crash quando a variável não +estava disponível em build time. + +Testes devem mockar `getResend`, não uma instância global. + +**Alternativas.** Manter HTML inline; templates do próprio Resend; string HTML +simples. Descartadas por padronização e escalabilidade menores. + +**Consequências.** Padronização visual, reuso de layout, melhor testabilidade e +separação de responsabilidades; em troca, uma dependência a mais e leve aumento de +complexidade inicial. + +**Impacto.** Infraestrutura / Comunicação. Não impacta banco, domínio nem regras +de negócio. + +--- + +## ADR-005 — Logger estruturado centralizado + +**Status:** Aprovada +**Data:** 2026-06-14 +**Issue:** #536 + +**Contexto.** Auditoria de 2026-05-17 encontrou 1 rota com logger estruturado, 37 +com `console` direto e 15 sem logging algum. Sem padrão, não há rastreabilidade +nem caminho de migração para serviço externo. + +**Decisão.** Logger centralizado em `src/lib/logger.ts`, saída JSON com +`timestamp`, `level`, `context`, `message` e `metadata`. `console.*` proibido em +código de runtime; scripts de CLI permanecem como exceção. + +**Consequências.** Cobertura uniforme; destino trocável sem alterar chamadores; +disciplina permanente para não registrar dado pessoal em `metadata`. + +Detalhamento em `docs/03 - tecnico/arquitetura/auditoria-logging-backend.md`. + +--- + +## ADR-006 — `username` como identificador público e 404 uniforme + +**Status:** Aprovada + +**Contexto.** A rota pública de portfólio usava `id` interno, expondo +identificador de banco. Além disso, portfólio privado retornava 403 — o que +confirmava a existência da conta. + +**Decisão.** URL pública usa exclusivamente `username` (único). Portfólio privado, +usuário inativo e usuário inexistente retornam **404 idêntico**. + +**Alternativas.** Manter `id` (expõe interno); usar 403 para privado (enumeração +de contas). + +**Consequências.** Não é possível descobrir se uma conta existe pela rota pública; +`username` precisa ser único e sua alteração quebra links externos — geração +automática no cadastro e edição pelo titular seguem pendentes. + +--- + +## ADR-007 — Camada de serviço separada do route handler + +**Status:** Aprovada + +**Contexto.** Lógica de negócio dentro de route handlers impede reuso por Server +Components e dificulta teste unitário. + +**Decisão.** Lógica em `src/lib/*.service.ts`; handler apenas orquestra. Serviços +lançam erros semânticos; handlers mapeiam para HTTP. Server Components chamam o +serviço diretamente, sem fetch HTTP interno. + +**Consequências.** Elimina latência de serialização, cache implícito e dependência +de URL local; testes unitários de rota passam a mockar o service, não o Prisma. + +Referência: `src/lib/portfolio.service.ts`. + +--- + +## ADR-008 — Modelo de reputação por corroborações + +**Status:** **Proposta** — aguarda spike de schema + +**Contexto.** O modelo original previa `rating` numérico agregado como média +simples exibida no portfólio. Isso contradiz os princípios declarados no próprio +documento de produto e nos textos institucionais: sem ranking, sem nota pública, +foco em aprendizado. Uma média pública **é** uma nota; duas médias lado a lado +**são** um ranking. + +Há ainda o problema de fundo: com IA gerando projetos inteiros, código deixou de +ser evidência de competência colaborativa. + +**Decisão proposta.** Substituir a nota agregada por **corroborações**: atestados +de comportamento observável, escolhidos de lista fechada de seis eixos, exibidos +com duplo denominador (pessoas × projetos), sem teto e com N mínimo de 3. +Feedback escrito vive em área privada; publicação exige consentimento do autor na +origem e do avaliado no destino. `rating` é despublicado e mantido como sinal +interno. + +**Alternativas.** Manter média (contradiz princípios); nota por competência +(continua sendo nota, com mais superfície de comparação); só texto livre (não +agrega, não compara, não sustenta portfólio). + +**Consequências.** Exige migration (nova entidade ou enum de atributos) e nova +rota de agregação; sinal anônimo é menos verificável externamente — mitigado pelo +duplo denominador; agregação por perfil fica mais cara que uma média e precisa ser +medida. + +**Pendências para aprovação:** estrutura final do schema; prazo do blind duplo; +validação do N mínimo com dados reais. + +Detalhamento em `docs/02 - produto/feedback/feedback-reputacao.md`. \ No newline at end of file diff --git a/docs/03 - tecnico/arquitetura/arquitetura-geral-atualizado.md b/docs/03 - tecnico/arquitetura/arquitetura-geral-atualizado.md deleted file mode 100644 index 979ce19c..00000000 --- a/docs/03 - tecnico/arquitetura/arquitetura-geral-atualizado.md +++ /dev/null @@ -1,145 +0,0 @@ -# Documento Técnico --- Arquitetura Geral - -Classificação: Documento Técnico\ -Camada: 3 --- Técnico\ -Status: Atualizado após implementação do Portfólio Público, logging estruturado e refatorações de layout - ------------------------------------------------------------------------- - -## 1. Stack Principal - -- Next.js (App Router) -- TypeScript -- Prisma ORM -- PostgreSQL -- NextAuth v4 -- TanStack Query v5 (estado de servidor no cliente) - ------------------------------------------------------------------------- - -## 2. Modelo Arquitetural - -Monólito modular evolutivo. - -Separação lógica por domínios com possibilidade futura de extração de -serviços conforme critérios definidos. - ------------------------------------------------------------------------- - -## 3. Separação de Domínios - -- Portfólio (público e privado) -- Autenticação -- Feedback -- Convites -- Projetos -- Produto - ------------------------------------------------------------------------- - -## 4. Estrutura de Rotas (App Router) - -``` -src/app/ - (auth)/ # Login, registro, esqueci/reset senha — sem layout wrapper - (public)/ # Landing, listagem de portfólios, portfólio individual - (private)/ # /dashboard/** — todas as rotas exigem sessão ativa - api/ # Route handlers (Next.js App Router) -``` - ------------------------------------------------------------------------- - -## 5. Providers Globais - -Todos os providers da aplicação são centralizados em `src/providers/index.tsx` -e incluídos uma única vez no layout raiz (`src/app/layout.tsx`). - -Providers ativos: - -- `QueryProvider` — TanStack Query client para estado de servidor -- `SessionProvider` — NextAuth session context - ------------------------------------------------------------------------- - -## 6. Layout do Dashboard - -O dashboard usa um layout compartilhado em -`src/app/(private)/dashboard/layout.tsx` como shell único para todas as -rotas privadas (Navbar + DashboardHeader + área de conteúdo principal). - -O componente `BasePage` foi removido — ele duplicava Navbar e Header em -cada página individualmente. - ------------------------------------------------------------------------- - -## 7. Camada de Serviço - -Lógica de query complexa fica em arquivos de serviço dedicados em vez de -dentro dos route handlers. - -Exemplo: `src/lib/portfolio.service.ts` com `getPublicPortfolio()` e -`listPublicPortfolios()`. - -Serviços lançam erros semânticos (ex.: `PortfolioNotFoundError`) para que -os handlers mapeiem para códigos HTTP corretos sem acoplamento de domínio. - -Server Components que precisam de dados chamam os serviços diretamente -(sem fetch HTTP interno), eliminando latência de serialização e dependência -de URL local. - ------------------------------------------------------------------------- - -## 8. Máquina de Estados --- Project - -Fluxo oficial: - -BUSCANDO\ -↓ (todas stacks assumidas automaticamente)\ -EM_ANDAMENTO\ -↓ (ação manual do owner)\ -CONCLUIDO - -Regras técnicas: - -- Transição BUSCANDO → EM_ANDAMENTO ocorre automaticamente. -- Transição EM_ANDAMENTO → CONCLUIDO é manual e exclusiva do owner. -- Projeto concluído não retorna para EM_ANDAMENTO (salvo decisão - futura formal). - ------------------------------------------------------------------------- - -## 9. Regra Técnica de Edição Condicional (Project) - -Antes de existir qualquer StackTaken: - Update completo permitido. - -Após existir pelo menos um StackTaken: - Bloqueio de edição -estrutural. - Permitido apenas append de observação na descrição. - -Concatenação deve ocorrer no backend. - Backend não deve aceitar -substituição completa da descrição. - ------------------------------------------------------------------------- - -## 10. Escalabilidade - -Critérios para futura separação de serviços: - -- Crescimento de carga. -- Necessidade de integração externa. -- Gargalos identificados. -- Complexidade excessiva em domínio específico. - ------------------------------------------------------------------------- - -## 11. Observabilidade - -- Logs estruturados obrigatórios em todas as rotas de API. -- Logger centralizado em `src/lib/logger.ts` com assinatura - `logger.info/warn/error(message, context, metadata)`. -- Registro de ações críticas: - - Alteração de status de projeto. - - Tentativas bloqueadas de edição estrutural. - - Encerramento manual. - - Ações críticas de portfólio (GET, PATCH, erros de autenticação). -- Proibição de `console.log` em código de runtime. -- Auditoria completa de logging registrada em - `docs/03 - tecnico/arquitetura/auditoria-logging-backend.md`. diff --git a/docs/03 - tecnico/arquitetura/arquitetura-geral.md b/docs/03 - tecnico/arquitetura/arquitetura-geral.md index 52ada6b0..4f153356 100644 --- a/docs/03 - tecnico/arquitetura/arquitetura-geral.md +++ b/docs/03 - tecnico/arquitetura/arquitetura-geral.md @@ -1,34 +1,195 @@ -# Documento Técnico --- Arquitetura Geral - -Classificação: Documento Técnico\ -Camada: 3 --- Técnico - -## 1. Stack Principal - -- Next.js (App Router) -- TypeScript -- Prisma ORM -- PostgreSQL -- NextAuth - -## 2. Modelo Arquitetural - +# Documento Técnico — Arquitetura Geral + +**Classificação:** Documento Técnico +**Camada:** 3 — Técnico +**Status:** Consolidado — substitui `arquitetura-geral.md` e `arquitetura-geral-atualizado.md` + +> 🔀 **Consolidação.** Existiam dois arquivos com o mesmo título e conteúdos +> divergentes. Este documento os funde. O arquivo `arquitetura-geral-atualizado.md` +> **deve ser removido do repositório** — manter dois documentos concorrentes viola +> o Documento 0, seção 4. + +--- + +## 1. Stack principal + +- Next.js 16 (App Router) +- TypeScript +- Prisma 7 + PostgreSQL +- NextAuth v4 (JWT) +- TanStack Query v5 (estado de servidor no cliente) +- Tailwind 4 +- Zod 4 +- Jest +--- + +## 2. Modelo arquitetural + Monólito modular evolutivo. - -## 3. Separação de Domínios - -- Produto -- Autenticação -- Feedback -- Convites -- Projetos - -## 4. Escalabilidade - -Critérios para futura separação de serviços: - Crescimento de carga. - -Necessidade de integração externa. - Gargalos identificados. - -## 5. Observabilidade - -- Logs estruturados. -- Registro de ações críticas. + +Separação lógica por domínios, com possibilidade futura de extração de serviços +conforme os critérios da seção 12. + +--- + +## 3. Separação de domínios + +- Autenticação +- Perfis e Portfólio (público e privado) +- Projetos +- Skills e Stacks +- Convites +- Feedback e Reputação +- Administração +--- + +## 4. Estrutura de rotas (App Router) + +``` +src/app/ + (auth)/ # Login, registro, esqueci/reset senha — sem layout wrapper + (public)/ # Landing, listagem de portfólios, portfólio individual + (private)/ # /dashboard/** — todas as rotas exigem sessão ativa + api/ # Route handlers +``` + +--- + +## 5. Providers globais + +Centralizados em `src/providers/index.tsx`, incluídos uma única vez no layout raiz +(`src/app/layout.tsx`). + +- `QueryProvider` — TanStack Query +- `SessionProvider` — NextAuth +--- + +## 6. Layout do dashboard + +Shell único em `src/app/(private)/dashboard/layout.tsx` (Navbar + DashboardHeader ++ área de conteúdo) para todas as rotas privadas. +O componente `BasePage` foi removido — duplicava Navbar e Header em cada página. + +--- + +## 7. Camada de serviço + +Lógica de negócio em `src/lib/*.service.ts`. O route handler apenas orquestra: +valida entrada, chama o serviço, mapeia erro para status HTTP. + +Referência de qualidade: `src/lib/portfolio.service.ts`, com `getPublicPortfolio()` +e `listPublicPortfolios()`. + +Serviços lançam erros semânticos (ex.: `PortfolioNotFoundError`) para que os +handlers mapeiem códigos HTTP sem acoplar domínio a transporte. + +Server Components que precisam de dados chamam os serviços diretamente, sem fetch +HTTP interno — elimina latência de serialização e dependência de URL local. + +--- + +## 8. Padrões obrigatórios de rota + +- Validação de entrada com **Zod**, na borda (início do handler); +- Verificação de sessão via `checkAuth` em toda rota nova; +- Verificação de propriedade do recurso, não apenas de identidade; +- Respostas via `buildResponse` (`src/constants/messages.ts`); +- Mensagens de usuário em `MESSAGES`; +- Log via `logger` (`src/lib/logger.ts`) — `console.*` proibido em runtime. +--- + +## 9. Máquina de estados — Project + +``` +BUSCANDO + ↓ (automático, quando todas as stacks são assumidas) +EM_ANDAMENTO + ↓ (ação manual e exclusiva do owner) +CONCLUIDO +``` + +Regras: + +- `BUSCANDO → EM_ANDAMENTO` é automática; +- `EM_ANDAMENTO → CONCLUIDO` é manual e exclusiva do owner; +- Projeto concluído não retorna a `EM_ANDAMENTO`, salvo decisão futura formal; +- **`CONCLUIDO` é pré-requisito de todo o sistema de Feedback.** +> ⚠️ O encerramento manual **não está implementado** (épico #553). Consequência +> arquitetural: o domínio de Feedback está inalcançável em runtime. + +--- + +## 10. Regra de edição condicional (Project) + +Antes de existir qualquer `StackTaken`: update completo permitido. + +Depois de existir ao menos um `StackTaken`: bloqueio de edição estrutural; +permitido apenas append de observação à descrição, concatenado no backend com +date stamp. O backend não aceita substituição integral da descrição. + +> ⚠️ **A regra está desativada em produção** por defeito na comparação de datas — +> ela travava a edição por completo. A direção acordada é **notificar os +> participantes em vez de bloquear**, mas essa decisão de produto ainda não foi +> desenhada. + +--- + +## 11. Observabilidade + +- Logging estruturado obrigatório em todas as rotas de API; +- Logger centralizado em `src/lib/logger.ts`, assinatura + `logger.info|warn|error(message, context, metadata)`; +- `context` no formato `'MÉTODO /api/rota'`; +- `metadata` nunca contém senha, token, e-mail completo ou dado pessoal; +- Ações críticas registradas: alteração de status de projeto, tentativa bloqueada + de edição estrutural, encerramento manual, ações de portfólio, criação e + ocultação de feedback; +- Auditoria completa em + `docs/03 - tecnico/arquitetura/auditoria-logging-backend.md`. +--- + +## 12. Escalabilidade + +Critérios para futura separação de serviços: + +- Crescimento de carga; +- Necessidade de integração externa; +- Gargalos identificados; +- Complexidade excessiva em domínio específico. +Nenhum critério está atendido hoje. **Não separar por antecipação.** + +--- + +## 13. Dívidas técnicas conhecidas + +Registradas aqui porque afetam decisão arquitetural, não apenas manutenção. + +| Dívida | Impacto | Ref. | +|---|---|---| +| `typescript.ignoreBuildErrors: true` no `next.config.ts` | Build passar não significa que compila; ~120 erros de tipo conhecidos | BUG-01 | +| `params` como `Promise` no Next 16, ~20 rotas tipadas como síncrono | Rotas quebradas em runtime | BUG-02 | +| Nenhuma rota usa `select`/`omit` do Prisma | `User` retornado com hash de senha — **falha de segurança ativa** | SEC-03 | +| Dependências com vulnerabilidade | 10 apontamentos em `npm audit` | SEC-07 | +| `package-lock.json` só pode ser gerado em Linux | Lockfile de Windows/macOS quebra o CI | Regra 7 | + +**Não replicar esses padrões em código novo.** Correção segue o backlog; não +corrigir por conta própria fora de escopo. + +--- + +## 14. Relação com outros documentos + +- `docs/03 - tecnico/modelagem/modelagem-dados.md` +- `docs/03 - tecnico/arquitetura/auditoria-logging-backend.md` +- `docs/03 - tecnico/arquitetura/tratamento-de-erros.md` +- `docs/03 - tecnico/adrs.md` +- `docs/04 - processo/ci-e-validacao.md` +--- + +## 15. Histórico + +| Data | Alteração | +|---|---| +| — | Versão inicial | +| — | Atualização após Portfólio Público, logging estruturado e refatoração de layout | +| Atual | **Consolidação dos dois arquivos divergentes**; adicionadas seções de padrões de rota, dívidas técnicas e dependência do Feedback sobre o encerramento de projeto | \ No newline at end of file diff --git a/docs/03 - tecnico/modelagem/modelagem-dados.md b/docs/03 - tecnico/modelagem/modelagem-dados.md index 8ca92e85..b5806433 100644 --- a/docs/03 - tecnico/modelagem/modelagem-dados.md +++ b/docs/03 - tecnico/modelagem/modelagem-dados.md @@ -1,218 +1,255 @@ -# Documento Técnico --- Modelagem de Dados - -Classificação: Documento Técnico\ -Camada: 3 --- Técnico\ -Status: Atualizado após implementação do Portfólio Público por Username + Segurança e Logging (issue #527) - ------------------------------------------------------------------------- - +# Documento Técnico — Modelagem de Dados + +**Classificação:** Documento Técnico +**Camada:** 3 — Técnico +**Status:** Atualizado — seção de Feedback revisada conforme modelo de reputação v2 + +--- + ## 1. Entidades Principais - + ### User - + #### Identificadores - -- **id**: Identificador interno único (uso exclusivo do sistema). -- **userName**: Identificador público único (`@unique`). - - Utilizado como chave pública na rota `/portfolio/{username}`. - - Substitui o uso de `id` para exposição externa. - - Pode ser alterado pelo usuário (regra de produto). - - Deve ser único no sistema. - + +- **id** — identificador interno único, uso exclusivo do sistema. +- **userName** — identificador público único (`@unique`). + - Chave pública na rota `/portfolio/{username}`; + - Substitui `id` para exposição externa; + - Pode ser alterado pelo usuário (regra de produto); + - Deve ser único no sistema. #### Campos de Perfil - -- **bio**: Texto de apresentação. -- **github**: URL do perfil no GitHub (nullable; string vazia convertida para `null` no backend). -- **linkedin**: URL do perfil no LinkedIn (nullable; mesma regra do GitHub). -- **avatar**: URL do avatar. - + +- **bio** — texto de apresentação; +- **github** — URL (nullable; string vazia convertida para `null` no backend); +- **linkedin** — URL (nullable; mesma regra); +- **avatar** — URL do avatar. #### Campos de Controle de Visibilidade - -- **showEmail**: controla exibição pública do email. -- **showGithub**: controla exibição pública do GitHub. -- **showLinkedin**: controla exibição pública do LinkedIn. -- **showCertificates**: controla exibição pública de certificados. -- **showProjects**: controla exibição pública de projetos. -- **showFeedback**: controla exibição pública de feedbacks. -- **portfolioPublic**: define se o portfólio pode ser acessado publicamente. - + +- **showEmail**, **showGithub**, **showLinkedin**, **showCertificates**, + **showProjects**, **showFeedback**; +- **portfolioPublic** — define se o portfólio é acessível publicamente. #### Campos de Controle Sistêmico - -- **isActive**: define se o usuário está ativo na plataforma. - + +- **isActive** — define se o usuário está ativo na plataforma. #### Observações Arquiteturais - -- O campo `emailVisible` foi removido para padronização. -- O `id` nunca deve ser utilizado como identificador público. -- A separação entre identificador interno (`id`) e público (`userName`) é obrigatória. -- Campos `github` e `linkedin` aceitam URL válida ou `null`. String vazia enviada pelo cliente é convertida para `null` antes da persistência. - ------------------------------------------------------------------------- - + +- O campo `emailVisible` foi removido por padronização; +- `id` nunca deve ser usado como identificador público; +- A separação entre identificador interno (`id`) e público (`userName`) é + obrigatória; +- `github` e `linkedin` aceitam URL válida ou `null`. +--- + ### Project - -- Possui enumeração **ProjectStatus**: - - `BUSCANDO` - - `EM_ANDAMENTO` - - `CONCLUIDO` - + +Enumeração **ProjectStatus**: `BUSCANDO`, `EM_ANDAMENTO`, `CONCLUIDO`. + #### Regra de Exposição Pública - -- Apenas projetos com status **CONCLUIDO** podem ser exibidos no portfólio público. -- Projetos em `BUSCANDO` ou `EM_ANDAMENTO` não são elegíveis para exposição pública. - ------------------------------------------------------------------------- - + +- Apenas projetos `CONCLUIDO` podem ser exibidos no portfólio público; +- `BUSCANDO` e `EM_ANDAMENTO` não são elegíveis. +#### Campo `totalValue` + +Valor **declarado** do projeto, quando houver. Não representa transação: a +plataforma não intermedia nem processa pagamento. Ver +`docs/01 - estrategia/visao-produto.md`, seção 7.1. + +--- + ### Feedback - -- Relaciona dois usuários (avaliador e avaliado). -- O campo `fromUser` é persistido no banco para rastreabilidade. -- No frontend público, a identificação do avaliador é anonimizada se `anonymous = true`. -- A reputação atualmente é calculada como média simples dos ratings recebidos. - ------------------------------------------------------------------------- - + +> ⚠️ **Esta seção foi revisada.** A versão anterior afirmava: *"a reputação +> atualmente é calculada como média simples dos ratings recebidos"*. **Essa +> afirmação está revogada** por `docs/02 - produto/feedback/feedback-reputacao.md` +> (v2). Média pública de notas contradiz os princípios declarados do produto. + +#### Estado atual do schema + +- Relaciona dois usuários (`fromUserId` avaliador, `toUserId` avaliado); +- Vinculado obrigatoriamente a `projectId`; +- Vínculo opcional a `stackTakenId`; +- Campos existentes: `rating`, `comment`, `anonymous`. +#### Modelo alvo (v2) — exige migration + +A reputação deixa de ser numérica e passa a ser composta por **corroborações**: +atestados de comportamento observável, de lista fechada. + +Estrutura proposta (pendente de spike técnico): + +- `Feedback` ganha `publicationAllowed`, `publishedByReceiver`, `hiddenByAdmin`, + `hiddenReason`; +- Nova entidade `FeedbackAttribute` (ou array de enum) com os eixos; +- Enum `FeedbackAttrEnum` com seis valores fixos; +- Restrição de unicidade em `(projectId, fromUserId, toUserId)`. +#### Destino dos campos legados + +| Campo | Destino | +|---|---| +| `rating` | Despublicado. Passa a `Int?`, sinal interno para ADMIN. Nunca agregado publicamente. | +| `anonymous` | Sem função de produto. Exibição pública é sempre anônima por regra fixa. Código novo não deve lê-lo. | + +#### Regras de persistência + +- `fromUserId` é sempre persistido — a identidade do avaliador nunca é anônima no + banco; +- Feedback não é editável nem excluível pelo autor; +- Na exclusão de conta aplica-se **anonimização assimétrica**: feedbacks recebidos + são excluídos; feedbacks dados a terceiros são preservados com `fromUserId` + substituído por marcador de conta removida. Ver + `docs/01 - estrategia/governanca/governanca-dados-lgpd.md`, seção 6.3. +#### Agregação pública + +A consulta pública devolve, por eixo: contagem de **avaliadores distintos** e +contagem de **projetos distintos**, filtrando `hiddenByAdmin = false`, com corte +de N mínimo (3) aplicado **no backend**. + +--- + ### UserAvailability - -Representa a disponibilidade semanal de um usuário para participar de projetos. - -- **weekday**: dia da semana (0 = domingo … 6 = sábado). -- **startTime** / **endTime**: horário de disponibilidade no formato `HH:MM`. -- **userId**: referência ao usuário dono da disponibilidade. - + +Disponibilidade semanal do usuário. + +- **weekday** — 0 (domingo) a 6 (sábado); +- **startTime** / **endTime** — formato `HH:MM`; +- **userId** — referência ao dono. +Regra: um único registro por usuário por dia da semana. + #### Gerenciamento de Skills via UserAvailability - -Skills do usuário são gerenciadas junto com a disponibilidade via `POST /api/user-availability`. O padrão utilizado é **delete-then-recreate** dentro de uma transação: - -1. `UserSkill.deleteMany({ where: { userId } })` — remove todos os vínculos existentes. -2. `UserSkill.createMany(...)` — recria os vínculos com os skillIds enviados. - -Isso garante consistência sem precisar diferenciar inserções de atualizações. - ------------------------------------------------------------------------- - + +Skills são gerenciadas junto com a disponibilidade via +`POST /api/user-availability`, com padrão **delete-then-recreate** em transação: + +1. `UserSkill.deleteMany({ where: { userId } })` +2. `UserSkill.createMany(...)` +Condição de execução: `if (skills !== undefined)` — array vazio limpa todas as +skills. + +> 🔍 **Observação para revisão futura.** Gerenciar skills dentro da rota de +> disponibilidade acopla dois domínios distintos. Funciona, mas é +> contraintuitivo para quem chega. Candidato a issue própria — não corrigir fora +> de escopo. + +--- + ### Invite - -Entidade responsável pelo controle de convites para criação de usuários. - ------------------------------------------------------------------------- - -### Stack - -Representa tecnologias associadas a projetos e usuários. - ------------------------------------------------------------------------- - -### Skill - -Representa habilidades individuais associadas a usuários via `UserSkill`. - ------------------------------------------------------------------------- - + +Controle de convites para criação de usuários. Campos: `id`, `email`, `code`, +`used`, `invitedBy`, `role`, `createdAt`, `usedAt`. + +--- + +### Stack e Skill + +- **Stack** — tecnologia base, associada a projetos via `ProjectStack` e a pessoas + via `StackTaken`; +- **Skill** — habilidade individual, associada a usuários via `UserSkill` e a + projetos via `ProjectSkill`. +--- + ## 2. Relações - -- Usuários participam de Projetos via `StackTaken`. -- Feedback está vinculado a Projeto e Usuários. -- Invite vincula criação de User. -- User possui múltiplas Skills via `UserSkill`. -- User possui múltiplos Certificados via `UserCertificate`. -- User possui múltiplas disponibilidades via `UserAvailability`. - ------------------------------------------------------------------------- - + +- Usuários participam de Projetos via `StackTaken`; +- Feedback vincula-se a Projeto e a dois Usuários; +- Invite vincula-se à criação de User; +- User possui múltiplas Skills (`UserSkill`), Certificados (`UserCertificate`) e + disponibilidades (`UserAvailability`). +--- + ## 3. Regras de Exposição Pública - -As seguintes regras são aplicadas nas rotas públicas e validadas no serviço `getPublicPortfolio()`: - -1. A URL pública utiliza exclusivamente `userName`. -2. Se o usuário não existir → retornar 404. -3. Se `isActive = false` → retornar 404. -4. Se `portfolioPublic = false` → retornar 404. -5. Campos são exibidos apenas se seus respectivos toggles estiverem ativos. -6. Apenas projetos com `ProjectStatus.CONCLUIDO` são exibidos. -7. Email nunca é exibido no resumo público (`/portfolios`). -8. Certificados e projetos não aparecem na listagem resumida. -9. Feedback é exibido apenas se `showFeedback = true`. -10. As respostas 404 para usuário inexistente e portfólio privado são idênticas (não revelam existência do usuário). - -Essas regras são aplicadas no backend e não dependem do frontend. - ------------------------------------------------------------------------- - + +Aplicadas no serviço `getPublicPortfolio()`: + +1. A URL pública usa exclusivamente `userName`; +2. Usuário inexistente → 404; +3. `isActive = false` → 404; +4. `portfolioPublic = false` → 404; +5. Campos exibidos apenas com o respectivo toggle ativo; +6. Apenas projetos `CONCLUIDO` são exibidos; +7. Email nunca aparece no resumo público (`/portfolios`); +8. Certificados e projetos não aparecem na listagem resumida; +9. Corroborações exibidas apenas com `showFeedback = true` **e** com N mínimo + atingido; +10. Feedback escrito exibido apenas com `publicationAllowed = true` **e** + `publishedByReceiver = true`; +11. As respostas 404 para usuário inexistente e portfólio privado são idênticas. +Todas aplicadas no backend, sem depender do frontend. + +--- + ## 4. Logging e Auditoria - -Logging estruturado implementado em **todas** as rotas de API em `src/app/api`. -A padronização foi concluída em 2026-06-14 (detalhes em -`docs/03 - tecnico/arquitetura/auditoria-logging-backend.md`). - -### Formato dos logs - -Todos os logs utilizam o logger estruturado em `src/lib/logger.ts`: - -```ts -logger.info(message, context, metadata) -logger.warn(message, context, metadata) -logger.error(message, context, metadata) -``` - -Assinatura real: - + +Logging estruturado implementado em todas as rotas de API. Padronização concluída +em 2026-06-14 (ver `auditoria-logging-backend.md`). + ```ts logger.info(message: string, context?: string, metadata?: unknown) +logger.warn(...) +logger.error(...) ``` - -Saída em JSON com campos: `timestamp`, `level`, `context`, `message`, metadados livres. - -### Convenção de uso - + +Saída JSON com `timestamp`, `level`, `context`, `message`, `metadata`. + | Nível | Quando usar | -|-------|-------------| -| `logger.error` | Erros inesperados em blocos `catch` | +|---|---| +| `logger.error` | Erros inesperados em `catch` | | `logger.warn` | Tentativas inválidas, bloqueios, recursos não encontrados com relevância operacional | | `logger.info` | Ações críticas de negócio concluídas com sucesso | - -### Regras - -- `context` no formato `'MÉTODO /api/rota'` (ex.: `'PATCH /api/portfolio/me'`). -- `console.log` / `console.error` não devem ser utilizados em código de runtime. -- Erros inesperados sempre incluem `error.message` nos metadados. -- Dados sensíveis (senha, token) nunca devem aparecer nos logs. - ------------------------------------------------------------------------- - + +Regras: + +- `context` no formato `'MÉTODO /api/rota'`; +- `console.*` proibido em runtime; +- Erros inesperados incluem `error.message` nos metadados; +- **Nunca** registrar senha, token, e-mail completo, conteúdo de feedback ou + qualquer dado pessoal. +**Ações de feedback que exigem log:** criação, ocultação por ADMIN (com motivo), +consulta de autoria mediante denúncia. + +--- + ## 5. Padrões de Acesso a Dados - + ### Server Component sem HTTP round-trip - -A rota pública `/portfolio/{username}` chama `getPublicPortfolio(username)` diretamente (serviço Prisma), sem fetch interno. Isso elimina: - -- Dependência de URL local (`localhost`) em produção. -- Cache implícito (`{ next: { revalidate: 60 } }`) que mascarava mudanças de visibilidade. -- Latência de serialização/desserialização HTTP desnecessária. - + +`/portfolio/{username}` chama `getPublicPortfolio(username)` diretamente, +eliminando dependência de URL local, cache implícito que mascarava mudanças de +visibilidade, e latência de serialização. + ### PATCH via Prisma `update` - -O endpoint `PATCH /api/portfolio/me` utiliza `prisma.user.update()` (não `findUnique`). Apenas campos presentes no payload são incluídos em `updateData` — campos ausentes não sobrescrevem valores existentes. - + +`PATCH /api/portfolio/me` usa `prisma.user.update()`. Apenas campos presentes no +payload entram em `updateData` — campos ausentes não sobrescrevem valores +existentes. + ### Delete-then-recreate para coleções - -Skills e certificados são gerenciados pelo padrão delete-then-recreate: - -```ts -await prisma.userSkill.deleteMany({ where: { userId } }); -await prisma.userSkill.createMany({ data: [...] }); -``` - -Isso evita lógica de diff e garante consistência da coleção após cada atualização. - ------------------------------------------------------------------------- - + +Skills e certificados usam delete-then-recreate, evitando lógica de diff e +garantindo consistência da coleção. + +--- + ## 6. Princípios Arquiteturais - -- Integridade referencial garantida via Prisma. -- Separação clara entre dados públicos e privados. -- Minimização de exposição de dados sensíveis. -- Não exposição de identificadores internos. -- Rastreamento histórico e auditabilidade via logger estruturado. -- Aplicação consistente de regras de negócio no backend. -- Sem dados sensíveis em queries públicas (`password`, `token` nunca selecionados). + +- Integridade referencial via Prisma; +- Separação clara entre dados públicos e privados; +- Minimização de exposição de dados sensíveis; +- Não exposição de identificadores internos; +- Rastreabilidade via logger estruturado; +- Regras de negócio aplicadas no backend. +> 🔴 **Dívida que contradiz os princípios acima (SEC-03):** nenhuma rota usa +> `select`/`omit` do Prisma, e objetos `User` são retornados íntegros — com o hash +> da senha. Isso viola "sem dados sensíveis em queries públicas". É falha ativa, +> não dívida de estilo. Em código novo, nunca retornar `User` cru. + +--- + +## 7. Histórico + +| Alteração | +|---| +| Atualizado após Portfólio Público por Username + Segurança e Logging (issue #527) | +| **Revogada** a afirmação de que a reputação é média simples dos ratings | +| Documentado o modelo alvo de corroborações e o destino dos campos legados | +| Registrada a regra de anonimização assimétrica na exclusão de conta | +| Registrada a dívida SEC-03 como contradição ativa com os princípios | \ No newline at end of file