Documentação / AWS S3 — uploads de mídia de templates (imagem, vídeo, PDF)

AWS S3 — uploads de mídia de templates (imagem, vídeo, PDF)

Entrar

AWS S3 — uploads de mídia de templates (imagem, vídeo, PDF)

O app envia arquivos pelo backend usando @aws-sdk/client-s3 (PutObject). Os objetos são gravados com prefixo:

public/tenants/<tenantId>/templates/<timestamp>-<random>.<ext>

Endpoints (fullstack)

| Rota | MIME | Tamanho máximo | Extensão | |------|------|----------------|----------| | POST /api/internal/uploads/template-image | image/png, image/jpeg, image/webp, image/gif | 5 MB | .png, .jpg, .webp, .gif | | POST /api/internal/uploads/template-video | video/mp4 | 16 MB | .mp4 | | POST /api/internal/uploads/template-document | application/pdf | 10 MB | .pdf |

Resposta típica: { "url": "...", "key": "public/tenants/..." }.

O JSON do template (body) pode incluir mediaUrl, mediaType ("image" | "video" | "document") e, para PDF, fileName opcional. Templates antigos só com mediaUrl continuam tratados como imagem (inferência por extensão quando aplicável).

Variáveis de ambiente (fullstack)

| Variável | Obrigatória | Descrição | |----------|-------------|-----------| | AWS_REGION | Não | Padrão: us-east-1 | | AWS_S3_BUCKET | Não | Padrão: pilot-status | | AWS_ACCESS_KEY_ID | Sim* | Credencial IAM | | AWS_SECRET_ACCESS_KEY | Sim* | Credencial IAM | | AWS_S3_PUBLIC_BASE_URL | Não | Se definida, a API retorna URLs com esse prefixo em vez do host virtual do S3 |

* Em produção na AWS (ECS/EC2/Lambda), prefira IAM role em vez de access key; o SDK usa a cadeia padrão de credenciais.

Docker Compose (dev)

O docker-compose.dev.yml repassa AWS_REGION, AWS_S3_BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY e AWS_S3_PUBLIC_BASE_URL do arquivo usado em --env-file (ex.: npm run dev:docker:compose usa .env.development). Defina as credenciais nesse arquivo e recrie o container (docker compose ... up -d --force-recreate web-fullstack-dev) para aplicar.

Passos na AWS

1) Bucket

  • Região: us-east-1 (alinhado ao exemplo pilot-status.s3.us-east-1.amazonaws.com).
  • Nome sugerido: pilot-status (ou o valor de AWS_S3_BUCKET).

2) IAM — permissão mínima de escrita

Crie um usuário ou role (ex.: pilot-status-app-s3-uploader) com policy inline ou gerenciada contendo apenas:

  • s3:PutObject em arn:aws:s3:::pilot-status/public/tenants/* (ajuste o nome do bucket se diferente).

Exemplo de statement (JSON):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "TemplateMediaUpload",
      "Effect": "Allow",
      "Action": ["s3:PutObject"],
      "Resource": ["arn:aws:s3:::pilot-status/public/tenants/*"]
    }
  ]
}

Se usar usuário IAM, gere Access key e configure AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY no deploy.

3) Leitura pública (URLs fixas para mediaUrl)

Para o WhatsApp e o app usarem a URL pública (https://<bucket>.s3.<region>.amazonaws.com/<key>), o objeto precisa ser legível publicamente ou você precisa de outro mecanismo (CloudFront + OAI, etc.).

Opção simples (objetos públicos só no prefixo):

  1. Em S3 → bucket → Permissions → Block public access, permita bucket policies públicas (desbloqueie só o necessário; não precisa abrir listagem do bucket).
  2. Adicione uma Bucket policy permitindo s3:GetObject para arn:aws:s3:::pilot-status/public/tenants/* com Principal: "*" (ou restrinja por IP/CloudFront conforme sua arquitetura).

Exemplo (leitura pública no prefixo public/tenants/):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadTemplateMedia",
      "Effect": "Allow",
      "Principal": "*",
      "Action": ["s3:GetObject"],
      "Resource": ["arn:aws:s3:::pilot-status/public/tenants/*"]
    }
  ]
}

Nota: Não é necessário CORS no bucket para este fluxo (upload via backend). CORS no S3 só seria obrigatório se o navegador enviasse o arquivo direto para o S3 (presigned URL).

4) Validação

  1. Configure as env vars no serviço fullstack e faça deploy.
  2. Na UI de templates, teste Imagem → Upload (PNG/JPEG/WebP/GIF < 5MB), Vídeo → Upload (MP4 < 16MB) e PDF → Upload (< 10MB).
  3. Confirme que a API retorna 201 e uma url que abre no navegador (HTTP 200).
  4. Salve o template e verifique que o body JSON contém mediaUrl e mediaType adequados.

Tipos e limites no backend

  • Imagem: image/png, image/jpeg, image/webp, image/gif — máx. 5 MB
  • Vídeo: video/mp4 — máx. 16 MB
  • Documento: application/pdf — máx. 10 MB