From 96995ae741304992562e4ea539f2d4be08e03810 Mon Sep 17 00:00:00 2001 From: Karina Date: Sun, 23 Aug 2026 16:17:56 -0300 Subject: [PATCH] docs(feedback): conclui spike de schema e registra decisao de notificar --- .../feedback/feedback-reputacao.md | 14 +- docs/02 - produto/projetos/gestao-projetos.md | 48 ++++++ .../spikes/spike-schema-atributos-feedback.md | 143 ++++++++++++++++++ 3 files changed, 200 insertions(+), 5 deletions(-) create mode 100644 docs/03 - tecnico/spikes/spike-schema-atributos-feedback.md diff --git a/docs/02 - produto/feedback/feedback-reputacao.md b/docs/02 - produto/feedback/feedback-reputacao.md index 46b46b9f..7bb1c939 100644 --- a/docs/02 - produto/feedback/feedback-reputacao.md +++ b/docs/02 - produto/feedback/feedback-reputacao.md @@ -388,9 +388,13 @@ enum FeedbackAttrEnum { } ``` -> ⚠️ 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. +> ✅ **Decidido em 19/08/2026** pela +> [spike de schema](../../03%20-%20tecnico/spikes/spike-schema-atributos-feedback.md): +> **tabela relacional**, como proposto acima. O critério não foi desempenho — em +> memória, agregar ~120 linhas por perfil é irrelevante — e sim **integridade**: +> só a tabela impede, no banco, que o mesmo eixo seja contado duas vezes na mesma +> avaliação. Com array de enum o Postgres aceita repetição, e a contagem pública +> — que é o valor da corroboração — fica à mercê de um bug de aplicação. ### 12.2 Agregação para o portfólio @@ -533,7 +537,7 @@ Documentos técnicos relacionados: **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 +2. ✅ ~~Spike de schema~~ — concluída em 19/08/2026: tabela relacional 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 @@ -541,7 +545,6 @@ Documentos técnicos relacionados: 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; @@ -558,6 +561,7 @@ Documentos técnicos relacionados: | 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 | +| 19/08/2026 | Schema dos atributos: **tabela relacional**, por integridade — ver [spike](../../03%20-%20tecnico/spikes/spike-schema-atributos-feedback.md) | | 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) | diff --git a/docs/02 - produto/projetos/gestao-projetos.md b/docs/02 - produto/projetos/gestao-projetos.md index a12ae502..f6ec4849 100644 --- a/docs/02 - produto/projetos/gestao-projetos.md +++ b/docs/02 - produto/projetos/gestao-projetos.md @@ -146,6 +146,54 @@ participantes. ------------------------------------------------------------------------ +### 6.4 Revisão de 19/08/2026 — notificar em vez de bloquear + +**Decisão:** a restrição da seção 6.3 passa a ser **notificação**, não bloqueio. +O owner pode editar o projeto após a formação da equipe; as pessoas envolvidas +são avisadas da alteração. + +**Por que mudou.** A regra foi implementada e desativada em 16/08/2026, por dois +defeitos que só apareceram no uso: + +1. **Escopo largo demais.** A verificação tratava `name`, `deadline` e + `totalValue` como estrutura, travando edições sem relação com a composição da + equipe — inclusive corrigir um erro de digitação na descrição. + +2. **Falso positivo na comparação de datas.** O formulário carregava o prazo sem + a hora (`deadline.split('T')[0]`) enquanto o banco guardava o timestamp + completo. Os dois nunca coincidiam, então **abrir a tela de edição e salvar + sem alterar nada já disparava o bloqueio.** Na prática a regra não protegia a + estrutura: travava a edição inteira, sem saída pela interface. + +**Por que notificar é melhor.** O bloqueio parte da premissa de que mudar é +errado. Notificar parte de que **mudar sem avisar** é que é. Num projeto onde as +pessoas estão aprendendo a trabalhar em equipe, a segunda premissa é mais fiel ao +que acontece no mercado: escopo muda, e a equipe é comunicada. + +O bloqueio também criava um beco sem saída — uma vez formada a equipe, nem o +owner nem um ADMIN conseguiam corrigir nada pela tela. + +**A regra da observação com data continua valendo.** Ela é o registro histórico +da mudança; a notificação é o aviso ativo. As duas se complementam. + +#### O que ainda precisa ser definido + +- **Quem é notificado** — todos que assumiram stack, ou apenas os afetados pela + alteração específica? +- **Por qual canal** — e-mail (o projeto já usa Resend), aviso no painel, ou os + dois? +- **O que a mensagem informa** — que houve alteração, ou quais campos mudaram? +- **Alguma alteração ainda exige confirmação prévia?** Trocar uma stack já + assumida afeta diretamente o trabalho de alguém — talvez mereça tratamento + diferente de corrigir a descrição. + +> ⚠️ **Estado atual do código:** a verificação existe em +> `src/app/api/team-project/[id]/route.ts`, desativada por uma constante, com o +> motivo documentado no próprio arquivo. Os três testes que a cobriam estão como +> `it.skip`, descrevendo o comportamento esperado caso a regra volte. + +------------------------------------------------------------------------ + ## 7. Impacto em Dados - Criação de registros em Project diff --git a/docs/03 - tecnico/spikes/spike-schema-atributos-feedback.md b/docs/03 - tecnico/spikes/spike-schema-atributos-feedback.md new file mode 100644 index 00000000..7e02b55f --- /dev/null +++ b/docs/03 - tecnico/spikes/spike-schema-atributos-feedback.md @@ -0,0 +1,143 @@ +# Spike — Estrutura dos atributos de Feedback + +**Classificação:** Documento Técnico / Spike +**Camada:** 3 — Documentos Técnicos +**Status do documento:** concluído +**Data:** 19/08/2026 +**Origem:** seção 12.1 de [`feedback-reputacao.md`](../../02%20-%20produto/feedback/feedback-reputacao.md) + +--- + +## 1. A pergunta + +O documento de produto propõe uma tabela relacional para os atributos, mas +registra a decisão como pendente: + +> 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, considerando o +> custo da query de agregação por perfil. + +--- + +## 2. As duas opções + +**A — Tabela relacional** + +```prisma +model Feedback { + attributes FeedbackAttribute[] +} + +model FeedbackAttribute { + feedbackId String + attribute FeedbackAttrEnum + feedback Feedback @relation(fields: [feedbackId], references: [id], onDelete: Cascade) + + @@unique([feedbackId, attribute]) + @@index([attribute]) +} +``` + +**B — Array de enum** + +```prisma +model Feedback { + attributes FeedbackAttrEnum[] +} +``` + +--- + +## 3. Resultado + +**As duas são válidas no Prisma 7.9.1** — `prisma validate` passa em ambas. A +decisão não é sobre viabilidade. + +### 3.1 O que o SQL gerado mostra + +Comparando `prisma migrate diff` das duas: + +| | Opção A | Opção B | +|---|---|---| +| Restrição de atributo repetido | `UNIQUE (feedbackId, attribute)` | **nenhuma** | +| Índice por atributo | `INDEX (attribute)` | **nenhum** | +| Exclusão em cascata | `ON DELETE CASCADE` | implícita na linha | +| Tabelas | 2 | 1 | + +A diferença decisiva está na primeira linha. Na opção B, o Postgres aceita +`{APOIA_A_EQUIPE, APOIA_A_EQUIPE, APOIA_A_EQUIPE}` sem reclamar — **o mesmo eixo +contado três vezes na mesma avaliação**. + +Isso não é detalhe de implementação. A regra da seção 5.2 — no máximo 3 eixos por +pessoa avaliada — existe para impedir que o sinal seja esvaziado por marcação de +cortesia. Com array, a integridade dessa regra depende inteiramente do código da +aplicação; um bug ou uma rota nova esquecendo a validação corrompe a agregação em +silêncio. Com a tabela, o banco recusa. + +### 3.2 Custo da agregação + +A consulta pública precisa, por eixo: contagem de avaliadores distintos e de +projetos distintos. + +**Nenhuma das duas opções é expressável no `groupBy` do Prisma**, porque ele não +suporta `COUNT(DISTINCT)` sobre coluna de tabela relacionada. Em ambas o caminho +é o mesmo: buscar os feedbacks do perfil e agregar em memória, ou usar SQL cru. + +**Estimativa de volume por perfil:** + +``` +10 projetos concluídos × 4 colegas = ~40 feedbacks recebidos +40 feedbacks × até 3 eixos = ~120 linhas de atributo +``` + +Nessa ordem de grandeza, agregar em memória é irrelevante em custo. O argumento +de desempenho — que motivava a spike — **não diferencia as opções**. + +Se o volume crescer a ponto de importar, SQL cru resolve nos dois casos. Na +opção B ele exige `unnest`, que é menos legível; na A é um `GROUP BY` comum. + +--- + +## 4. Decisão + +**Opção A — tabela relacional.** + +O critério que decide não é desempenho, e sim **integridade**: só ela impede, no +banco, que o mesmo eixo seja contado mais de uma vez na mesma avaliação. Como o +valor público da corroboração vem justamente da contagem, um dado duplicado +corrompe exatamente aquilo que a funcionalidade entrega. + +Fatores secundários que reforçam: + +- índice por atributo, útil para a métrica da seção 17 (distribuição por eixo); +- `onDelete: Cascade` explícito, relevante para a exclusão de conta (seção 13); +- consulta de agregação mais legível se um dia precisar de SQL cru; +- adicionar um eixo novo é alterar o enum nos dois casos — sem diferença. + +O custo é uma tabela a mais. É pouco pelo que se ganha. + +--- + +## 5. O que isto destrava + +A etapa 3 da ordem de execução (seção 20 do documento de produto): migration e +rotas. A estrutura de `FeedbackAttribute` proposta na seção 12.1 fica confirmada +como especificação técnica. + +**Continuam em aberto**, e não dependiam desta spike: + +- prazo do blind duplo (14 dias é proposta); +- N mínimo para exibição (3 é proposta); +- manutenção ou remoção do `rating` legado; +- existência de fluxo de denúncia pelo avaliado. + +--- + +## 6. Como este resultado foi obtido + +```bash +prisma validate --schema opcao-a.prisma # e opcao-b +prisma migrate diff --from-empty --to-schema opcao-a.prisma --script +``` + +Executado com Prisma CLI 7.9.1, mesma versão do projeto.