Entrada sem conta
Aluno escaneia o QR Code da turma (ou digita o código curto) e já começa a praticar — zero cadastro, zero senha pra esquecer.
Aprender a ler começa por ouvir — app de prática de leitura em voz alta, sem fricção nenhuma pro aluno.
Professor monta a turma e a lista de palavras. Aluno escaneia um QR Code, sem criar conta nem lembrar senha, e já começa a praticar: ouve a palavra falada pelo celular e repete em voz alta. Projeto de extensão universitária em grupo, com backend real em Supabase e app publicado como APK de testes.
Fluxo pensado pro aluno nunca travar em nada técnico — só a palavra e o botão de ouvir.
O Palavra Falada nasceu na disciplina de extensão (Ciência da Computação) em grupo, com um objetivo simples de enunciar e difícil de executar bem: deixar um aluno praticar leitura em voz alta sem precisar de conta, senha ou qualquer fricção técnica no meio do caminho.
O professor cria a turma e a lista de palavras pelo celular ou navegador. O aluno só escaneia um QR Code — ou digita um código curto de 6 caracteres — e cai direto na prática: ouve a palavra (texto-pra-voz em português do Brasil) e repete em voz alta. Fui responsável pela maior parte da implementação de frontend/backend e por resolver os bugs de produção que só aparecem depois que o app sai do ambiente de desenvolvimento.
"A parte mais difícil nunca foi o React Native — foi descobrir por que o Postgres deixava passar uma RLS certa e ainda assim bloqueava tudo. O detalhe que ninguém vê é sempre o que mais ensina."
Construído pra quem está alfabetizando, não pra quem entende de app.
Aluno escaneia o QR Code da turma (ou digita o código curto) e já começa a praticar — zero cadastro, zero senha pra esquecer.
Cada palavra é falada pelo motor de texto-pra-voz do próprio aparelho — sem depender de áudio pré-gravado.
Cria, edita e exclui turmas e tarefas; acompanha quem já entrou em cada turma e consegue ouvir qualquer palavra antes de aplicar.
Um cabeçalho e um menu reaproveitados em todas as telas do professor — unificado depois de várias telas terem crescido de forma inconsistente.
Trocamos o UUID gigante do QR Code por um código de 6 caracteres — mais fácil de ler, digitar e projetar na lousa.
Só a palavra, o ícone de ouvir e o botão de confirmar. Nada de categoria, prefixo técnico ou menu sobrando na tela.
O aluno ouve, repete em voz alta e confirma tocando no ✓ — prática acompanhada pelo professor, sem fingir que existe reconhecimento de voz automático.
Build gerado via EAS e publicado como Release no GitHub — instala direto no Android, fora da Google Play, pra quem quiser testar agora.
App multiplataforma com backend real, não só telas bonitas.
Base do app, rodando em Android e Web a partir do mesmo código.
Navegação por arquivos, com grupos de rotas separando o fluxo do aluno e do professor.
Auth, banco Postgres e API de dados — backend completo sem servidor próprio pra manter.
Row Level Security controlando o que aluno (anônimo) e professor (autenticado) podem ler e escrever.
Scanner nativo lê o código da turma e resolve pro id real via consulta ao banco.
Fala cada palavra em português do Brasil usando a engine de voz do próprio aparelho.
Pipeline de build na nuvem gerando o APK direto a partir do código, sem Android Studio local.
Modal de alerta/confirmação próprio via Context — substitui o Alert nativo, que não funciona na versão web.
Os bugs que só aparecem fora do ambiente de desenvolvimento — e como rastreei cada um até a causa real.
Criei as policies de Row Level Security corretas e mesmo assim o app continuava sem achar nenhuma turma. A causa não estava nas policies: faltava o GRANT de acesso à API de dados pro papel anon — uma camada de permissão que é avaliada antes da RLS, e que falha em silêncio (sem erro, só devolve vazio).
Todo Alert.alert do app — inclusive a confirmação de exclusão — simplesmente não fazia nada ao rodar na versão Web. O motivo: no react-native-web, o módulo de Alert é um stub vazio. Resolvi com um sistema próprio de modal via Context API, funcionando igual em qualquer plataforma.
O APK gerado pelo EAS abria e fechava na hora, sem nenhum erro visível. Capturando o log de crash via adb logcat, achei a causa: o .env está no .gitignore, e o EAS Build respeita isso — as variáveis do Supabase nunca chegavam no build. Corrigido cadastrando as variáveis direto como EAS Environment Variables, fora do arquivo local.
O Stack Navigator do grupo do professor estava configurado com cabeçalho nativo ligado por padrão, em cima de cabeçalhos já customizados em cada tela — resultado: duas barras de título empilhadas. Padronizei num único componente de cabeçalho reusável e desliguei o nativo onde já existia um customizado.
O código da turma começou como um UUID inteiro — ótimo pra chave de banco, péssimo pra alguém digitar manualmente ou ler no campo de teste. Troquei por um código curto de 6 caracteres gerado na criação da turma, resolvido pro id real via consulta no momento da leitura.
O botão de excluir turma ficava dentro do card inteiro (que também navega ao tocar). No nativo isso nunca foi problema, mas no React Native Web o clique sobe pelo DOM — excluir também disparava a navegação. Separei a área clicável de navegação dos botões de ação, que passaram a ser elementos irmãos, não aninhados.
Cada projeto deixa marcas. Aqui ficam as mais importantes deste.
Policies corretas não bastam se o GRANT de base da API não existir — são duas camadas distintas, e a falha em uma delas não gera erro nenhum.
Build de produção não mostra overlay de erro — aprendi a capturar crash via logcat e decodificar logs comprimidos em brotli direto da API do EAS.
APIs nativas como Alert e comportamento de clique em elementos aninhados mudam de verdade entre nativo e react-native-web — testar só num ambiente esconde bugs reais.
O EAS Build ignora o que o .gitignore ignora — variáveis de ambiente locais precisam virar configuração explícita do projeto, não só um arquivo .env no disco.
Tirar categoria, prefixo e menu da tela do aluno foi tão importante quanto qualquer funcionalidade nova — menos escolha é o produto certo pra esse público.
Boa parte das mudanças vieram de feedback direto do time e do orientador — traduzir "tá poluído" ou "não funciona" em causa raiz técnica é parte do trabalho.
O Palavra Falada é um trabalho em grupo, mas boa parte da implementação e dos bugs de produção resolvidos aqui foram meus. Veja o código ou conheça outros projetos do portfólio.