尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗App para planejar viagens em grupo: orçamento diário por pessoa, despesas realizadas, aportes ("receitas") dos participantes e relatório de orçado x realizado x saldo. Multiusuário, com login e controle de quais usuários enxergam quais viagens.
Banco de dados: o próprio Google Sheets (não há Postgres). Isso é intencional - veja Limitações antes de usar em produção com muitos usuários simultâneos.
O acesso à planilha é feito via Google Apps Script, publicado como Web App - mesmo padrão já usado em outros projetos aqui. Não precisa criar projeto no Google Cloud, habilitar API nem gerar chave de service account.
Código.gs e cole o conteúdo de
apps-script/Codigo.gs deste repositório.+ ao lado de "Arquivos" → Script),
chame de Config e cole o conteúdo de apps-script/Config.gs. Esse
arquivo separado existe justamente para guardar os valores reais desta implantação - daqui pra
frente, quando você for aplicar uma atualização de código, só mexe em Codigo.gs e deixa
Config.gs intocado, sem precisar copiar/colar o segredo e os IDs de novo.appsscript.json". Depois abra esse arquivo e substitua o conteúdo pelo de
apps-script/appsscript.json.Config.gs, troque a constante SHARED_SECRET por uma string aleatória longa (ex.: gere com
openssl rand -base64 32 no seu terminal). Guarde esse valor - ele também vai para a variável de
ambiente APPS_SCRIPT_SHARED_SECRET do Next.js. Sem esse segredo, qualquer pessoa que
descobrir a URL do Web App conseguiria ler/escrever na planilha, já que o Web App é publicado
como "Qualquer pessoa" (o Google não oferece outra forma de chamada servidor-a-servidor aqui).
Se for usar a funcionalidade de anexos, preencha também DRIVE_ROOT_FOLDER_ID com o ID da pasta
do Drive (trecho depois de /folders/ na URL da pasta).testeAutorizacao uma vez pelo editor (▶️ ao lado do seletor de função) - isso
vai pedir para você autorizar o script a acessar a planilha (e o Drive, se for usar anexos) com
a sua conta Google. Aceite (pode aparecer um aviso "app não verificado" → clique em
Avançado → Acessar [nome do projeto], normal para scripts pessoais)./exec.Essa URL é o valor de APPS_SCRIPT_URL. Se no futuro você editar o Codigo.gs (ex.: para pegar uma
atualização deste repositório), apague só o conteúdo de Codigo.gs e cole o novo - Config.gs
continua com seus valores reais - depois use Gerenciar implantações → editar (ícone de lápis) →
Nova versão para que a URL publicada reflita as mudanças (a URL em si não muda).
Copie .env.local.example para .env.local (local) e configure as mesmas variáveis no painel do
Vercel (Project Settings → Environment Variables) para produção:
| Variável | Descrição |
|---|---|
APPS_SCRIPT_URL | URL /exec da implantação do Apps Script (passo 7 acima) |
APPS_SCRIPT_SHARED_SECRET | O mesmo valor colado em SHARED_SECRET no Codigo.gs |
NEXTAUTH_SECRET | String aleatória longa (openssl rand -base64 32) |
NEXTAUTH_URL | URL da aplicação (http://localhost:3000 local, URL do Vercel em produção) |
GEMINI_API_KEY | Chave do Google AI Studio (free tier), usada pra ler vouchers na tela Itens (ver seção 6) |
Nunca commite .env.local - já está no .gitignore.
O app não tem cadastro público - só um admin cria usuários pela tela Admin → Usuários. Para criar
o primeiro admin (antes de existir qualquer login), rode localmente, com .env.local
preenchido:
npm run create-admin -- "Seu Nome" "[email protected]" "sua-senha" admin
Esse comando também garante que todas as abas da planilha existam (chama ensureStructure no Apps
Script antes de criar o usuário). Depois disso, faça login normalmente em /login e crie os
demais usuários pela tela admin.
npm install
npm run dev
Abra http://localhost:3000.
.env.local; o apps-script/Codigo.gs pode
ficar no repositório normalmente - o segredo real deve estar só na cópia publicada no Apps
Script e na env var, não commitado em texto claro num arquivo de exemplo).A tela Itens lê PDF/imagem de um voucher e pré-preenche o formulário via Google AI Studio (free tier - uso pessoal, sem cobrança).
GEMINI_API_KEY no .env.local (e na env var equivalente do
Vercel, em produção)./api/trips/{id}/itens/analisar) que faz a chamada ao
Gemini no servidor; o cliente nunca vê a chave.No plano gratuito, o Google pode usar o conteúdo enviado (imagem/PDF do voucher) para melhorar os modelos - avalie isso antes de subir documento com dado sensível de terceiros. Se isso for um problema, ative faturamento (pay-as-you-go) no mesmo projeto do Google AI Studio: o código não muda, só o comportamento de retenção de dado do lado do Google.
Cada aba usa a linha 1 como cabeçalho; a coluna id é sempre um UUID gerado pelo app. A criação das
abas é feita pelo ensureStructure do Apps Script (via tela Admin → Parâmetros ou pelo script de
criação do admin). Esse mesmo botão também serve para atualizar uma planilha já em uso quando o
app ganha um campo novo (ex.: temp_min/temp_max) - ensureStructure acrescenta ao final do
cabeçalho as colunas que ainda faltarem em abas já existentes, sem apagar nada. Depois de
atualizar o Codigo.gs publicado, clique em Admin → Parâmetros → "Verificar/criar abas na
planilha" para aplicar colunas novas às planilhas já em uso.
admin/user), ativo_lat/_lon são preenchidos ao escolher
uma cidade pelo autocomplete nos campos Origem/Destino/Pernoite - nenhum dos dois é digitado)Anexos (comprovantes) não ficam na planilha - vivem direto no Google Drive, numa
subpasta por viagem (nome = "{nome da viagem} - {id}") dentro da pasta configurada em
DRIVE_ROOT_FOLDER_ID (Config.gs), com uma subpasta por categoria dentro de cada
viagem. O próprio Drive é a fonte da verdade da listagem - não há aba extra pra manter
sincronizada.
Foi uma escolha deliberada usar a planilha existente como banco de dados ao vivo, e o acesso via Apps Script (em vez de service account do Google Cloud) traz limitações extras a considerar:
Codigo.gs usa LockService para serializar leituras+escritas de uma mesma ação, mas isso não
elimina 100% o risco entre ações diferentes.UserTrip apontando para uma
viagem já removida manualmente na planilha).You do not have permission to call DriveApp...Aparece como DriveApp.getFolderById ou DriveApp.Folder.createFolder, em ações que mexem na
pasta de anexos (enviar anexo, listar anexos, excluir uma viagem), e quer dizer que o script foi
autorizado com um escopo de Drive estreito demais. Acontece quando o appsscript.json colado no
editor não declara oauthScopes - sem essa lista, o Apps Script infere os escopos sozinho e pode
escolher um mais restrito que o necessário. Para resolver:
appsscript.json", abra o arquivo e garanta que ele tem o bloco oauthScopes igual ao de
apps-script/appsscript.json.testeAutorizacao pelo editor de novo. Como os escopos mudaram, o Google vai pedir
autorização outra vez - agora incluindo o acesso ao Drive.Atenção ao "Autorização OK!": até uma versão recente,
testeAutorizacaosó lia a pasta raiz, então passava com o escopo de leitura e dava um falso positivo - o teste dizia OK e o upload de anexo continuava quebrando emcreateFolder. Hoje a função cria e descarta uma pasta temporária de propósito: se o escopo estiver errado, ela falha ali, que é o comportamento útil. Se o seu editor ainda tem a versão antiga, cole oCodigo.gsatual antes de confiar no resultado do teste.
Excluir uma viagem funciona mesmo com esse erro pendente: a remoção da pasta no Drive é feita por último e não derruba a exclusão - o app só avisa que a pasta ficou para trás.
Se o uso crescer (muitos usuários simultâneos, muitas viagens) ou a app precisar rodar em nome de uma identidade técnica separada da conta pessoal, o caminho recomendado é migrar para um banco relacional (Postgres via Neon/Vercel Postgres) ou para uma service account do Google Cloud, mantendo a mesma estrutura de dados.
Next.js 16 (App Router) + TypeScript + Tailwind CSS · NextAuth.js v5 (Credentials, sessão JWT) · Google Apps Script (Web App) como camada de acesso à planilha · zod · bcryptjs.