Tenant

Endpoints sob /api/tenant/*. Misturam leitura (qualquer usuário autenticado do tenant) e escrita (apenas tenant admins). Escopo: todos os endpoints são automaticamente filtrados pelo tenant_id do usuário autenticado via trait BelongsToTenant. Super admins veem tudo; tenant admins veem o próprio tenant; usuários regulares veem dados restritos à sua unidade. Endpoints de presets de laudo (/api/tenant/report-presets) estão documentados em Laudos e Presets.

Unidades

GET /api/tenant/units

Lista as unidades (filiais) do tenant — usado para dropdowns e seleções. Auth: auth:api

Query params

tenant_id
uuid
Filtra por tenant específico (útil para super admins).
Busca case-insensitive em name e slug. Máximo 255 caracteres.

Response 200

Paginação Laravel (50 itens por página):
{
  "data": [
    {
      "id": "uuid",
      "tenant_id": "uuid",
      "name": "string",
      "slug": "string | null",
      "is_active": true,
      "created_at": "iso8601",
      "updated_at": "iso8601"
    }
  ],
  "current_page": 1,
  "per_page": 50,
  "total": 4
}
Ordenação: name ASC.

Templates de Laudo

Templates definem o layout A4 do PDF do laudo: regiões (header/footer), slots (logo, nome da unidade, assinatura), tipografia e papel timbrado opcional. Apenas um template pode ser ativo por unidade — ativar um desativa automaticamente os outros. Schema do layout: estrutura JSONB conforme ReportTemplateLayoutV1 — referência em frontend/types/report-template-layout.ts. Schema do assets: estrutura JSONB para papel timbrado — { background: { data_url, opacity } } conforme TemplateAssets no mesmo arquivo.

GET /api/tenant/templates

Lista paginada de templates. Auth: auth:api Visibilidade:
  • Super admin / tenant admin: todos os templates do tenant
  • Usuário regular (doutor): apenas templates ativos (is_active = true) da própria unidade ou globais (unit_id = null)

Query params

unit_id
uuid
Filtra por unidade.
search
string
Busca ILIKE em name.

Response 200

Paginação (50 itens por página):
{
  "data": [
    {
      "id": "uuid",
      "tenant_id": "uuid",
      "unit_id": "uuid | null",
      "name": "string",
      "content": "string | null",
      "schema_version": 1,
      "layout": { "...": "ReportTemplateLayoutV1 (regions, slots, typography)" },
      "page": { "...": "config de página" },
      "assets": { "background": { "data_url": "base64", "opacity": 1 } },
      "is_active": true,
      "unit_name": "string | null",
      "created_at": "iso8601",
      "updated_at": "iso8601"
    }
  ],
  "current_page": 1,
  "per_page": 50,
  "total": 8
}
unit_name é computado no controller (eager load do relacionamento).

GET /api/tenant/templates/

Detalhe de um template. Auth: auth:api

Response 200

Mesmo shape do item do index.

Erros

StatusSituação
404Template não existe ou pertence a outro tenant

GET /api/tenant/my-template

Retorna o template ativo da unidade do usuário logado. Usado pelo painel de laudos para aplicar automaticamente o layout ao gerar o PDF. Auth: auth:api

Response 200

Um objeto template (mesmo shape do show) ou null se a unidade do usuário não tiver template ativo:
null
Se o usuário não tiver unit_id, também retorna null.

POST /api/tenant/templates

Cria um template. Auth: auth:api + tenant_admin

Request body

name
string
required
Nome do template. Máximo 255 caracteres.
unit_id
uuid
required
Unidade à qual o template pertence. Deve pertencer ao tenant do usuário.
content
string
Campo livre, opcional.
schema_version
integer
default:"1"
Versão do schema do layout. Atualmente só 1.
layout
object
Objeto ReportTemplateLayoutV1. Ver frontend/types/report-template-layout.ts.
page
object
Configurações de página.
assets
object
TemplateAssets. Tipicamente { background: { data_url: "data:image/png;base64,...", opacity: 1 } }.
is_active
boolean
default:"true"
Se true, desativa automaticamente outros templates da mesma unidade.

Response 201

Objeto template criado.

Erros

StatusSituaçãoBody
403Usuário não é tenant_admin
422unit_id não pertence ao tenant{"errors": {"unit_id": ["A unidade informada não pertence ao seu tenant."]}}

PATCH /api/tenant/templates/

Atualiza um template. Todos os campos opcionais. Auth: auth:api + tenant_admin

Request body

Mesmos campos de POST, todos com validação sometimes / nullable.

Response 200

Template atualizado.

Erros

StatusSituação
403Usuário não é tenant_admin
404Template não existe ou fora do tenant
422Validação

Notas

  • Mudar is_active para true desativa os demais templates da mesma unidade

DELETE /api/tenant/templates/

Remove um template (soft delete — campo deleted_at preenchido, registro permanece no banco). Auth: auth:api + tenant_admin

Response 204

Sem body.

Erros

StatusSituação
403Usuário não é tenant_admin
404Template não existe ou fora do tenant

Configurações do Tenant

GET /api/tenant/settings

Retorna nome e logo da clínica. Auth: auth:api

Response 200

{
  "id": "uuid",
  "name": "string",
  "logo": "data:image/jpeg;base64,... | null"
}

PATCH /api/tenant/settings

Atualiza configurações (atualmente só logo). Auth: auth:api + tenant_admin

Request body

Data URL base64 no formato data:image/jpeg;base64,... ou data:image/png;base64,.... Pode ser null para remover o logo.
Validação por regex /^data:image\/(jpeg|png);base64,/ — outros formatos são rejeitados para bloquear SVG com scripts e afins.

Response 200

{
  "id": "uuid",
  "name": "string",
  "logo": "data:image/... | null"
}

Erros

StatusSituação
403Usuário não é tenant_admin
422Logo não está em formato data URL permitido