feat: object storage (Garage) para anexos novos, sem migrar histórico #76
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/object-storage-garage"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Implementa o P1 "object storage para anexos" do backlog, com duas decisões de produto confirmadas com o usuário antes de implementar.
O que muda:
Attachment/ImageeRunAttachmentganhamstorage_key(nullable). Uma linha grava OU_data(BLOB) OUstorage_key, nunca os dois -- a propertydatadecide de onde ler, então nenhum ponto de leitura existente precisou mudar (attachment.data/image.datacontinuam funcionando idênticos em todo lugar que já chamava isso). Só o momento da escrita (services/attachments.py::decode_and_store, usado nos ~7 pontos que antes chamavamdecode_imagedireto) decide uma vez se o anexo novo vai pro Garage ou continua BLOB.services/object_storage.pyisola o client S3 (boto3), mesmo padrão de isolamento deai_client.py/hubspot_client.py/modules/orchestration/client.py. Opcional por design: sem as 5 env varsGARAGE_*configuradas,is_configured()éFalsee tudo continua BLOB automaticamente -- dev/teste não dependem do Garage estar de pé.Duas decisões de produto confirmadas com o usuário antes de escrever código (ver ADR-0016):
ENVIRONMENT:development/attachments/<uuid>vsproduction/attachments/<uuid>.Correção real ao escopo esperado: a auditoria arquitetural anterior assumia que tanto
AttachmentquantoRunAttachmentjá estavam abstraídos por trás de uma propertydata. Isso era verdade só praRunAttachment--Attachment/Imageusava umaColumndireta. Corrigido convertendo pra property também (com@data.setter, mesmo padrão queRunAttachmentjá tinha), sem mudar nenhum contrato HTTP.Verificação: 269/269 testes de backend (7 novos em
test_object_storage.py: config das 5 env vars, prefixo de key por ambiente, roundtrip upload/download com fake client, fallback pra BLOB sem Garage configurado, e um teste de ponta a ponta via API confirmando queImageOutnunca expõestorage_keye queGET /api/images/{id}devolve o binário certo nos dois casos). Migration testada upgrade→downgrade→upgrade +alembic checksem drift. Smoke test único contra o Garage real (upload + download + delete de limpeza) rodou com sucesso -- credenciais usadas só como env vars inline no shell durante o teste, nunca escritas em nenhum arquivo do repositório (confirmado por scan do diff antes do commit).🤖 Generated with Claude Code