Appearance
Módulo de Timesheet & Time Tracking
O módulo de Timesheet é um sistema de controle de horas e ponto headless completo. Ele permite que um workspace opere registro de ponto (com geolocalização), jornadas de trabalho, ausências, fluxo de aprovação de dias e períodos, apontamento por projeto com valor-hora e um kanban integrado — tudo isolado por instância.
Cada workspace pode ter várias instâncias do Timesheet (uma por empresa ou unidade), com configurações, profissionais, clientes, projetos e apontamentos totalmente independentes.
Por que utilizar este módulo?
- Isolamento Total: Os dados são isolados por instância do Timesheet (
timesheet_idé o eixo de isolamento) — um profissional de uma instância não enxerga dados de outra. - Dois Públicos, Duas APIs: O dono da conta provisiona e configura a instância; gestores e profissionais operam o ponto e os apontamentos com autenticação própria do módulo.
- Regras na Aplicação: Toda a inteligência (consolidação de dias, cálculo de valor-hora, trava de períodos fechados, máquinas de estado) vive na aplicação — o banco guarda apenas os dados, sem functions, triggers ou views.
- Auditoria Nativa: Batidas de ponto nunca sofrem UPDATE; correções de apontamento geram revisões com antes/depois, autor e motivo.
As Duas Áreas do Módulo
| Área | Prefixo das rotas | Público | Guard |
|---|---|---|---|
| Gestão da instância | /user/timesheets | Dono da conta (módulo user) | user |
| Operação | /v1/timesheet | Gestores e profissionais | timesheetUser |
- A gestão da instância cria e configura as instâncias (fuso, moeda, geolocalização obrigatória, dia de virada do período) e segue a autenticação da plataforma.
- A área de operação concentra todo o restante: equipe, estrutura organizacional, jornadas, ponto, apontamentos, períodos, métricas, chamados internos, kanban e exportações.
Autenticação e Contexto
Identificação da Instância
Todas as requisições para os endpoints /v1/timesheet/** devem incluir o identificador da instância:
| Header | Tipo | Obrigatório | Descrição |
|---|---|---|---|
X-Timesheet-Id | UUID | Sim | O tokenHeader da instância, obtido no painel administrativo do workspace. |
Como funciona o X-Timesheet-Id
O middleware resolve a instância pelo tokenHeader e valida se o domínio (ou IP) de origem está na lista de domínios autorizados do workspace, conforme a configuração allowBy (domain ou ip) de cada domínio vinculado. Requisições sem o header, com instância inexistente ou com origem não autorizada recebem 401 Unauthorized. Instâncias inativas (ou cujo workspace está inativo) recebem 503 Service Unavailable.
bash
curl -X GET "https://api.us.basis.tavares.in/v1/timesheet/me/days" \
-H "X-Timesheet-Id: 123e4567-e89b-12d3-a456-426614174000" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Tokens de Acesso
O login da operação é feito em POST /v1/timesheet/users/login com email + password do profissional e retorna um token Bearer com validade de 30 dias. O logout invalida o token imediatamente.
| Header | Valor | Descrição |
|---|---|---|
Authorization | Bearer <token> | Token obtido no login do profissional (guard timesheetUser). |
Profissionais sem senha cadastrada (quem só bate ponto num tablet, por exemplo) não conseguem autenticar — o cadastro de email e password é opcional.
Controle de Acesso (Gestor vs Profissional)
O módulo tem um RBAC simples, baseado na flag isManager do profissional:
| Papel | Escopo |
|---|---|
Gestor (isManager: true) | Acesso total à instância: gerencia equipe, estrutura, jornadas, tarifas, clientes, projetos, feriados; aprova dias, ausências e períodos; enxerga dados de todos os profissionais. |
Profissional (isManager: false) | Bate o próprio ponto, cria os próprios apontamentos e ausências, consulta apenas os próprios dias, períodos, chamados e exportações (endpoints /me/** ou escopo automático). |
Regras adicionais:
- Ações restritas a gestor falham com
403 FORBIDDENpara profissionais. - Profissionais que tentam acessar recursos de terceiros recebem
404 Not Found(o recurso é filtrado pelo próprio ID). - O kanban tem um RBAC próprio por quadro (
owner/editor/viewer), detalhado em Kanban.
Billing e Limites de Plano
Todas as rotas do módulo passam por limite de plano (usageLimit) e contabilização de uso horário (workspaceHourlyUsage). Quando o plano não permite a operação, a API responde 402 Payment Required com um dos seguintes códigos:
| Code | Significado |
|---|---|
PENDING_INVOICES | Existem faturas pendentes no workspace. |
PLAN_REQUIRED | O workspace não possui um plano ativo para o módulo. |
USAGE_LIMIT_EXCEEDED | O limite de uso do plano foi atingido. |
Convenções da API
- Paginação: parâmetros
page/perPage(máx. 100). Os endpoints/v1/timesheet/**respondem no formato{ "meta": { "currentPage", "perPage" }, "data": [...] }; a área do dono (/user/timesheets) usa o paginador completo da plataforma, comtotal,lastPage,firstPagee URLs de navegação nometa. - Listas para dropdown: endpoints
GET .../listretornam[{ "value", "label" }], comsearchopcional. - Soft delete: registros removidos não aparecem em nenhuma consulta.
- Erros de validação:
422 Unprocessable Entitycomerrors: [{ "message", "rule", "field" }](mensagens em pt/en via i18n). - Datas: sempre em ISO 8601; filtros de período e campos de dia usam
YYYY-MM-DD; instantes (startedAt,punchedAt) usam ISO 8601 completo. Horários de jornada (startsAt/endsAt) são enviados comoHH:mme retornados comoHH:mm:ss. - Durações e valores: tempos são sempre em minutos inteiros (
expectedMinutes,workedMinutes...). Campos decimais — valores monetários (hourlyCost,billingAmount...), coordenadas e posições do kanban — são serializados como string na resposta (ex.:"billingRate": "160.0000","position": "1000.0000000000"); métricas calculadas (workedHours,totalBillable...) vêm como número. - IDs: retornados como números, sem assumir tamanho (as tabelas usam
bigint). - Rate limit: 3000 req/min para o módulo (global); as rotas de gestão da instância (
/user/timesheets) seguem o throttle do módulouser(100 req/min).
Códigos de Erro de Negócio
Erros de regra de negócio retornam status 4xx com um code identificador no corpo da resposta. Os principais:
| Code | Status | Significado |
|---|---|---|
FORBIDDEN | 403 | Profissional sem permissão de gestor para a ação. |
OPEN_ENTRY_EXISTS | 422 | Já existe um apontamento em aberto para o profissional. |
NO_OPEN_ENTRY | 422 | Tentativa de bater saída sem apontamento aberto. |
MAX_INTERVALS_REACHED | 422 | Limite diário de intervalos (maxIntervalsPerDay) atingido. |
INVALID_PUNCH_INTERVAL | 422 | Saída anterior à entrada ou registro com mais de 24h. |
GEOLOCATION_REQUIRED | 422 | A instância exige geolocalização e a batida veio sem coordenadas. |
OUTSIDE_GEOFENCE | 422 | Batida fora do raio de qualquer local autorizado. |
ENTRY_OVERLAP | 422 | O apontamento se sobrepõe a outro existente. |
MANUAL_ENTRY_NOT_ALLOWED | 422 | A instância não permite apontamentos manuais (isAllowsManualEntry: false). |
DAY_LOCKED | 422 | O dia não está em um status editável (aprovado/bloqueado; para profissional, qualquer status diferente de open). |
PERIOD_CLOSED | 422 | A data pertence a um período já fechado. |
PERIOD_OVERLAP | 422 | Já existe um período sobreposto para o profissional. |
RATE_OVERLAP | 422 | Vigência de tarifa sobreposta para o mesmo profissional. |
SCHEDULE_OVERLAP | 422 | Vigência de jornada sobreposta para o mesmo profissional. |
INVALID_STAGE_MOVE | 422 | Transição de status inválida (dia, período, ausência ou chamado). |
WIP_LIMIT_REACHED | 422 | Limite de WIP da coluna do kanban atingido. |
COLUMN_HAS_CARDS | 422 | A coluna possui cards e não pode ser removida. |
LAST_OWNER | 422 | O quadro precisa ter ao menos um proprietário. |
NOT_BOARD_MEMBER | 403 | Profissional não é membro do quadro privado. |
EXPORT_EXPIRED | 422 | O arquivo da exportação expirou (24h após a geração). |