You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-**Structured Logger**: `src/lib/logger.ts` — thin wrapper around `console.*` with Sentry-aware error forwarding; eliminates raw `console.*` calls across the codebase.
13
+
-**`data-testid="dashboard-welcome"`**: stable E2E anchor on the student dashboard `h1` (`dashboard-client.tsx`).
14
+
15
+
### Changed
16
+
17
+
-**Playwright env isolation**: port 3333 dedicated to E2E (`playwright.config.ts`); `reuseExistingServer: false` prevents reuse of a dev server carrying `.env.local` production credentials; explicit `env` block forwards Supabase vars to the webServer child process.
18
+
-**Seed determinism**: `purgeAuthUsers()` in `prisma/seed-e2e.ts` deletes `auth.users` by email before re-seeding with fixed UUIDs, eliminating UUID collision failures on re-run.
19
+
-**`sentry.client.config.ts` → `instrumentation-client.ts`**: migrated Sentry client init to Next.js 15 / v10 standard location; old file removed.
20
+
-**Observability**: replaced all `console.error` / `console.log` calls in client components and server actions with `Logger.*`; added `Sentry.captureException` in `alunos`, `financeiro`, `treinos` server actions.
21
+
-**Defensive XP serialization**: `/aluno/dashboard` page now null-guards `aluno.exp` and `aluno.nivel` and protects against division-by-zero in progress calculation.
22
+
23
+
### Fixed
24
+
25
+
-**ALUNO E2E login flake**: `loginAs()` helper adds a hard `page.goto(expectedPath)` after `waitForURL` to force a GET request where the browser includes the session cookie. Next.js App Router inline-renders the redirect target during the server action POST, where `Set-Cookie` is not yet in the `Cookie` request header, causing `getUser()` to fail and redirect to `/aluno/login`.
26
+
-**`isRedirectError` swallowed**: wrapped `redirect()` in `src/app/actions/auth.ts` with `try/catch` that re-throws via `isRedirectError` (from `next/dist/client/components/redirect-error`) so Next.js can inline-render the redirect target.
27
+
-**Strict-mode violation in heading assertion**: `getByRole('heading')` matched 2 elements on the admin dashboard; changed to `.first()` (and later to `data-testid` in student portal spec) to avoid Playwright strict-mode errors.
The following items are recognized as "Managed Debt" — intentional compromises for compatibility or performance:
97
99
98
100
1.**Sentry Boundary Casts**: Use of `any` in `beforeSend` (suppressed with `eslint-disable`) is required due to Sentry SDK interface rigidness.
99
-
2.**Server console.log**: 31 warnings in Server Actions are preserved to ensure minimal observability in the terminal during development.
101
+
2.**Logger internals**: `Logger` uses `console.*` internally — these are the only remaining `no-console` warnings and are acceptable as the structured logging layer.
100
102
3.**Prisma Type Overrides**: We use `@pg/types` pinning to resolve Prisma 7/Next 15 conflicts until `@prisma/adapter-pg` upstream fixes land.
101
103
102
104
## Known Issues
103
105
104
-
- 31 `no-console` warnings in server actions — accepted for server-side debug logging.
105
106
- GitHub Secrets for CI (Playwright) require one-time manual setup.
106
107
- Transitive dependency vulnerabilities in `@prisma/dev` (not reachable in production).
108
+
-`isRedirectError` must be imported from `next/dist/client/components/redirect-error` (not `next/navigation`) — no public API yet in Next.js 15.
O flow só é necessário quando o usuário clica "Finalizar Treino" — nunca no render inicial.
251
251
- **Lição:** Imports de módulos pesados com dependências de runtime (OpenTelemetry, telemetria, etc.) devem ser dinâmicos quando usados apenas em handlers de evento. Import estático ≠ "só executa quando chamado" — o módulo é resolvido e bundled na inicialização.
252
252
253
-
- **Efetividade:** Pendente — CI em andamento (run `24266743760`)
253
+
- **Efetividade:** ✅ Resolvido — import dinâmico eliminou o erro de bundle; student-portal suite passou em CI
254
+
255
+
---
256
+
257
+
## ERR-019 — E2E Auth: `redirect()` em server action nunca executa — swallowed por `try/catch`
258
+
259
+
- **Data:** 2026-04-17
260
+
- **Contexto:** Branch `fix/e2e-auth-stabilization` — `src/app/actions/auth.ts` — login de todos os roles
261
+
- **Sintoma:** Login retornava sem erro, mas o browser ficava na página `/login` sem navegar. `waitForURL('**/dashboard**')` timeout em 15s.
262
+
- **Causa raiz:** Next.js App Router implementa `redirect()` lançando internamente uma exceção especial (`NEXT_REDIRECT`). Se o `redirect()` é chamado dentro de um bloco `try/catch` sem re-throw, a exceção é absorvida — o redirect nunca acontece e a server action simplesmente retorna `undefined`.
263
+
- **Fix:** Adicionar guard `isRedirectError` antes de qualquer catch genérico:
264
+
265
+
```ts
266
+
import { isRedirectError } from 'next/dist/client/components/redirect-error';
267
+
// ⚠️ NÃO importar de 'next/navigation' — não exporta isRedirectError (TS2305)
268
+
269
+
try {
270
+
redirect('/dashboard');
271
+
} catch (err: unknown) {
272
+
if (isRedirectError(err)) throw err; // ← re-throw obrigatório
273
+
return { error: 'Erro inesperado' };
274
+
}
275
+
```
276
+
277
+
- **Arquivo afetado:** `src/app/actions/auth.ts`
278
+
- **Lição:** `redirect()` do Next.js é implementado via throw. Nunca envolver em `try/catch` sem o guard `isRedirectError`. O path de import correto é `next/dist/client/components/redirect-error` — `next/navigation` não exporta essa função (erro TypeScript TS2305 se tentar).
279
+
- **Efetividade:** ✅ Resolvido — todos os roles redirecionaram corretamente após o fix
280
+
281
+
---
282
+
283
+
## ERR-020 — E2E Auth: ALUNO sempre aterrissa em `/aluno/login` após login bem-sucedido
284
+
285
+
- **Data:** 2026-04-17
286
+
- **Contexto:** Branch `fix/e2e-auth-stabilization` — `tests/e2e/specs/auth.spec.ts` — teste ALUNO
287
+
- **Sintoma:** Login do ALUNO: `waitForURL` passava (URL mudava para `/aluno/dashboard`), mas a página renderizava `/aluno/login`. `getByRole('heading')` — element not found.
288
+
- **Causa raiz:** Next.js App Router inline-renderiza o target do redirect durante a mesma resposta POST da server action. Nesse momento, `cookies()` no server component lê os **request headers** — mas o cookie de sessão (`sb-*-auth-token`) setado por `signInWithPassword()` só existe no **response** `Set-Cookie`. O browser ainda não armazenou o cookie, então `getUser()` falha e a página redireciona para `/aluno/login`.
289
+
- Ponto crítico: `/dashboard`(admin) não chama `getUser()` no server component e não foi afetado. `/aluno/dashboard` chama e foi afetado.
290
+
- **Fix:** No helper `loginAs()`, forçar uma navegação GET após o `waitForURL`:
- **Lição:** Em Next.js App Router, o inline RSC render do redirect target não recebe o cookie de sessão que acabou de ser setado. Qualquer server component que chame `getUser()` ou `cookies()` e seja redirect target de uma server action está sujeito a esse timing. Em produção funciona (browser faz GET separado); em E2E é necessário forçar o GET explicitamente.
297
+
- **Efetividade:** ✅ Resolvido — ALUNO aterrou em `/aluno/dashboard` em todas as execuções subsequentes
298
+
299
+
---
300
+
301
+
## ERR-021 — E2E Auth: Todos os logins falhando com `TimeoutError: page.waitForURL` — servidor usando credenciais de produção
302
+
303
+
- **Data:** 2026-04-17
304
+
- **Contexto:** Branch `fix/e2e-auth-stabilization` — primeira execução após configurar o `.env.test`
305
+
- **Sintoma:** `TimeoutError: page.waitForURL: Timeout 15000ms exceeded` em todos os 3 testes de login. Apenas o teste de credenciais inválidas passava.
306
+
- **Causa raiz:** `playwright.config.ts` tinha `reuseExistingServer: true` (padrão) e a porta padrão (3001). Um servidor dev já estava rodando na porta 3001 carregado com `.env.local` (credenciais Supabase de produção). O Playwright reusou esse servidor — os usuários de teste não existem no projeto Supabase de produção, então todos os logins falhavam silenciosamente no `signInWithPassword()`.
307
+
- **Diagnóstico confirmado:** Trocar temporariamente para `reuseExistingServer: false` e port 3333 mostrou que o servidor novo (com `.env.test`) funcionava.
308
+
- **Fix:** Em `playwright.config.ts`:
309
+
```ts
310
+
webServer: {
311
+
command: 'npm run dev -- --port 3333', // porta dedicada E2E
// ... forward explícito de todas as vars do .env.test
317
+
},
318
+
}
319
+
```
320
+
- **Arquivo afetado:** `playwright.config.ts`
321
+
- **Lição:** `reuseExistingServer: true` é conveniente para velocidade mas perigoso quando o projeto tem múltiplos ambientes (`.env.local` + `.env.test`). O servidor reutilizado pode ter sido iniciado com qualquer conjunto de variáveis de ambiente. Em projetos com staging/test isolation, sempre usar `reuseExistingServer: false` + porta dedicada para E2E.
322
+
- **Efetividade:** ✅ Resolvido — porta 3333 dedicada, servidor sempre iniciado com `.env.test`
0 commit comments