ESP32-S3 Bench Guide
ESP32‑S3 N16R8 벤치 가이드: 실시간 핀아웃, 강의, 시뮬레이터 및 벤치 로그
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Aplicativo para ajudar a memorizar palavras — frontend em React + Vite. • Node.js 20.19+ ou 22.12+ • npm A URL do backend vem de src/config.js, que traz um padrão para cada ambiente: Com isso o projeto funciona sem configuração extra, tanto localmente quanto no deploy. Defina VITE_API_URL — ela tem precedência sobre os padrões: Para o deploy, defina VITE_API_URL nas variáveis de ambiente do projeto na Vercel e publique novamente.README 전문 보기 ↗
Aplicativo para ajudar a memorizar palavras — frontend em React + Vite.
A URL do backend vem de src/config.js, que traz um padrão para cada ambiente:
| Ambiente | Padrão |
|---|---|
Desenvolvimento (npm run dev) | http://localhost:8080 |
Produção (npm run build) | https://mem-words-backend.onrender.com |
Com isso o projeto funciona sem configuração extra, tanto localmente quanto no deploy.
Defina VITE_API_URL — ela tem precedência sobre os padrões:
cp .env.example .env # desenvolvimento; o .env não é versionado
Para o deploy, defina VITE_API_URL nas variáveis de ambiente do projeto na
Vercel e publique novamente.
Por que o padrão fica no código, e não em um
.env.production? O build da Vercel não aplica arquivos.envversionados no repositório — verificado na prática: com.env.productionpresente e correto, o site publicado reportava a variável como indefinida. Um padrão embutido no código é embutido no bundle em tempo de build e não depende do comportamento do host.
Variáveis lidas pelo Vite precisam do prefixo
VITE_e são embutidas no bundle em tempo de build — não guarde segredos nelas. A URL do backend é pública, por isso pode ficar no código.
O frontend é publicado na Vercel e o backend no Render. Como são origens diferentes, o backend precisa liberar CORS para a origem do frontend.
O botão "Entrar com o Google" (Google Identity Services) exige
VITE_GOOGLE_CLIENT_ID — sem ela, o botão simplesmente não aparece, e o
formulário de e-mail e senha continua funcionando normalmente.
VITE_GOOGLE_CLIENT_ID=seu-client-id.apps.googleusercontent.com
Precisa ser o mesmo Client ID configurado no backend (GOOGLE_CLIENT_ID)
— valores diferentes fazem todo login com Google falhar com um erro genérico
do backend.
A tela /diagnostico informa de onde veio a URL deste build:
| O que aparece | O que significa |
|---|---|
Origem: VITE_API_URL | O build recebeu a variável de ambiente. |
Origem: padrão de produção | Build de produção usando o padrão de src/config.js. |
Origem: padrão de desenvolvimento | Build de desenvolvimento apontando para localhost. |
falha na conexão com endpoint correto | A URL está certa; o problema é o backend (fora do ar ou sem CORS liberado). |
npm install # instala as dependências
npm run dev # servidor de desenvolvimento em http://localhost:5173
npm run build # gera o bundle de produção em dist/
npm run preview # serve o bundle de produção localmente
npm run lint # analisa o código com oxlint
| Rota | Tela | Acesso |
|---|---|---|
/entrar | Entrada por e-mail e senha | pública; com sessão ativa, redireciona para / |
/cadastro | Criação de conta | pública; com sessão ativa, redireciona para / |
/ | Início da área autenticada | protegida |
/diagnostico | Status da conexão com o backend | pública |
/galeria | Galeria do design system | pública |
| qualquer outra | Página não encontrada | pública |
Uma rota protegida só é exibida com sessão ativa. Quem chega sem sessão é
levado a /entrar e, depois de autenticar, volta ao endereço que tentou
abrir. Enquanto a sessão guardada está sendo confirmada, a tela mostra
carregamento — e não a tela de entrada, que apareceria e desapareceria a cada
recarga.
/diagnostico é pública de propósito: é a ferramenta para descobrir que o
backend está fora do ar, o que inclui o caso em que a entrada não funciona
por isso.
Deploy: as rotas são resolvidas no navegador, então o host precisa devolver
index.htmlpara qualquer endereço — sem isso, abrir/entrardireto responde 404 (verificado servindodist/em um servidor estático puro). É o que overcel.jsonna raiz faz, com uma regra de reescrita para/index.html.
A galeria era alcançável por
?galeriana URL. Agora que a aplicação tem rotas de verdade, ela mora em/galeria; o parâmetro antigo não tem mais efeito.
O backend (mem-words-backend)
emite dois tokens no login, e este frontend consome os endpoints
POST /auth/register, POST /auth/login, POST /auth/refresh,
POST /auth/logout e GET /users/me.
| Token | O que é | Onde vai |
|---|---|---|
| Access token | JWT curto (15min) | cabeçalho Authorization: Bearer de cada chamada autenticada |
| Refresh token | valor opaco, de uso único | corpo das chamadas de renovação e de saída |
Onde os tokens ficam guardados. Em localStorage, sob a chave
mem-words.auth, junto com os dados do usuário. É o que permite recarregar a
página sem entrar de novo. A contrapartida é conhecida e aceita: um XSS no
frontend alcançaria o token, porque o backend devolve os tokens no corpo da
resposta em vez de gravar um cookie httpOnly. A decisão, suas alternativas e
o que o backend teria de mudar estão registrados em
openspec/changes/archive/*-add-authentication/design.md.
Quando o armazenamento não está disponível — janela privativa, dados de site bloqueados —, a aplicação continua funcionando; a sessão passa a valer apenas enquanto a página estiver aberta.
Sessão guardada não é sessão válida. Ao abrir a aplicação, os tokens
guardados são conferidos contra GET /users/me antes de a sessão ser
considerada ativa: eles podem estar expirados, revogados ou pertencer a uma
conta excluída. Se o backend estiver inacessível, os tokens não são
apagados e a tela informa falha de conexão — uma queda de rede não deslogaria
ninguém.
Renovação automática. Uma resposta 401 em chamada autenticada dispara
uma renovação e repete a requisição original uma única vez. Como o refresh
token é de uso único e reapresentá-lo faz o backend revogar todas as sessões
do usuário, renovações concorrentes na mesma aba convergem para uma única
chamada — quem chega durante uma renovação aguarda a mesma promessa.
Duas abas cujos tokens expirem no mesmo instante ainda podem apresentar o mesmo refresh token, o que o backend trata como reuso e derruba a sessão. O caminho de recuperação é entrar de novo; sincronizar as abas é melhoria registrada para depois.
/diagnostico consulta o endpoint GET /health do backend assim que carrega
e mostra o resultado:
O botão Verificar novamente repete a consulta sem recarregar a página.
src/
├── api/
│ ├── ApiError.js # falha de chamada em formato único
│ ├── client.js # cliente HTTP: tempo limite, erros, renovação
│ ├── auth.js # /auth/register, /login, /refresh, /logout
│ ├── users.js # /users/me
│ └── health.js # /health
├── auth/
│ ├── tokenStore.js # tokens em memória, espelhados no localStorage
│ ├── session.js # contexto, estados e erro de cadastro sem sessão
│ ├── AuthProvider.jsx # ciclo de vida da sessão
│ ├── useAuth.js # acesso das telas à sessão
│ ├── useAuthForm.js # estado comum dos formulários de autenticação
│ ├── validation.js # regras espelhando as do backend
│ ├── RequireAuth.jsx # guarda de rota
│ └── GuestOnly.jsx # mantém quem tem sessão fora de entrar/cadastro
├── components/ # design system, moldura autenticada, status
├── pages/ # entrada, cadastro, início, diagnóstico, 404
├── routes.jsx # mapa de rotas
├── config.js # leitura de VITE_API_URL
└── App.jsx # provedor de sessão + roteador
Como o backend fica em outra origem, ele precisa liberar CORS para a origem do frontend. No backend isso é a variável
CORS_ORIGIN(lista separada por vírgula); hoje ela aceita qualquer origem, e ao ser restringida precisa incluir a origem publicada na Vercel — caso contrário o navegador bloqueia as requisições e toda tela passa a informar falha de conexão.
O repositório usa OpenSpec para desenvolvimento orientado a especificações. Para instalar a CLI:
npm install -g @fission-ai/openspec
As especificações ficam em openspec/ e os comandos /opsx:* estão
disponíveis no Claude Code.