Documentação Técnica
Stack, arquitetura, banco de dados e instruções de deploy do BBrain.
Stack Tecnológica
Arquitetura
O BBrain é uma aplicação monolítica simples. Não há frameworks, ORMs ou dependências externas além da googleapis.
│
↓ HTTP (JSON REST)
│
Fly.io — server.js ← Node.js nativo, porta 3000
├── → Google Sheets API v4 ← banco de dados
└── → Gmail SMTP (465/TLS) ← emails de reset
Autenticação
Mecanismo
A senha é armazenada como SHA-256 hash. Nunca há texto puro em disco ou memória. A função readAuth() segue esta ordem de prioridade:
- authCache (Google Sheets) — carregado no boot via
initSheets(). Prioridade máxima — garante que a senha definida pelo usuário persiste entre deploys sem ser sobrescrita. - BBRAIN_PASSWORD_HASH — hash SHA-256 definido diretamente como secret no Fly.io. Usado se não há Sheets configurado.
- BBRAIN_PASSWORD — senha provisória em texto. O servidor calcula o hash em runtime e força troca de senha no primeiro login.
- Arquivo local —
auth.jsonna raiz. Fallback para desenvolvimento local.
MASTER_ADMIN
brunomassa é o admin master vitalício, hardcoded em server.js como MASTER_ADMIN. Email fixo: brunobrm@gmail.com. Esse usuário não pode ser alterado por nenhum deploy, reset de senha ou venda do produto.
LEGACY_USERS
Usuárias com acesso vitalício e mensagem de primeiro acesso: Karina Lisboa Cerqueira Massa (klisboacerqueira@gmail.com) e Cecília Lisboa Massa. No primeiro login, o sistema exibe uma mensagem especial e a persiste no rodapé do app via localStorage.
Troca forçada de senha
Quando o login retorna force_password_change: true, o frontend exibe um formulário obrigatório antes de liberar o app. A nova senha é salva via POST /api/auth/change-password com o token Bearer. Após a troca, force_password_change é gravado como false na aba Config do Sheets.
Token de sessão
Após login bem-sucedido, o servidor gera um token aleatório (32 bytes). O token é salvo no localStorage do browser com validade de 30 dias e enviado no header Authorization: Bearer <token> em todas as requisições. O frontend invalida o token localmente ao trocar de dia (expiração diária por cliente).
Banco de Dados
O Google Sheets funciona como banco relacional simples. A planilha possui três abas:
Aba: Ideas
| Coluna | Tipo | Descrição |
|---|---|---|
id | string | ID gerado no servidor (YYYYMMDD-XXXXX) |
text | string | Texto da ideia |
source | string | Origem: web, whatsapp, api |
whatsapp_from | string | Número de origem (só WhatsApp) |
created_at | ISO 8601 | Data/hora de criação |
status | string | nova, em_analise, no_roadmap, arquivada |
tags | JSON array | Tags atribuídas |
evaluation | string | Avaliação gerada pela IA |
roadmap_phase | string | backlog, planejado, em_execucao, concluido |
connections | JSON array | IDs de ideias relacionadas |
session_id | string | ID da sessão em que foi capturada |
updated_at | ISO 8601 | Última atualização |
Aba: Sessions
| Coluna | Tipo | Descrição |
|---|---|---|
id | string | ID gerado no servidor |
started_at | ISO 8601 | Início da sessão |
ended_at | ISO 8601 | Fim da sessão |
location | string | Local da sessão |
initial_thoughts | string | Pensamento inicial do check-in |
duration_minutes | number | Duração calculada em minutos |
features_worked | JSON array | Features trabalhadas na sessão |
ideas_captured | JSON array | IDs das ideias capturadas |
social_content | string | Post sugerido para redes sociais |
Aba: Config
Persiste autenticação e configurações de usuário entre deploys.
| Chave | Tipo | Descrição |
|---|---|---|
password_hash | string | SHA-256 hash da senha |
username | string | Nome de usuário |
email | string | Email para recuperação de senha |
force_password_change | bool | Se true, força troca de senha no próximo login |
plan | string | Plano atual: free, pro, power |
reminder_frequency | string | Frequência de lembretes: daily, every2days, every15days, monthly |
reminder_time | string | Horário do lembrete (HH:MM) |
reminder_channels | string | Canais: email, whatsapp ou ambos |
last_reminder | ISO 8601 | Timestamp do último lembrete enviado |
Service Account
Acesso à API via service account Google. As credenciais podem ser fornecidas como JSON completo em GOOGLE_CREDENTIALS_JSON ou como variáveis individuais (client_email, private_key, etc). O servidor monta o objeto automaticamente.
Variáveis de Ambiente
| Variável | Obrigatória | Descrição |
|---|---|---|
GOOGLE_SHEET_ID | Sim | ID da planilha Google Sheets |
GOOGLE_CREDENTIALS_JSON | Sim* | JSON completo da service account (minificado) |
client_email | Sim* | Email da service account (alternativa ao JSON) |
private_key | Sim* | Chave privada RSA da service account |
BBRAIN_PASSWORD | Não** | Senha provisória em texto — forçará troca no primeiro login |
BBRAIN_PASSWORD_HASH | Não** | SHA-256 da senha (hex) — sem troca forçada |
BBRAIN_USERNAME | Não | Nome de usuário (padrão: brunomassa) |
GMAIL_FROM | Não | Endereço Gmail remetente para reset de senha |
GMAIL_APP_PASSWORD | Não | App Password do Gmail (16 chars) |
WHATSAPP_ACCESS_TOKEN | Não | Token Meta Cloud API para envio via WhatsApp |
WHATSAPP_PHONE_NUMBER_ID | Não | ID do número WhatsApp Business |
WHATSAPP_VERIFY_TOKEN | Não | Token de verificação do webhook Meta |
PORT | Não | Porta do servidor (padrão: 3000) |
* Forneça GOOGLE_CREDENTIALS_JSON ou as variáveis individuais (client_email, private_key, etc.) — o servidor monta as credenciais automaticamente de qualquer uma das formas.
** Se não definidas, o servidor usa a auth salva na aba Config do Sheets (carregada no boot). Isso garante que a senha persiste entre deploys sem redefinir variáveis.
Endpoints da API
| Método | Endpoint | Auth | Descrição |
|---|---|---|---|
| GET | /api/ideas | Sim | Lista todas as ideias (filtros: ?status=, ?source=) |
| POST | /api/ideas | Sim | Cria nova ideia |
| PATCH | /api/ideas/:id | Sim | Atualiza status, tags, evaluation, roadmap_phase, connections |
| DELETE | /api/ideas/:id | Sim | Remove ideia permanentemente |
| GET | /api/sessions | Sim | Lista todas as sessões |
| POST | /api/sessions | Sim | Cria nova sessão (check-in) |
| PATCH | /api/sessions/:id | Sim | Encerra sessão (ended_at, duration_minutes) |
| GET | /api/settings | Sim | Retorna configurações do usuário (plano, lembretes) |
| POST | /api/settings | Sim | Salva configurações (plan, reminder_frequency, reminder_time, reminder_channels) |
| GET | /api/report/monthly | Sim | Relatório do mês (?month=2026-03) |
| GET | /api/auth/status | — | Verifica token ativo |
| POST | /api/auth/login | — | Login — retorna token, force_password_change, firstLoginMessage |
| POST | /api/auth/change-password | Sim | Troca de senha forçada (requer token válido) |
| POST | /api/auth/logout | Sim | Invalida o token atual |
| POST | /api/auth/setup | — | Configuração inicial (primeiro acesso) |
| POST | /api/auth/reset-request | — | Solicita reset de senha (envia email) |
| POST | /api/auth/reset | — | Confirma reset com código de 6 dígitos |
| GET | /api/version | — | Healthcheck — retorna versão atual |
Deploy
Requisitos
Fly.io CLI instalado (flyctl), autenticado com a conta Aproove. O arquivo fly.toml deve estar na raiz do projeto.
Comando
Fluxo
O Fly.io detecta automaticamente Node.js via Dockerfile ou buildpack. A aplicação é implantada na região GRU (São Paulo) no free tier, com uma máquina compartilhada de 256MB RAM.
Estrutura de Arquivos
├── server.js ← servidor principal (Node.js nativo)
├── fly.toml ← config do Fly.io
├── Dockerfile ← imagem Docker
├── .github/workflows/ ← GitHub Actions (fly-deploy.yml)
├── package.json
├── laboratorio/
│ ├── index.html ← BBrain app (acessado via /entrar)
│ ├── landing.html ← LP pública (bbrainapp.you/)
│ ├── privacidade.html ← Política de Privacidade (/privacidade)
│ └── DOCUMENTACAO/
│ ├── index.html ← hub de docs
│ ├── tecnica.html
│ ├── roadmap.html
│ ├── conceito.html
│ ├── investidores.html
│ ├── guia-uso.html
│ ├── api.html
│ └── publicar-app.html
Rotas de front-end
| URL | Arquivo | Descrição |
|---|---|---|
/ (bbrainapp.you) | landing.html | Landing page pública com planos |
/entrar | index.html | App BBrain (autenticado) |
/laboratorio | index.html | Alias para o app |
/privacidade | privacidade.html | Política de Privacidade |
/conceito | conceito.html | Conceito do produto |
/guia | guia-uso.html | Guia de uso |