Nexus — Faxina Fase 1 7 episódios

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.

01 - Visão GeralVISÃO GERAL

O que é a "faxina" — manutenção consciente entre Fase 1 e Fase 2

0:00 / 0:00

Resumo

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).

contextomanutenção8 pendências
CÓDIGO COMPLETO
02 - A história do nomeNOME

Por que "Nexus" — origem em latim e na série Loki, sobrepostas

0:00 / 0:00

Resumo

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).

latimLokicarreira
CÓDIGO COMPLETO
03 - Validando o build do frontendBUILD

Por que npm run dev não basta — Vite tem dois modos diferentes

0:00 / 0:00

Resumo

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).

ViteSSRadapter-auto
CÓDIGO COMPLETO
04 - Evoluindo a Note: archived e pinnedJPA

Migration V4, dois passos coordenados (banco + Java), e por que soft delete ficou pra depois

0:00 / 0:00

Resumo

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).

Flyway V4@UpdateTimestampsoft delete
CÓDIGO COMPLETO
05 - Cobrindo a Fase 1 com testesTESTES

O maior trabalho da faxina — 33 testes, 4 tipos do Spring Boot, Postgres real

0:00 / 0:00

Resumo

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.

@DataJpaTest@WebMvcTest@SpringBootTestownership
CÓDIGO COMPLETO
06 - Refatorando o saveAndFlushREFACTOR

Bandeira amarela — workaround do JPA pra fazer @UpdateTimestamp refletir no DTO

0:00 / 0:00

Resumo

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.

@UpdateTimestampDTObandeira amarela
CÓDIGO COMPLETO
07 - 401 vs 403, semântica HTTPHTTP

A última pendência da faxina — descoberta acidental durante os testes

0:00 / 0:00

Resumo

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.

Spring SecurityAuthenticationEntryPointREST
CÓDIGO COMPLETO