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