ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 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.