Javis OS
Javis OS is an Agentic AI that assists entrepreneurs in business tasks, helping them grow their work.
AI translation
Sistema de gestão de plantões e escalas para equipes hospitalares.
Translation pending
BusinessTypeScript · JavaScriptGitHub @FeSeijiOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Sistema de gestão de plantões hospitalares do GAMI (Grupo Anestesia Materno Infantil): escala de plantões, trocas entre médicos, férias e congressos, fichas anestésicas, casos fora, gestão de usuários e o BM Financeiro mensal.
O projeto é dividido em duas aplicações:
Backend
@supabase/supabase-js recomenda v20+)Frontend
.xlsxDeploy: backend no Render, frontend na Vercel, banco no Supabase.
Plantão/
├── Backend/
│ ├── src/
│ │ ├── controllers/
│ │ │ ├── authController.js # Login, refresh, cadastro, /me (perfil e troca de senha) e redefinição de senha
│ │ │ ├── users.js # Busca de médicos e gestão de usuários (inclui a aprovação de cadastros)
│ │ │ ├── plantoes.js # Plantões, vagas, trocas e histórico
│ │ │ ├── afastamentos.js # Férias e congressos (pedido do médico, aprovação da gestão)
│ │ │ ├── fichas.js # Fichas anestésicas (com foto) e a exportação para o faturamento
│ │ │ ├── casosFora.js # Casos fora da escala
│ │ │ ├── hospitais.js # Hospitais dos casos fora
│ │ │ ├── dashboard.js # Painel pessoal e visão da gestão
│ │ │ └── bmFinanceiro.js # Resumo mensal: pontos dos sócios e plantões dos plantonistas
│ │ ├── services/ # Regras compartilhadas: vagas, conflitos de horário, trocas por horas, afastamentos, usuários
│ │ ├── middleware/
│ │ │ ├── auth.js # Validação do JWT e checagem de roles
│ │ │ └── rateLimit.js # Limites de login, cadastro e e-mails
│ │ ├── routes/
│ │ ├── app.js # Configuração do Express
│ │ └── server.js # Entrypoint — sobe o servidor
│ ├── scripts/
│ │ └── seed-local.js # Dados de teste do Supabase local
│ ├── Dockerfile
│ ├── .env.example
│ └── package.json
├── Frontend/
│ ├── app/
│ │ ├── page.tsx # Página inicial (pública)
│ │ ├── login/ register/ forgot-password/ reset-password/
│ │ └── (app)/ # Área logada (com sidebar)
│ │ ├── dashboard/
│ │ ├── plantoes/ # Calendário de plantões
│ │ ├── meu-plantao/ # Semana no formato da escala
│ │ ├── fichas/ # Fichas anestésicas
│ │ ├── casos-fora/ # Casos fora
│ │ ├── perfil/ # Meu perfil (dados, senha, dias disponíveis, férias e congressos)
│ │ ├── usuarios/ # Gestão de usuários
│ │ └── bm-financeiro/ # BM Financeiro
│ ├── components/ # Modais, calendário, lista de participantes, sidebar, badges
│ ├── public/ # Logos da GAMI
│ ├── .env.example
│ └── package.json
├── supabase/
│ ├── config.toml # Supabase local
│ └── migrations/ # Schema do banco
├── docker-compose.yml
└── README.md
cp Backend/.env.example Backend/.env
PORT=3000
SUPABASE_URL=https://xxxx.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
# URL do frontend, usada no link de redefinição de senha enviado por e-mail
FRONTEND_URL=http://localhost:3001
⚠️ A
SUPABASE_SERVICE_ROLE_KEYé uma chave administrativa (ignora o RLS) — nunca exponha no frontend ou em repositórios públicos.
cp Frontend/.env.example Frontend/.env.local
NEXT_PUBLIC_API_URL=http://localhost:3000
Para testar localmente, use o Supabase local (Postgres, Auth e Storage no Docker), com dados de teste. Precisa da Supabase CLI (brew install supabase/tap/supabase).
supabase start # na raiz do repositório; sobe o Supabase local
cd Backend && npm run db:reset # zera o banco local, aplica as migrations e cria os dados de teste
Backend/.env aponta para o Supabase local (http://host.docker.internal:54321, porque o backend roda no Docker). A chave service_role local aparece no supabase status.Backend/.env.producao (fora do git). Para subir o backend contra ela: ENV_FILE=.env.producao docker-compose up.senha123: [email protected] (escritório + admin), [email protected] (técnico), [email protected] (sócia), [email protected] (plantonista) etc. A lista completa sai no fim do npm run db:reset.http://127.0.0.1:54323. E-mails (redefinição de senha): http://127.0.0.1:54324.host.docker.internal: echo "127.0.0.1 host.docker.internal" | sudo tee -a /etc/hosts.O schema fica em supabase/migrations/. A produção não aplica migrations sozinha: cada mudança de schema vira um arquivo novo em supabase/migrations/ e também é rodada manualmente no SQL Editor do Supabase de produção.
docker-compose up
A API ficará disponível em http://localhost:3000.
O Docker monta o volume
./Backend/src, então alterações no código reiniciam automaticamente via nodemon.
cd Backend
npm install
npm run dev # hot reload
npm start # produção
Sem Docker, use SUPABASE_URL=http://127.0.0.1:54321 no .env para o Supabase local.
cd Frontend
npm install
npm run dev -- -p 3001
O frontend ficará disponível em http://localhost:3001 (a porta 3000 é usada pela API).
| Role | Descrição |
|---|---|
anestesita_socio | Anestesista sócio — entra em qualquer vaga do plantão; no BM conta pontos pela vaga |
anestesita_plantonista | Anestesista plantonista — entra em qualquer vaga do plantão; no BM conta plantões por categoria (se também for sócio, conta pontos) |
tecnico | Técnico — faz parte da gestão |
escritorio | Escritório — faz parte da gestão |
is_admin, que dá acesso de gestão e só pode ser concedida ou retirada por outro administrador.escritorio, tecnico e administradores. É quem monta a escala, aprova cadastros e afastamentos e edita registros de outras pessoas.app_metadata no Supabase — só a service role key consegue alterá-las./register): qualquer cargo (sócio, plantonista, técnico ou escritório). A conta nasce bloqueada e só entra depois que a gestão aprova na tela de Usuários.Segue a escala anual do cliente: um plantão por dia, com as vagas do diurno e do noturno. A vaga (posição de 1 a 13, na ordem das linhas da escala) identifica cada lugar:
| Turno | Horário | Vagas (posição) |
|---|---|---|
| Diurno | 7h–19h | Coordenador (1), Coordenador (2), 2º a 7º (3 a 8) |
| Noturno | 19h–7h do dia seguinte | Intermediário (9), 1º (10), 1º (11), 2º (12), 3º (13) |
No sábado e no domingo (pela data do plantão: o noturno de domingo para segunda conta, o de sexta não) algumas vagas mudam:
| Turno | Vagas (posição) no fim de semana |
|---|---|
| Diurno | Coordenador (1), Coordenador (2), Manhã 7h–13h (3), 1º a 4º (4 a 7). A vaga 8 não existe. |
| Noturno | Intermediário (9), 1º a 4º (10 a 13) |
A manhã tem horário próprio: libera o médico às 13h e limita a troca por horas a 7h–13h. Os pontos de cada vaga no fim de semana estão na seção do BM Financeiro.
Regras de escala:
No modal do plantão, os participantes aparecem em lista, uma por turno, com uma linha por vaga: a vaga ("Coord.", "2º", "Interm."), a sigla, o nome e, embaixo, avisos como troca pendente, troca por horas ou férias. As ações de cada médico (trocar, remover) ficam no botão ⋯, e uma vaga livre mostra + Adicionar. Quem vira coordenador é definido mudando o médico de vaga — inclusive entre o diurno e o noturno. Mudar posições: a gestão e os médicos escalados no plantão. O modal também mostra o histórico de trocas, remoções e mudanças de vaga.
O calendário tem visões de semana (uma linha por turno) e mês, com uma cor por turno (âmbar = diurno, índigo = noturno). Cada sigla tem indicadores: anel roxo do coordenador, ponto laranja de troca pendente, "!" de afastamento aprovado, "?" de pedido pendente e a sigla de quem cobre (troca por horas ou férias). No celular, a semana mostra os dias empilhados.
No modal do plantão, o médico (sócio ou plantonista) vê Pedir esta vaga nas vagas livres, até o turno começar e se ainda não estiver naquele turno. O pedido fica pendente até a gestão aprovar ou recusar, pelo sino de notificações ou na própria vaga no modal.
A semana no formato da escala: as vagas nas linhas e os dias nas colunas, com as suas vagas destacadas. No sábado e no domingo, a célula mostra o nome da vaga quando ele muda (Manhã, 1º–4º), e a vaga 8 fica cinza. Clicar em qualquer célula de um dia abre o plantão. Para sócios, plantonistas, técnicos e escritório.
Acessado pelo menu da sigla (canto superior). Cada usuário edita nome, sigla, telefone, data de nascimento e CRM, e troca a própria senha. E-mail e funções só a gestão altera. Anestesistas também têm:
*), uma cor por médico com legenda, a lista de congressos e os dias de férias e de congresso de cada um (só períodos aprovados).Plantões que viram a noite contam pelo dia em que começam.
Registro avulso de uma anestesia, sem ligação com o plantão: data e horário (início e fim, podendo virar a noite), um ou mais anestesistas, tipo de anestesia, valor, observações e uma foto da ficha (guardada num bucket privado do Supabase Storage; o link da foto vale 1 hora).
.xlsx no modelo do faturamento (Data, Hora, Número de Atendimento … Nome Procedimento), com uma linha por anestesista. A ficha preenche só Data (dd/mm/aa), Hora (hh:mm:ss), Crm Anestesista e Anestesista; as outras colunas saem vazias, para o faturamento completar à mão antes de importar no outro sistema. A gestão exporta todas as fichas do período; o médico, só as linhas em que ele é o anestesista.Cirurgias feitas por um anestesista fora da escala (substitui o antigo Google Forms): data, anestesista (até dois por caso), se estava escalado, cirurgião, paciente (nome e CPF), cirurgia, hospital, recibo (GAMI/ADDS ou sem nota fiscal), valor e comentários. Todos os usuários logados veem; editam e excluem quem criou ou a gestão. A lista de hospitais é cadastrada pela gestão (hospital desativado some das opções, mas continua nos casos antigos). Os casos do mês também aparecem numa aba do BM Financeiro.
Tela para listar, criar e editar usuários, aprovar cadastros pendentes, ativar/desativar contas e enviar e-mail de redefinição de senha. A lista mostra o contato (e-mail e telefone) de cada usuário, e o modal do médico mostra suas férias e congressos (a gestão pode remover).
anestesita_socioPainel pessoal de cada usuário: próximo plantão (com contagem regressiva e a vaga), agenda dos próximos 7 dias, trocas aguardando o seu aceite (com Aceitar/Recusar), trocas que você pediu e o resumo do seu mês (pontos do sócio; plantões por categoria do plantonista).
Para a gestão, o dashboard também mostra a visão do hospital: quem está de plantão agora, alertas de cobertura dos próximos 7 dias por turno (turno sem médico ou diurno sem coordenador), trocas pendentes no sistema, resumo do mês comparado ao anterior, top 5 em plantões (plantonistas) e pontos (sócios) e a equipe cadastrada por role.
Resumo mensal por médico, calculado na hora a partir dos plantões (nada é gravado). O plantão não tem tipo: a separação é pelo cargo do médico.
Regras em Backend/src/services/pontuacao.js (tabela do cliente de 19/10/2026), iguais para todos os meses.
Tem seletor de mês, busca por médico, aba de casos fora e exportação para Excel. Acesso: só administradores (flag is_admin).
A API usa JWT via Supabase Auth. Após o login, inclua o token nas requisições protegidas:
Authorization: Bearer <access_token>
"Gestão" nas tabelas abaixo = escritorio, tecnico ou administrador.
| Método | Rota | Descrição |
|---|---|---|
GET | /health | Status da API e do banco (usado pelo monitor que mantém o Render acordado) |
POST | /auth/login | Login — retorna { token, refresh_token, expires_at } |
POST | /auth/refresh | Renova a sessão (refresh_token) |
POST | /auth/register | Cadastro público — a conta fica pendente até a gestão aprovar |
POST | /auth/forgot-password | Envia e-mail de redefinição de senha |
POST | /auth/reset-password | Define a nova senha (access_token + password) |
Autenticação
| Método | Rota | Descrição |
|---|---|---|
GET | /auth/me | Dados do usuário logado (id, email, nome, sigla, roles, is_admin, CRM, telefone, data de nascimento, dias disponíveis) |
PATCH | /auth/me | Edita o próprio cadastro (nome, sigla, telefone, data de nascimento, CRM, dias disponíveis) |
POST | /auth/me/senha | Troca a própria senha (senha_atual + nova_senha, mínimo 8). Encerra as sessões da conta e devolve uma nova (token, refresh_token, expires_at) |
Usuários
| Método | Rota | Descrição |
|---|---|---|
GET | /users | Busca de médicos (?search=, ?role=). Com ?data= marca quem está de férias/congresso; com ?horaInicio=&horaFim= também tira quem tem conflito de horário |
GET | /users/gestao | Lista para a gestão de usuários (gestão e sócios) |
POST | /users | Cria usuário (gestão) |
PATCH | /users/:id | Edita nome, sigla, roles, flag admin e CRM (gestão) |
PATCH | /users/:id/ativo | Ativa/desativa usuário — também aprova cadastros pendentes (gestão) |
POST | /users/:id/reset-senha | Envia e-mail de redefinição de senha (gestão) |
Plantões
| Método | Rota | Descrição |
|---|---|---|
GET | /plantoes | Lista plantões (?inicio=, ?fim=) |
GET | /plantoes/:id | Detalhe de um plantão |
POST | /plantoes | Cria o plantão do dia (titulo, data, fila: [{ usuario_id, posicao }]); 409 se o dia já tem plantão (gestão) |
PATCH | /plantoes/:id | Edita título, descrição e dia (gestão) |
POST | /plantoes/:id/usuarios | Preenche vagas vazias (fila: [{ usuario_id, posicao }]) (gestão) |
DELETE | /plantoes/:id/vagas/:posicao | Esvazia a vaga (registra no histórico e cancela a troca pendente dela) (gestão) |
PATCH | /plantoes/:id/posicao | Move o médico da vaga posicao para nova_posicao (troca com quem estiver nela); define o coordenador (gestão e médicos) |
GET | /plantoes/:id/remocoes | Histórico de remoções do plantão |
GET | /plantoes/:id/mudancas-posicao | Histórico de mudanças de vaga |
GET | /plantoes/:id/trocas | Histórico de trocas do plantão |
POST | /plantoes/:id/trocas | Solicita troca da vaga (posicao, usuario_entrada e, na troca por horas, hora_inicio/hora_fim) |
PATCH | /plantoes/:id/trocas/:trocaId/cancelar | Cancela um pedido pendente (quem pediu ou a gestão) ou desfaz uma troca por horas aceita (gestão) |
GET | /plantoes/:id/pedidos-vaga | Pedidos de vaga livre do plantão (todos os status) |
POST |
Férias e congressos
| Método | Rota | Descrição |
|---|---|---|
GET | /afastamentos | Todos os médicos (gestão). Sem período, os atuais e futuros; ?inicio=&fim= para outro intervalo; ?tipo= e ?status= (padrão: aprovados e pendentes) |
GET | /afastamentos/me | Períodos atuais e futuros do usuário logado (inclui os recusados) |
POST | /afastamentos | Pede férias ou congresso (só anestesistas) — fica pendente até a gestão aprovar |
DELETE | /afastamentos/:id | Remove um período (o próprio médico, enquanto não for aprovado; a gestão, qualquer um) |
GET | /afastamentos/pendentes | Pedidos aguardando aprovação (gestão) |
POST | /afastamentos/usuario/:usuarioId | A gestão cadastra férias ou congresso de um médico — já aprovado, e pode ser no passado |
GET | /afastamentos/usuario/:usuarioId | Períodos atuais e futuros de um médico (gestão) |
PATCH | /afastamentos/:id/aprovar | Aprova o pedido (gestão) |
PATCH | /afastamentos/:id/recusar | Recusa o pedido (gestão) |
PATCH | /afastamentos/:id/tipo-congresso | Define o tipo do congresso (palestrante/congressista): o próprio médico, se estiver sem tipo ou pendente; a gestão, sempre |
Fichas anestésicas
| Método | Rota | Descrição |
|---|---|---|
GET | /fichas | Lista as fichas (gestão: todas; médico: as dele) |
GET | /fichas/exportar?inicio=&fim= | Linhas da planilha do faturamento no período (até um ano), uma por anestesista |
GET | /fichas/:id | Detalhe, com o link temporário da foto (404 para quem não pode ver a ficha) |
POST | /fichas | Cria a ficha (foto em fotos_novas, como data URL) (médicos e gestão) |
PATCH | /fichas/:id | Edita (quem criou ou a gestão) |
DELETE | /fichas/:id | Exclui, com a foto (quem criou ou a gestão) |
Casos fora e hospitais
| Método | Rota | Descrição |
|---|---|---|
GET | /casos-fora | Lista os casos fora |
POST | /casos-fora | Registra um caso (médicos e gestão) |
PATCH | /casos-fora/:id | Edita (quem criou ou a gestão) |
DELETE | /casos-fora/:id | Exclui (quem criou ou a gestão) |
GET | /hospitais | Lista os hospitais |
POST | /hospitais | Cadastra um hospital (gestão) |
PATCH | /hospitais/:id | Renomeia ou ativa/desativa (gestão) |
Dashboard
| Método | Rota | Descrição |
|---|---|---|
GET | /dashboard | Próximo plantão, agenda de 7 dias, trocas pendentes e resumo do mês do usuário logado |
GET | /dashboard/gestao | Visão do hospital (gestão): plantões em andamento, alertas de cobertura, trocas pendentes, resumo/top 5 do mês e equipe |
BM Financeiro
| Método | Rota | Descrição |
|---|---|---|
GET | /bm-financeiro?mes=AAAA-MM | Plantões por categoria por plantonista, pontos por sócio e os casos fora do mês (administradores e técnicos) |
POST /auth/register
{
"email": "[email protected]",
"password": "senha123",
"nome": "Dr. Fulano",
"sigla": "FU",
"roles": ["anestesita_plantonista"],
"crm": "123456",
"crm_uf": "SP"
}
crmecrm_ufsão obrigatórios só para anestesistas. A conta fica pendente até a gestão aprovar.
Resposta:
{
"id": "…",
"pendente": true
}
POST /auth/login
{
"email": "[email protected]",
"password": "senha123"
}
Resposta:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "…",
"expires_at": 1760000000
}
/plantoes/:id/pedidos-vaga |
Pede uma vaga livre (posicao) (médicos) |
GET | /plantoes/pedidos-vaga/pendentes | Pedidos de vaga aguardando aprovação, de todos os plantões (gestão) |
PATCH | /plantoes/pedidos-vaga/:pedidoId/aprovar | Aprova: o médico entra na vaga e os outros pedidos dela são recusados (gestão) |
PATCH | /plantoes/pedidos-vaga/:pedidoId/recusar | Recusa o pedido (gestão) |
PATCH | /plantoes/pedidos-vaga/:pedidoId/cancelar | Cancela um pedido pendente (quem pediu ou a gestão) |
GET | /plantoes/trocas/pendentes | Trocas aguardando o aceite do usuário logado |
PATCH | /plantoes/trocas/:trocaId/aceitar | Aceita a troca |
PATCH | /plantoes/trocas/:trocaId/recusar | Recusa a troca |