Aprender para Todos
Plataforma de estudo gratuita, da pré-escola ao ENEM, construída sem backend e sem conta: o progresso vive no dispositivo do estudante.
Contexto
Projeto social: uma plataforma de estudo gratuita, organizada por etapa e ano escolar, cobrindo da pré-escola ao ensino médio, incluindo ENEM e redação. O público é estudante, família que quer acompanhar, vestibulando e professor ou ONG, em boa parte gente acessando pelo celular.
Desafio
Sustentar uma plataforma educacional completa com custo de operação próximo de zero, e sem coletar dado pessoal de estudante, sendo muitos deles menores de idade. Tirar o backend da equação resolve custo e privacidade de uma vez, mas deixa duas perguntas abertas: onde vive o progresso do aluno, e como se autora conteúdo sem um CMS.
Meu papel
Arquitetura, desenvolvimento, modelagem do domínio educacional, acessibilidade, testes, infraestrutura e deploy.
Responsabilidades
- Arquitetura da aplicação e do modelo de conteúdo.
- Modelagem do domínio educacional: etapas, anos, áreas, trilhas, módulos, lições e quizzes.
- Camada de persistência local sobre IndexedDB.
- Acessibilidade como preferência de primeira classe.
- Suíte de testes e pipeline de CI.
- Infraestrutura AWS e deploy em dois ambientes.
Restrições
- Projeto gratuito: o custo de operação precisa caber em quem o mantém, indefinidamente.
- Público inclui crianças: conta e cadastro significam coleta de dado pessoal de menor.
- Mobile first, com aparelho possivelmente modesto: cada KB de JavaScript é pago pelo usuário.
- Base de conteúdo ampla (várias etapas, anos e componentes) que precisa crescer sem virar bagunça.
Arquitetura
- Next.js 16 com App Router e export estático: nenhum servidor de aplicação, nenhum banco em runtime.
- Nenhuma dependência de runtime além do próprio framework: next, react e react-dom. Sem biblioteca de estado, de UI ou de acesso a IndexedDB.
- Persistência no dispositivo: wrapper próprio sobre IndexedDB, com um repositório por domínio (progresso, quizzes, caderno de erros, plano de estudo, rascunhos, histórico).
- Preferências pequenas e síncronas em localStorage, separadas do IndexedDB para não bloquear o primeiro render.
- Conteúdo como código TypeScript, com IDs branded para o compilador barrar referência cruzada errada entre entidades.
- Pipeline editorial no próprio domínio: validadores puros que retornam issues estruturados, relatório de cobertura e estados editoriais explícitos.
- Console editorial local rodando no browser, sem CMS e sem servidor.
- Envelope versionado de exportação e importação de dados, validado na entrada, como alternativa a sincronizar por servidor.
Principais decisões técnicas
Não ter backend: o progresso do estudante vive no dispositivo, em IndexedDB.
Por quê
Conta e banco de dados significariam coletar dado pessoal de criança, assumir a responsabilidade de guardá-lo e pagar servidor para sempre. Também colocariam uma tela de cadastro entre o aluno e a lição. Sem backend, o custo de operação de um projeto gratuito cai para hospedagem estática, e não existe dado de menor para vazar.
Trade-offs
- O progresso não sincroniza entre aparelhos: trocar de celular começa do zero.
- Limpar os dados do navegador apaga o histórico de estudo.
- Sem servidor não há telemetria agregada, nenhuma visão de como o conteúdo está sendo usado.
- Mitigação parcial: exportação e importação de dados em um envelope versionado, controlado pelo usuário.
Zero dependências de runtime além do framework.
Por quê
Cada KB de JavaScript é pago justamente pelo aparelho modesto que é o público-alvo. E cada dependência é manutenção futura que um projeto gratuito não tem como custear a longo prazo. Context do React e a API nativa de IndexedDB dão conta do que o produto precisa.
Trade-offs
- Mais código próprio para manter. O wrapper de IndexedDB, por exemplo, é nosso.
- Abre mão dos recursos prontos de bibliotecas maduras (devtools, cache, utilitários).
- Em troca: bundle pequeno, superfície de supply chain praticamente nula e nenhuma quebra vinda de terceiro.
Conteúdo como código versionado, com testes guardando a própria base de conteúdo.
Por quê
Um CMS traria de volta o servidor e o banco que a primeira decisão removeu. Com o conteúdo em TypeScript, o compilador garante a forma e o CI valida cobertura e pendências antes do deploy. Erro de conteúdo vira build vermelho, não bug em produção.
Trade-offs
- Autoria passa a exigir build e Git, o que não serve para autor não técnico.
- Por isso existe o console editorial local: autoria no browser, com rascunho em IndexedDB e exportação, sem reintroduzir servidor.
- Uma base de conteúdo grande vira muitos arquivos TypeScript para navegar.
Implementação
- Trilhas por etapa, ano e componente curricular, com lição e quiz canônicos por módulo.
- Caderno de erros, plano de estudo, progresso e métricas, tudo local.
- Área de ENEM, incluindo redação.
- Múltiplos perfis no mesmo dispositivo, para quando o aparelho é compartilhado.
- Acessibilidade com três eixos (movimento reduzido, alto contraste e tamanho de texto), com padrão herdado das preferências do sistema operacional e sobrescrita persistida do usuário.
- Exportação e importação dos dados do dispositivo, com validação e pré-visualização antes de importar.
Operação em produção
- Export estático publicado em S3 privado, servido por CloudFront com OAC.
- URLs limpas resolvidas na borda por uma CloudFront Function em viewer-request.
- Infraestrutura provisionada por scripts idempotentes e versionados, com usuário IAM por ambiente.
- Cache separado por classe de asset: HTML revalidável, assets com hash imutáveis.
- CI roda testes, lint, build e uma validação do export antes de qualquer deploy.
- Dois ambientes: staging automático no merge, produção só por acionamento manual com confirmação explícita.
- Sem servidor de aplicação em produção: não há o que operar, corrigir ou escalar.
Resultados
- Custo de operação limitado a hospedagem estática, o que torna um projeto gratuito sustentável.
- Nenhum dado de estudante sai do dispositivo: não há conta, não há banco, não há analytics.
- Integridade do conteúdo protegida por testes que rodam no CI, cobrindo persistência, domínio e a própria base de conteúdo.
- Acessibilidade tratada como parte da arquitetura, e não como ajuste posterior: herda a preferência do sistema e deixa o usuário sobrescrever.
- Cada bug de conteúdo virou um teste permanente, em vez de uma correção pontual.
Stack
- Next.js 16
- React 19
- TypeScript
- Tailwind CSS 4
- IndexedDB
- Vitest
- AWS S3
- AWS CloudFront
- CloudFront Functions
- GitHub Actions