NoteBugsDocs

Referência da API

Armazenamento e arquivos

Onde os bytes são gravados, e por onde eles voltam.

As duas primeiras exigem administrador e são recusadas no modo demonstração. /api/files/[name] é a porta de leitura, e ela serve tanto o anexo quanto o avatar.

GET/api/storage
Papel: Administrador

Onde os anexos e o .zip do backup são gravados.

driver é o que foi ESCOLHIDO; effectiveDriver e effectiveBackupDriver são onde as coisas caem de fato. Eles divergem numa configuração incompleta, ou quando o escopo manda só uma parte para o bucket.

Requisição

curl -s http://localhost:3000/api/storage \
  -H "Authorization: Bearer $TOKEN"

Resposta200

{
  "driver": "S3",
  "effectiveDriver": "LOCAL",
  "effectiveBackupDriver": "S3",
  "endpoint": "https://br-se1.exemplo-objects.com",
  "region": "br-se1",
  "bucket": "notebugs",
  "accessKeyId": "AKIAEXEMPLO000000000",
  "scope": "BACKUPS",
  "prefix": "uploads/",
  "prefixBackup": "backups/",
  "forcePathStyle": true,
  "hasSecret": true,
  "ready": true,
  "locked": true,
  "envFields": []
}

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
403A conta não é administradora. Este prefixo exige ADMIN em qualquer método, inclusive na leitura.

O secretAccessKey nunca sai: a resposta traz hasSecret, que diz que existe um segredo sem dizer qual.

PATCH/api/storage
Papel: Administrador

Configura o backend de armazenamento: disco local ou bucket S3-like.

Corpo da requisição

CampoTipoDescrição
driverenumLOCAL · S3
endpointstringVazio significa AWS regional. Aceita http://minio:9000 sem TLS, que é o caso mais comum na rede interna do Compose.Ausente: vazio = AWS regional
regionstring
bucketstring
accessKeyIdstring
secretAccessKeystringEntra e nunca sai. String vazia APAGA o segredo; ausente não mexe.
scopeenumO que vai para o bucket: tudo, só os anexos ou só os backups.ALL · IMAGES · BACKUPS
prefixstring
prefixBackupstring
forcePathStylebooleanNecessário na maioria dos serviços S3-like que não são a AWS.
lockedbooleanBloqueia a configuração contra mudança acidental. Sozinho no corpo, é a única escrita aceita enquanto ele está ligado.

Requisição

curl -s -X PATCH http://localhost:3000/api/storage \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "driver": "S3",
    "endpoint": "https://br-se1.exemplo-objects.com",
    "region": "br-se1",
    "bucket": "notebugs",
    "accessKeyId": "AKIAEXEMPLO000000000",
    "secretAccessKey": "o segredo, que entra e nunca sai",
    "scope": "BACKUPS",
    "prefixBackup": "backups/",
    "forcePathStyle": true
  }'

Resposta200

{
  "driver": "S3",
  "effectiveDriver": "LOCAL",
  "effectiveBackupDriver": "S3",
  "endpoint": "https://br-se1.exemplo-objects.com",
  "region": "br-se1",
  "bucket": "notebugs",
  "accessKeyId": "AKIAEXEMPLO000000000",
  "scope": "BACKUPS",
  "prefix": "uploads/",
  "prefixBackup": "backups/",
  "forcePathStyle": true,
  "hasSecret": true,
  "ready": true,
  "locked": true,
  "envFields": []
}

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
403A conta não é administradora. Este prefixo exige ADMIN em qualquer método, inclusive na leitura.
403A instalação está em modo demonstração, e ali backup, armazenamento e contas ficam fora do ar.
409A configuração está bloqueada contra alterações. Mande { "locked": false } sozinho antes de editar o resto.
422Falta o que o backend escolhido precisa: S3 sem bucket, por exemplo. A checagem acontece depois de compor com o que o container definiu.
POST/api/storage/test
Papel: Administrador

Grava, lê e apaga um arquivo de teste usando a configuração DO FORMULÁRIO.

Testa o que está no formulário, e não o que já está salvo: dá para conferir a credencial antes de gravá-la. Um arquivo de teste por prefixo em uso.

Corpo da requisição

CampoTipoDescrição
driverenumLOCAL · S3
endpointstring
regionstring
bucketstring
accessKeyIdstring
secretAccessKeystring
scopeenumALL · IMAGES · BACKUPS
prefixstring
prefixBackupstring
forcePathStyleboolean

Requisição

# corpo vazio testa o que está valendo agora
curl -s -X POST http://localhost:3000/api/storage/test \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "driver": "LOCAL", "scope": "ALL" }'

Resposta200

{
  "driver": "LOCAL",
  "detail": "Volume em disco e volume em disco responderam à gravação, à leitura e à remoção.",
  "label": "disco local"
}

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
403A conta não é administradora. Este prefixo exige ADMIN em qualquer método, inclusive na leitura.
403A instalação está em modo demonstração, e ali backup, armazenamento e contas ficam fora do ar.
502O bucket recusou ou não respondeu. O 502 diz que a falha foi do serviço atrás desta aplicação; a mensagem traz o que o S3 devolveu.

Não grava configuração nenhuma. Corpo vazio testa o que está valendo agora.

GET/api/files/[name]
Papel: Leitor

Serve um arquivo: anexo do card, imagem de comentário ou avatar.

Sempre inline, com Content-Security-Policy: sandbox e nosniff: um HTML anexado não roda no domínio da aplicação.

Parâmetros de rota

CampoTipoDescrição
nameobrigatórionome gerado pelo servidorO nome GERADO pelo servidor (storedName), que veio no payload do anexo. O formato desse nome é a barreira contra path traversal.

Requisição

curl -s -o print.png \
  http://localhost:3000/api/files/18ab694d-48ed-4b56-bd2b-3a324fec55de.png \
  -H "Authorization: Bearer $TOKEN"

Resposta200

content-type: image/png
content-length: 25381
content-disposition: inline; filename*=UTF-8''print.png
content-security-policy: default-src 'none'; sandbox
x-content-type-options: nosniff
cache-control: public, max-age=31536000, immutable

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
404O recurso não existe, ou já foi apagado.
422O nome pedido não tem o formato dos nomes gerados pelo servidor. É a barreira contra path traversal, e vale para qualquer backend.

Resolve o nome em Attachment e no avatarName da conta, porque o avatar não tem linha de anexo. Os bytes vêm do disco ou do bucket, conforme o destino em vigor.