Skip to content

Commit c85342b

Browse files
feat(aluno): dashboard UI polish + seed auth users + PR review fixes (#193)
Dashboard: remove fake stats, fix spacing, fix exercicios rendering, workout count label. Seed: create Supabase Auth users, fix HistoricoTreino cascade, password security. Docs: clean PRD. Housekeeping: remove tmp-output.json.
1 parent abbeb62 commit c85342b

8 files changed

Lines changed: 612 additions & 62 deletions

File tree

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,6 @@ NEXT_PUBLIC_APP_URL=http://localhost:3000
9191

9292
# E2E: default password for test users (used by seed-e2e.ts and auth helper)
9393
# E2E_DEFAULT_PASSWORD=Test1234!
94+
95+
# Seed: default password for all seed users created in Supabase Auth
96+
# SEED_DEFAULT_PASSWORD=Test1234!

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,5 @@ graphify-out/
165165
qa/
166166
.sisyphus/evidence/
167167
.omo/
168+
.env*
169+
tmp-output.json
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
# PRD — Aprimoramento UI Aluno (PWeb_Project)
2+
3+
**Data**: 2026-07-07
4+
**Status**: Draft (aguarda aprovação)
5+
**Branch alvo**: `feat/008-aluno-ui-premium`
6+
**Dependências**: nenhuma
7+
**Owner**: design + frontend
8+
9+
---
10+
11+
## 1. Contexto
12+
13+
Auditoria exaustiva da superfície Aluno (PWeb_Project / Five Star Gym / Aegis Fitness OS) identificou 25 melhorias concretas, ordenadas por impacto e risco. Esta PRD é a fonte de verdade para a execução.
14+
15+
**Stack**: Next.js 15 App Router · Tailwind v4 (OKLCH) · Inter + Outfit · lucide-icons · dark-first OLED · TypeScript strict.
16+
17+
**Constraint cultural**: ponytail (lazy senior dev) — diff mínimo, stdlib/native first, sem abstração especulativa, sem nova dep sem justificativa.
18+
19+
---
20+
21+
## 2. Visão
22+
23+
> Aluno abre o app e em 3 segundos vê seu próximo treino + progresso real, sem ruído, sem dados falsos, com hierarquia clara que impressiona sem exagerar.
24+
25+
---
26+
27+
## 3. Princípios (premium = disciplina, não efeito)
28+
29+
1. **Sem dados falsos** — KPI inventado destrói confiança.
30+
2. **Hierarquia em 3 níveis** — Headline → ação primária → contexto. Sem 4º nível competindo.
31+
3. **Estado vazio é first-class** — aluno novo vê CTA claro, não tela morta.
32+
4. **A11y não é opcional** — heading semântico, autofocus correto, contrast AAA.
33+
5. **Spec ↔ código alinhados** — pill onde DESIGN.md diz pill.
34+
6. **Ponytail** — 1 arquivo, 1 tarefa, diff mínimo.
35+
36+
---
37+
38+
## 4. Fases
39+
40+
### Fase 1 — Aluno Home (P1, bloqueia tudo)
41+
42+
**Por quê primeiro**: priorizado pelo usuário. Tela que ele abre primeiro.
43+
44+
| ID | Arquivo | Mudança | Verify | Risk |
45+
| --- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------ | ------ |
46+
| T01 | `src/app/aluno/dashboard/dashboard-client.tsx:224` | Remover KPI hardcoded (Meta Semanal 80%, Power Index 752). Substituir por `treinosConcluidos/semana` real; esconder card se 0. | `npm run typecheck` + screenshot 375px → "Sem treinos" | low |
47+
| T02 | `src/app/aluno/dashboard/dashboard-client.tsx:266` | `flex justify-around gap-2``flex justify-center gap-2` nos 3 achievement badges. | Visual: badges com mesmo gutter | low |
48+
| T03 | `src/app/aluno/dashboard/dashboard-client.tsx` (topo) | Empty state quando `treinos.length === 0`: card glass + "Bem-vindo, [nome]" + CTA "Falar com instrutor". | Login aluno novo → empty state | low |
49+
| T04 | `src/app/aluno/dashboard/dashboard-client.tsx` | Hierarquia: próximo treino é o primeiro card visível (não KPIs). Move KPIs para abaixo. | Mobile viewport → próximo treino acima da dobra | medium |
50+
| T05 | `src/app/aluno/dashboard/dashboard-client.tsx` (timer) | `aria-live="polite"` no timer + `role="timer"` + label humano. Sem pulse em `prefers-reduced-motion`. | axe DevTools 0 violations em timer | medium |
51+
52+
### Fase 2 — Card-treino + meus-treinos (P1/P2)
53+
54+
**Por quê**: tela mais usada depois do home.
55+
56+
| ID | Arquivo | Mudança | Verify | Risk |
57+
| --- | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ---------------------------------- | ------ |
58+
| T06 | `src/components/dashboard/aluno/card-treino.tsx:65` | `<CardTitle>` (renderiza `<div>`) → `<h3>` semântico com mesma classe. | axe: heading outline inclui título | low |
59+
| T07 | `src/components/dashboard/aluno/card-treino.tsx` | Press feedback: `active:scale-[0.98] transition-transform` + `focus-visible:ring-2 ring-primary`. | Tab no card → ring visível | low |
60+
| T08 | `src/app/aluno/meus-treinos/meus-treinos-client.tsx:183` | Renderizar 2-3 nomes de exercícios truncados abaixo do count. | Card mostra "Supino, Agachamento…" | low |
61+
| T09 | `src/app/aluno/meus-treinos/meus-treinos-client.tsx` | Empty state quando 0 treinos: ícone lucide (Dumbbell) + "Você ainda não tem treinos" + CTA. | Login aluno novo → empty state | low |
62+
| T10 | `src/app/aluno/meus-treinos/meus-treinos-client.tsx` | Loading skeleton (Tailwind `animate-pulse`) no lugar de spinner genérico. Respeita reduced-motion. | Refresh → vê skeleton 200ms | medium |
63+
64+
### Fase 3 — Login first impression (P1)
65+
66+
**Por quê**: tela que define "esse app é bom?" em 5s.
67+
68+
| ID | Arquivo | Mudança | Verify | Risk |
69+
| --- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ---- |
70+
| T11 | `src/app/aluno/login/page.tsx:134` | Email: `autoComplete="email" type="email" inputMode="email" autoCapitalize="none"`. Password: `autoComplete="current-password"`. | 1Password preenche; mobile mostra teclado @ | low |
71+
| T12 | `src/app/aluno/login/page.tsx` | Erro inline com `role="alert"` + `aria-describedby` no input. Sem toast que some. | Erro de credencial → foco no input, erro anunciado | low |
72+
| T13 | `src/app/aluno/login/page.tsx` | Motion de entrada: fade+slide sutil no card (200ms ease-out). `prefers-reduced-motion` → fade only. | Reduced-motion ON → sem slide | low |
73+
74+
### Fase 4 — A11y foundation (P1)
75+
76+
**Por quê**: conserta bugs que afetam tudo.
77+
78+
| ID | Arquivo | Mudança | Verify | Risk |
79+
| --- | -------------------------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------- | ------ |
80+
| T14 | `src/components/ui/circular-progress.tsx:61` | Add `viewBox="0 0 100 100"` + `aria-hidden="true"`. Valor numérico em texto separado. | axe 0 violations | low |
81+
| T15 | `src/app/aluno/aluno-header.tsx:89` | Habilitar item "Perfil" do dropdown + criar rota `/aluno/perfil` (pode ser stub "Em breve"). | Dropdown → "Perfil" navega | medium |
82+
| T16 | `src/app/aluno/aluno-header.tsx` | Avatar do menu: `aria-label="Menu do aluno"` (sem nome visível). | NVDA anuncia "Menu do aluno" | low |
83+
84+
### Fase 5 — Design drift (P2)
85+
86+
**Por quê**: alinha spec ↔ código.
87+
88+
| ID | Arquivo | Mudança | Verify | Risk |
89+
| --- | -------------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------- | ------ |
90+
| T17 | `src/components/ui/button.tsx:8` | `rounded-md``rounded-full` no default variant (DESIGN.md: "Pill-shaped for primary actions"). | `npm run build` OK; botões viram pill | low |
91+
| T18 | `src/app/globals.css` | Adicionar `.text-gradient-cyan` (referenciada em dashboard-client:65 + landing page). | gradient visível | low |
92+
| T19 | `src/app/globals.css` | Validar `--color-muted-foreground` ≥ 4.5:1 (AAA large). Ajustar lightness se <. | Lighthouse a11y ≥ 95 | medium |
93+
| T20 | `src/components/bottom-nav.tsx` | Active state: além do `border-t-2`, adicionar `text-primary` (só border hoje). | Visual: tab ativo texto cyan + border | low |
94+
95+
### Fase 6 — Brand polish (P3)
96+
97+
**Por quê**: consistência de identidade.
98+
99+
| ID | Arquivo | Mudança | Verify | Risk |
100+
| --- | -------------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------- | ---- |
101+
| T21 | `src/app/page.tsx` | "Academia Five Star" → "Five Star Gym" (consistente com brand). Tagline idem. | Texto da landing bate com DESIGN.md | low |
102+
| T22 | `src/app/layout.tsx` | Validar `font-display: swap` (FOIT prevention) em Inter+Outfit. | Lighthouse Best Practices 100 | low |
103+
| T23 | `DESIGN.md` | Documentar decisão: **Inter (body) + Outfit (headline)** — não SF Pro. Atualizar spec para refletir código. | Markdown diff | low |
104+
105+
### Fase 7 — Motion + reduced-motion pass (P2)
106+
107+
**Por quê**: polish final + acessibilidade.
108+
109+
| ID | Arquivo | Mudança | Verify | Risk |
110+
| --- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ---- |
111+
| T24 | `src/app/globals.css` | `@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }` | DevTools reduced-motion ON → zero animação | low |
112+
| T25 | `src/components/ui/button.tsx` + cards | `hover:scale-[1.02]``hover:brightness-110` (mais sutil, sem motion sickness). | DevTools mobile test | low |
113+
114+
---
115+
116+
## 5. KPIs (medir sucesso)
117+
118+
| KPI | Meta | Como medir |
119+
| ------------------------------------------ | ----------- | ----------------------------------------------- |
120+
| Lighthouse a11y score | ≥ 95 | Chrome DevTools / Lighthouse CI |
121+
| axe DevTools violations (Aluno surfaces) | 0 | axe-core CLI no CI |
122+
| Empty state coverage (treinos, conquistas) | 100% | Visual review: cada lista tem UI para 0 |
123+
| KPI hardcoded em produção | 0 | `grep -E "['\"\`][0-9]+%['\"\`]" src/app/aluno` |
124+
| Pill buttons em CTAs primárias | 100% | Visual review |
125+
| `text-gradient-cyan` aplicado | sim | grep + visual |
126+
| Mobile first paint | não regride | Lighthouse perf |
127+
128+
---
129+
130+
## 6. Ordem de execução
131+
132+
1. **T01-T05** (Fase 1) — user abre app, vê algo bom.
133+
2. **T11-T13** (Fase 3) — user consegue logar com qualidade.
134+
3. **T14-T16** (Fase 4) — a11y base sólida.
135+
4. **T06-T10** (Fase 2) — navegação interna polida.
136+
5. **T17-T20** (Fase 5) — spec/code alinhados.
137+
6. **T21-T25** (Fases 6+7) — polish final.
138+
139+
**Total: 25 tasks · 12 arquivos · 0 deps novos.**
140+
141+
---
142+
143+
## 7. Out of scope (skipped, adicionar quando X)
144+
145+
- Ilustrações SVG custom para empty states — lucide cobre. Designer quando virar feature de marca.
146+
- i18n de strings hardcoded — quando houver user en/es.
147+
- Animações de entrada por rota (Framer Motion) — diff só se user pedir.
148+
- Skeleton library dedicada — `animate-pulse` nativo cobre. Dep quando shapes ficarem complexos.
149+
150+
---
151+
152+
## 8. Workflow sugerido (execução)
153+
154+
### Abordagem: feature branch + PRs por fase
155+
156+
#### 8.1. Setup (1 comando)
157+
158+
```bash
159+
git checkout -b feat/008-aluno-ui-premium
160+
```
161+
162+
#### 8.2. Execução fase-a-fase (recomendado)
163+
164+
Para cada fase:
165+
166+
```bash
167+
# 1. Criar sub-branch
168+
git checkout -b feat/008-fase-N-<slug>
169+
170+
# 2. Implementar tasks (uma por commit, conventional commits)
171+
git commit -m "feat(aluno/dashboard): T01 remove fake KPIs"
172+
173+
# 3. Gates (todos devem passar)
174+
npm run lint && npm run typecheck && npm test
175+
176+
# 4. PR para main (ou merge em feat/008-aluno-ui-premium)
177+
gh pr create --base main --title "feat(aluno): fase N — <título>"
178+
179+
# 5. Aguardar CI + review + merge
180+
181+
# 6. Voltar para feat/008-aluno-ui-premium e rebase
182+
git checkout feat/008-aluno-ui-premium
183+
git rebase main
184+
```
185+
186+
#### 8.3. Validação final
187+
188+
Após merge de todas as fases:
189+
190+
```bash
191+
# 1. E2E suite (deve continuar passando)
192+
npm run e2e
193+
194+
# 2. Lighthouse mobile
195+
npx lighthouse https://staging.example.com/aluno/dashboard --view
196+
197+
# 3. axe-core scan
198+
npx axe https://staging.example.com/aluno/dashboard
199+
200+
# 4. Tag da iteração
201+
git tag v0.9.1-premium-ui
202+
```
203+
204+
---
205+
206+
## 9. Riscos e mitigação
207+
208+
| Risco | Probabilidade | Impacto | Mitigação |
209+
| ---------------------------------------- | ------------- | ------- | ---------------------------------------------------------- |
210+
| Regressão em E2E tests | média | médio | Rodar `npm run e2e` após cada fase |
211+
| Quebra de design system (tokens globais) | baixa | alto | Fases 5+6 em branch isolado, validar visual antes de merge |
212+
| Performance (motion excessivo) | baixa | médio | T24 força reduced-motion global como rede de segurança |
213+
| Inconsistência entre fases | média | baixo | PRs pequenos por fase facilitam review |
214+
215+
---
216+
217+
## 10. Acceptance criteria
218+
219+
Esta PRD está DONE quando:
220+
221+
- [ ] Todas as 25 tasks mergeadas em main
222+
- [ ] Lighthouse a11y ≥ 95 nas 4 rotas Aluno
223+
- [ ] axe DevTools 0 violations
224+
- [ ] Nenhum KPI hardcoded permanece em `src/app/aluno/`
225+
- [ ] E2E suite 100% verde
226+
- [ ] Screenshots mobile (375px) revisados: home, login, treinos, empty states
227+
- [ ] `docs/CURRENT-STATE.md` atualizado refletindo a iteração
228+
229+
---
230+
231+
## 11. Referências
232+
233+
- Audit workflow: `wf_eaffd9ce-9c6` (synthesis falhou; plano derivado inline)
234+
- DESIGN.md: `docs/...` (spec a ser atualizado em T23)
235+
- Memory: `project_mobile_first_prds.md`, `project_prd3_plan_pending.md`

0 commit comments

Comments
 (0)