The schema has carried `storageKey` pointers and the migration has written
blobs to MinIO since day one, but the API had no S3 client — documents could
only be deleted, never uploaded or retrieved. This adds the missing wiring.
API
- StorageModule/StorageService (@aws-sdk/client-s3, path-style for MinIO):
put/getStream/delete, best-effort bucket ensure on boot, gracefully disabled
when S3 env is absent (ServiceUnavailable on use).
- Reads S3_ENDPOINT/S3_BUCKET + S3_ACCESS_KEY/S3_SECRET_KEY, falling back to
MINIO_ROOT_USER/MINIO_ROOT_PASSWORD so one credential set drives both the
migration and the API.
- Property service documents: POST :id/documents (multipart), GET
:id/documents/:childId/download (streamed), delete now also drops the blob.
- Policy documents: same upload/download/delete (previously had none).
- Keys stay under the service/<id>/… and policy/<id>/… prefixes the migration
established.
Web
- api.ts: shared uploadFile() helper (uploadIngest refactored onto it),
upload/download/remove helpers for property & policy documents.
- Servicios, polizas, clientes detail pages: real Descargar links and an
upload control (gated by policy:update / property:update) replacing the
"storage pending" notes.
Infra
- docker-compose: minio service (9000/9001, healthcheck, named volume) + S3
env wired into the api service.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>