Sequência da faxina entre Fase 1 e Fase 2 — manutenção consciente das pendências da Carta do Claude. Sete pendências fechadas em sessões de 25 e 28 de abril (uma oitava ficou em aberto, esperando o servidor próprio chegar). Sete episódios, cada um com áudio + resumo + material completo.
O que é a "faxina" — manutenção consciente entre Fase 1 e Fase 2
A Fase 1 do Nexus terminou em 23/04 com 4 dos 5 passos prontos. Em 25/04 veio a Carta do Claude com 11 observações, e cada item acionável virou pendência numerada. Em 28/04 essas pendências foram fechadas em sessão dedicada.
Esse trabalho — limpar pendências antes de começar a Fase 2 — é o que está sendo chamado de faxina. Não é desvio, é manutenção consciente.
Placar final: 7 fechadas, 1 aberta (a #7, plano B de deploy, espera o servidor próprio chegar).
Por que "Nexus" — origem em latim e na série Loki, sobrepostas
O nome "Nexus" tinha referência clara pro Flávio mas não estava registrada. Era a única decisão importante do projeto sem porquê escrito (observação 11 da Carta).
Duas referências sobrepostas: nexus do latim (nexo, ligação, vínculo — descreve o que o projeto FAZ: consolidar informação espalhada) + evento Nexus da série Loki (ramificação consciente que altera a linha do tempo — descreve o que o projeto É pro Flávio: salto Jasap → Spring de mercado).
Função + intenção. Pendência #4 fechada — agora registrado em nexus.md §1 (Visão) e §12 (Histórico).
Por que npm run dev não basta — Vite tem dois modos diferentes
Na Fase 1 o frontend só rodou com npm run dev — nunca com npm run build. Pendência #2 cobre essa validação.
Vite tem 2 modos diferentes: em dev, cada arquivo é servido individualmente (HMR rápido, alta tolerância a erros). Em build, Rollup empacota tudo, faz tree shaking, valida imports estritamente. Passar em dev NÃO garante passar em build.
Resultado da pendência: build limpo (155+170 módulos), npm run preview servindo HTTP 200 com SSR. Único achado: warning conhecido do adapter-auto (vai sumir quando trocar pra adapter-node no deploy — pendência #7).
Migration V4, dois passos coordenados (banco + Java), e por que soft delete ficou pra depois
A entidade Note tinha 4 campos úteis no fim da Fase 1 (id, title, content, user, timestamps). Pendência #6 perguntou: o que falta antes da Fase 2?
5 candidatos avaliados: archived ✅, pinned ✅, deleted_at ❌ (adiado pra depois dos testes — refatoração arriscada sem rede), position ❌ (Fase 3, drag-drop), color ❌ (sem caso de uso).
Migration V4 com BOOLEAN NOT NULL DEFAULT FALSE nos dois campos. Java atualizado com boolean primitivo + getters isArchived()/isPinned(). DTO ganhou os 2 campos novos. Sem mudança em controller/service/frontend (defaults garantem compatibilidade).
O maior trabalho da faxina — 33 testes, 4 tipos do Spring Boot, Postgres real
Fim da Fase 1: zero teste automatizado (só o smoke do Initializr). Pendência #1 corrigiu — a maior da faxina, 33 testes em 1 sessão dedicada.
4 decisões antes da primeira linha: cobertura essencial (não agressiva), Postgres local real (não H2 nem Testcontainers — fiel a tipos como tsvector), JWT real onde possível, atacar agora.
4 tipos de teste do Spring Boot: @DataJpaTest (só JPA), @WebMvcTest (só Web), @SpringBootTest (contexto inteiro), slice tests específicos. Distribuição: 6+4+8+10+5 = 33 novos. Descoberta no caminho: Spring retorna 403 (não 401) sem token — virou pendência #8.
Resultado: 35 testes verdes em ~11s, cobrindo ownership, fluxos principais, exceptions. Habilitam mudança segura — refatoração de saveAndFlush e config do 401 viraram triviais com a rede de proteção.
Bandeira amarela — workaround do JPA pra fazer @UpdateTimestamp refletir no DTO
O NoteService.update tinha um saveAndFlush em vez de save. Funcionava — forçava o flush imediato pra @UpdateTimestamp popular updatedAt antes do DTO ser construído. Mas era bandeira amarela da Carta (pendência #5): sintoma de DTO mal desenhado.
3 opções avaliadas: A — manter (decisão consciente), B — DTO com OffsetDateTime.now() explícito, C — PUT retornar 204 (mais invasivo). Escolhida B.
Mudança: NoteResponse ganhou overload from(Note, OffsetDateTime), NoteService.update chama save + NoteResponse.from(note, OffsetDateTime.now()). Diverge do banco em microssegundos — irrelevante. Teste novo update_responseUpdatedAtIsAfterCreatedAt protege contra regressão.
Habilitado pelos testes — refatoração só foi tranquila porque a pendência #1 já tinha rodado.
A última pendência da faxina — descoberta acidental durante os testes
Pendência #8 não veio da Carta — apareceu quando o teste de acesso anônimo falhou: "Status expected 401, but was 403". Spring Security default retorna 403 pra request sem token. Semanticamente errado.
401 ≠ 403: 401 = "precisa autenticar" (sem token, token inválido). 403 = "está autenticado mas não tem permissão". Sem token é caso de 401.
Solução: Json401EntryPoint em io.nexus.common — implementa AuthenticationEntryPoint, retorna 401 com body {"error":"unauthorized"}. Registrado no SecurityFilterChain via .exceptionHandling(eh -> eh.authenticationEntryPoint(entryPoint)).
Frontend não precisou mudar — lib/api.ts já tratava 401/403 igual. Pura limpeza de semântica HTTP. Faxina fechada.