Skip to main content

Snippets pessoais — API

Textos pré-definidos ("atalhos") privados ao próprio usuário, cada um identificado por um shortcut curto e único entre os snippets ativos do dono. Usados para inserir trechos de texto recorrentes rapidamente (o conteúdo em si é de uso do frontend — este levantamento cobriu apenas o contrato da API, sem confirmar onde o snippet é consumido na interface).

Funcionamento​

  1. Cada snippet pertence a exatamente um ownerUserId — sempre o subject do access token; não há rota para operar sobre snippet de outro usuário.
  2. Criar: exige Idempotency-Key; reenviar a mesma chave com o mesmo payload devolve o snippet já criado. shortcut deve ser único entre os snippets ativos do mesmo dono (case-insensitive) — criar um segundo com o mesmo atalho é conflito.
  3. Conteúdo é sempre sanitizado antes de salvar: em PLAIN_TEXT, qualquer marcação HTML é rejeitada; em RICH_TEXT, tags e atributos perigosos (script, iframe, manipuladores on*, protocolos javascript:/data: etc.) são rejeitados, e só uma lista fixa de tags simples (p, br, strong, em, u, s, ul, ol, li, blockquote) sobrevive à sanitização — atributos são sempre removidos.
  4. Substituir (PUT) e retirar (DELETE) usam controle de versão otimista: o snippet só é modificado se a versão informada bate com a versão atual; a cada substituição a versão incrementa.
  5. Retirar é soft-delete (deletedAt); um snippet retirado não aparece mais em list/find.
  6. Um token OAuth delegado por serviço (binding !== null) nunca acessa este recurso — só sessão de usuário final.

Endpoints​

MétodoRotaDescrição
POST/v1/me/snippetsCria um snippet pessoal
GET/v1/me/snippetsLista os snippets ativos do dono, paginado
GET/v1/me/snippets/:snippetIdLê um snippet específico
PUT/v1/me/snippets/:snippetIdSubstitui um snippet (versão obrigatória)
DELETE/v1/me/snippets/:snippetIdRetira (soft-delete) um snippet

Versão: v1

Swagger: Identity — Personal snippets · Rota (Dev): http://localhost:3000/v1/me/snippets

Permissões​

Rotas privadas ao próprio usuário: exigem apenas um access token de usuário final (não delegado). Não há permissão nomeada — o escopo é sempre o subject do token.

RotaGuardsAcesso
Todas deste grupoIdentityOAuthAccessTokenGuard, IdentitySnippetUserTokenGuardusuário autenticado, apenas sobre os próprios snippets; token delegado por serviço é recusado

Headers​

HeaderObrigatórioDescrição
AuthorizationSimBearer <access_token> de usuário final
Idempotency-KeySim (POST)única por dono e payload
If-MatchSim (DELETE)versão atual do snippet

Path parameters​

NomeTipoObrigatórioDescrição
snippetIduuidSim (exceto POST/GET lista)Identificador do snippet

Query parameters (GET lista)​

NomeTipoObrigatórioDefaultDescrição
pageint ≥ 1Não1página
limitint (1–200)Não100tamanho da página

Body​

POST / PUT — IdentitySnippetMaintainRequest:

json
{
"shortcut": "assinatura-padrao",
"title": "Assinatura padrão",
"contentFormat": "PLAIN_TEXT",
"content": "Atenciosamente,\nDra. Ana Silva",
"version": 2
}
CampoTipoObrigatórioValidação
shortcutstringSim1–80 caracteres; apenas letras/números/./_/-
titlestringSim1–200 caracteres
contentFormatPLAIN_TEXT | RICH_TEXTSimenum
contentstringSim1–50.000 caracteres; sanitizado conforme contentFormat
versionint ≥ 1Sim só no PUTdeve bater com a versão atual do snippet

Response​

201/200 — IdentitySnippetResponse:

json
{
"data": {
"id": "...", "shortcut": "assinatura-padrao", "title": "Assinatura padrão",
"contentFormat": "PLAIN_TEXT", "content": "Atenciosamente,\nDra. Ana Silva",
"version": 1, "createdAt": "2026-08-26T12:00:00.000Z", "updatedAt": "2026-08-26T12:00:00.000Z"
}
}

200 — lista: envelope paginado (data[] + meta.page/limit/total/totalPages).

204 — DELETE: sem corpo.

Erros​

Classe de erroerrorCodeStatusQuando ocorre
— (guard)DELEGATED_USER_REQUIRED401token delegado por serviço, sem sessão de usuário final
ValidationErrorIDEMPOTENCY_KEY_REQUIRED400header ausente no POST
ValidationErrorIDENTITY_SNIPPET_INVALID_TITLE400título vazio ou maior que 200 caracteres
IdentitySnippetInvalidShortcutErrorIDENTITY_SNIPPET_INVALID_SHORTCUT422shortcut fora do padrão permitido
IdentitySnippetUnsafeContentErrorIDENTITY_SNIPPET_UNSAFE_CONTENT422conteúdo com marcação não permitida, protocolo perigoso, ou tamanho/controle inválido
IdentitySnippetIdempotencyConflictErrorIDENTITY_SNIPPET_IDEMPOTENCY_CONFLICT409mesma Idempotency-Key com payload diferente
IdentitySnippetDuplicateShortcutErrorIDENTITY_SNIPPET_DUPLICATE_SHORTCUT409shortcut já usado por outro snippet ativo do mesmo dono
IdentitySnippetNotFoundErrorIDENTITY_SNIPPET_NOT_FOUND404snippet inexistente, de outro dono, ou já retirado
IdentitySnippetVersionConflictErrorIDENTITY_SNIPPET_VERSION_CONFLICT409version/If-Match não bate com a versão atual
ValidationErrorVERSION_REQUIRED400PUT sem version, ou DELETE sem If-Match válido
—IDENTITY_INVALID_OAUTH_ACCESS_TOKEN401token ausente, inválido, expirado ou revogado

Regras de negócio​

IDRegraComportamento esperado
RN-01Snippet é sempre privado ao dononão existe rota para ler/editar snippet de outro usuário, nem para administrador
RN-02shortcut é único apenas entre ativos do mesmo donoum shortcut pode ser reaproveitado depois que o snippet anterior é retirado
RN-03Sanitização é obrigatória e não configurávelPLAIN_TEXT nunca aceita marcação; formato rico só mantém uma lista fixa de tags, sem atributos
RN-04Retirar é soft-delete versionadoretirar duas vezes com a mesma versão esperada (já incrementada) é tratado como já concluído; com versão desatualizada é conflito
RN-05Token delegado por serviço nunca acessa snippetsmesmo com identityAccessToken válido, binding !== null é recusado

Compliance​

Órgão / normaExigênciaComo a rota atende
LGPDisolamento por donotoda leitura/escrita é filtrada por ownerUserId = subject do token
HIPAA (condicional)não expor conteúdo sensível em auditoriaeventos de auditoria gravam metadados (tamanho, formato, versão), não o conteúdo do snippet

Variáveis de ambiente​

Nenhuma específica a esta rota.

Requisitos não funcionais​

RequisitoDefinição
IdempotênciaSim, na criação, por Idempotency-Key
ConcorrênciaOtimista, por version/If-Match
PaginaçãoSim — page/limit, máximo 200 por página
AuditoriaSim — identity.snippet.created.v1, .updated.v1, .deleted.v1 (sem o conteúdo em claro)

Relacionado​

  • 🖥️ Tela: A confirmar — responsável: time de frontend; data: 24/09/2026.
  • 📂 Módulo: Usuário