Data: 2026-01-27
Contexto: Piano Trainer / Piano Pro — app de treino musical com falling notes, partitura (OSMD), MIDI, lições e analytics.
- Frontend (viewer): React + Vite + TypeScript. Home → Hub (capítulos) → Sessão de prática.
- Modos de prática: WAIT (nota a nota), FILM (Time Film com notas caindo), PLAIN (visual).
- Input: Teclado QWERTY mapeado para notas + MIDI físico (Web MIDI).
- Visualização: Partitura (OpenSheetMusicDisplay), falling notes, HUD (progresso, score, streak).
- Backend: FastAPI em Python — catálogo de lições, sessões, analytics, dashboard.
- Core: Engine de prática em Python (
core/), adaptadores MIDI, storage, sync com viewer.
| Camada | Stack | Papel |
|---|---|---|
| Viewer | React, Vite, TS | UI, falling notes, OSMD, input, event stream local |
| Backend | FastAPI, SQLite/Postgres, Alembic | API REST, lições, sessões, analytics |
| Core | Python | PracticeEngine, lições, gamificação, sync (viewer_sync) |
| Adapters | Python | MIDI (mido/rtmidi) |
- Dados:
assets/lessons.json(módulos/capítulos),data/(sessões, etc.), MusicXML para partitura. - Fluxo atual: Cliente pode rodar local (LocalTransportDriver, LessonEngine) ou integrar com backend via REST; migração em curso de WebSocket para Event Stream + validação offline (REST).
- Lições estruturadas (Clave de Sol, etc.) e catálogo bem definido.
- Dashboard de analytics (heatmap, sugestões, etc.) já existe.
- Tipos e contratos em evolução (
LessonContentPacket,EventV1, etc.). - Testes Python para engine, gamificação, timing, storage.
- Documentação de bugs e plano de correção (QA 2026-01-23) alinhada com arquitetura alvo.
| ID | Problema | Severidade |
|---|---|---|
| A1 | Wait Mode não avança ao tocar (keyboard/MIDI); HUD não aparece | P0 |
| A2 | Score/streak não atualizam em nenhum modo | P1 |
| B1 | Partitura termina antes do Falling Notes / progresso (dois clocks) | P0 |
| C1 | Troca de modo não reseta (step/score herdados) | P0 |
| C2 | Troca de lição herda progresso da lição anterior | P0 |
| C3 | Plain Mode sem feedback definido | P2 |
| D1 | Play não controla execução (parece preview MIDI) | P2 |
| D2 | Reload não faz nada | P2 |
| E1 | Falling Notes nascem “em cima” da tecla (sem lead time) | P0 |
| E2 | Sem count-in visual (2–3 compassos) antes de começar | P0 |
Causa raiz: Mistura de dois contratos (WS antigo vs cliente-autoritativo + Event Stream). Store/sessão não escopada por session_id/lesson_id; falta TimelineController único; OSMD e falling usam clocks diferentes.
viewer/index.tsx~2.265 linhas — monolito; difícil manter e testar (Fase 2 do ROADMAP).- Mapeamento teclado/nota espalhado (
keyboardNoteMap, etc.); sem tabela única + testes paramétricos. - Telemetria/observabilidade ainda incipiente (Fase 0 do ROADMAP).
- Polifonia não tratada de forma estruturada (Fase 3).
- Estabilidade e corretude do runtime — Eliminar P0/P1; sessão e timeline coerentes.
- Manutenibilidade — Quebrar
index.tsx, contratos claros, mapeamento único. - Polifonia e áudio — Engine de vozes, latência, underrun (Fase 3).
- Performance e operação — FPS, CPU, pipeline de release, SLOs (Fase 4).
Regra: Estabilidade > corretude de mapeamento > polifonia > performance > novas features. Congelar features até fechar P0/P1 e refatoração crítica.
- Definir e documentar Event Stream v1 e StateFrame v1 (já esboçados no plano de correção).
- Instrumentar crash, drift_ppm e latência nota→áudio onde fizer sentido.
- Validar schemas (config, lições) na inicialização e em CI.
- Painel mínimo (local ou backend) para eventos críticos.
Entregável: Taxonomia de métricas + eventos nomeados; baseline de estabilidade.
Ordem de ataque (com gates), conforme plano de correção:
- Reset canônico: trocar modo ou lição →
session_end+ novosession_start; novosession_id; HUD zerado. - Reload →
RESET_SESSION+session_start; timeline e stores limpos. - Garantir que store/contexto não vazam entre lições/modos.
- Gate: Smoke de troca de modo + troca de lição + Reload em cada modo.
Arquivos: viewer/index.tsx (session context, reset, handlers), possivelmente viewer_sync / backend se ainda houver uso de WS state.
- Input (keyboard + MIDI) roteado para runtime em WAIT.
- Avaliar nota → atualizar StateFrame v1 (step, total, score, streak, last_result).
- HUD só consome StateFrame (zero cálculo no UI).
- Telemetria:
note_on+ resultado (HIT/MISS/LATE) comt_ms. - Gate: Matriz de modos (Wait + Keyboard, Wait + MIDI) com feedback visível.
Arquivos: LessonEngine, input adapter no viewer, hooks de gamificação, componentes de HUD.
- TimelineController como único driver de tempo (
timeline_ms); play avança, pause congela. - OSMD, falling e HUD apenas consomem
timeline_ms(sem clock próprio). - Event stream como histórico sobre esse clock.
- Alinhamento partitura / falling / progresso com desvio < 20 ms (P95).
- Gate: Teste de desvio automático ou checklist QA.
Arquivos: local-transport-driver, osmd-controller, piano-roll-controller, beat-to-x-mapping, mapping-engine.
- Play/Pause controla TimelineController (execução real); separar “preview MIDI” em ação distinta (ex.: “Ouvir exemplo”).
- Reload já coberto em 1.1; garantir que está ligado ao reset canônico.
- Gate: Play pausa/reinicia; Reload reseta tudo; sem “preview” disfarçado de Play.
- Lead time:
lead_time_msconfigurável (ex.: 2000–3000 ms); notas nascem acima e “encaixam” na tecla no tempo certo. - Count-in: 2–3 compassos de preparação com overlay “3–2–1” e, se possível, click do metrônomo; timeline só inicia após pre-roll.
- Gate: Primeira nota cai no tempo certo; usuário vê count-in antes de começar.
- Decisão explícita: (a) só visual, input desativado + banner, ou (b) treino com HUD. Implementar e documentar.
- Gate: Comportamento definido, testado e documentado.
- Quebrar
index.tsxem módulos (ex.:AppShell,Transport,Visualization,AudioEngine) — alvo: maior módulo ≤ 400 linhas. - Tabela única de mapeamento teclado↔nota + testes paramétricos; fallback para mapeamento antigo por flag.
- Contratos e tipos explícitos (Props, eventos, payloads); verificação em CI.
- Gate: Nenhum ciclo de imports; lint ok; smoke da matriz de modos passando.
(Detalhes em ROADMAP.md Fase 2.)
- Engine de polifonia (voice stealing, limite de vozes, opcional “safe mode”).
- Testes de integração áudio; métricas de latência e underrun.
- Gate: Rollout gradual com flag; sem regressão em cenários atuais.
(Detalhes em ROADMAP.md Fase 3.)
- Perfilagem e otimizações (render, áudio).
- Pipeline de release com canário, health-checks e rollback automático.
- SLOs, runbooks, alertas.
(Detalhes em ROADMAP.md Fase 4.)
| Sprint | Foco | Entregáveis |
|---|---|---|
| 1–2 | Fase 0 + Fase 1.1–1.2 | Instrumentação mínima; reset de sessão (C1, C2, D2); Wait + HUD (A1, A2) |
| 3 | Fase 1.3–1.4 | Timeline único (B1); Play/Reload corretos (D1, D2) |
| 4 | Fase 1.5–1.6 | Lead time + count-in (E1, E2); Plain definido (C3); smoke completo |
| 5–6 | Fase 2 | Quebra do index.tsx; mapeamento único; contratos |
| 7+ | Fase 3–4 | Polifonia, performance, pipeline, operação |
- Sessão: Trocar modo ou lição → novo
session_id, HUD zerado,session_startemitido. - Reload: Reset total; timeline e HUD limpos.
- Matriz de modos: Wait (Keyboard + MIDI), Time Film, Plain — com feedback esperado.
- Telemetria:
session_start/session_end,note_on+ resultado,t_ms. - Smoke manual: Troca modo/lição, Reload, Play/Pause, count-in, falling.
- Bugs e plano de correção:
bugs/sprint-2026-01-23/(relatorio-qa.md,plano-correcao.md). - Roadmap técnico (4 fases):
ROADMAP.md. - Sprint runtime/UI:
docs/sprints/2026-01-23_runtime-ui.md. - Contratos viewer:
core/services/contracts/viewer_messages_v1.py,viewer/types.ts.
O app está em transição de arquitetura (WS → Event Stream + REST) e com bugs P0 que impedem uso confiável: Wait sem feedback, sync partitura/falling quebrado, vazamento de sessão, controles Play/Reload incorretos, falling sem lead time e sem count-in.
Próximos passos imediatos:
- Fechar P0/P1 (Fase 1): reset de sessão, Wait + HUD, timeline único, Play/Reload, lead time + count-in, Plain definido.
- Instrumentar (Fase 0) em paralelo para visibilidade e baseline.
- Refatorar
index.tsxe mapeamento (Fase 2) assim que o runtime estiver estável. - Só então polifonia (Fase 3) e performance/operação (Fase 4), com flags e rollout controlado.
Prioridade: estabilidade e corretude primeiro; depois manutenibilidade e novas capacidades.