Object Storage¶
For uploaded files, generated PDFs, document extracts, image variants, audio recordings — anything that doesn't belong in a relational table. The portfolio splits between MinIO (self-hosted) and AWS S3 (managed), with R2 used in two apps for egress savings.
Portfolio map¶
| Backend | Apps | Role |
|---|---|---|
| MinIO | 4 | Self-hosted S3-compatible. Default for AI document apps. |
| AWS S3 | 4 | Managed cloud storage. Used by tenant-facing apps that need durability + CDN. |
| Cloudflare R2 | 2 | S3-compatible with zero egress fees. Used in e-commerce. |
| Local disk only | rest | No durable file storage — everything's in DB or files-on-server. |
MinIO¶
What it is. Open-source, S3-compatible object store. Runs as a Docker container alongside Postgres and Redis. Same SDKs as AWS S3 (@aws-sdk/client-s3, boto3, minio SDK).
Why we use it. Self-hosted on the IONOS VPS = no monthly bill, no egress fees, full control of the data, GDPR-friendly. The S3 API means migrating to AWS S3 later is a config change.
Used in: - GoGreen-AI-Concierge — uploaded knowledge files, scraped pages, processed embeddings cache. - GoGreen-DOC-AI — scanned documents, OCR outputs, generated PDFs. - GoGreen-SmartForms — form attachments, extracted data exports. Uses MinIO in dev, S3 in prod. - GoGreen-Workflow-Hub — workflow artifacts (reports, logs, exports).
Common docker-compose pattern:
minio:
image: minio/minio
command: server /data --console-address ":9001"
ports: ["9000:9000", "9001:9001"]
environment:
MINIO_ROOT_USER: ...
MINIO_ROOT_PASSWORD: ...
volumes: [minio_data:/data]
Tradeoffs. You operate it. No multi-region, no built-in CDN — pair with nginx caching or Cloudflare in front for that.
AWS S3¶
What it is. Amazon's object storage. The reference implementation of the S3 API. Multi-region, lifecycle policies, intelligent tiering, signed URLs, pre-signed POST.
Why we use it. When the tenant needs verifiable durability (11 nines), regional residency, or the app benefits from CloudFront CDN integration. Also when usage is low enough that the AWS bill is negligible.
Used in: - FamilyChat — user-uploaded media (images, video clips, voice notes). - Ecom-Sales — product images, marketplace asset feeds. - GogreenSellerAI — same. - GoGreenMarketing — campaign assets. - GoGreen-SmartForms — production storage (MinIO is the dev mirror). - OpenSentinel — long-term audit logs and OSINT artifacts (via the AWS S3 integration adapter).
SDK: @aws-sdk/client-s3 v3 modular SDK in TS, boto3 in Python.
Cloudflare R2¶
What it is. Cloudflare's S3-compatible object store. Zero egress fees is the headline feature — you pay only for storage and requests, not for bytes leaving the bucket.
Why we use it. Tenant-facing assets where users download a lot — product images, marketplace exports — would rack up S3 egress charges. R2's pricing inverts that.
Used in: - Ecom-Sales — configurable per tenant; some tenants run on R2 instead of S3. - GogreenSellerAI / EcomFlow — same.
Tradeoffs. No native CloudFront integration (you use Cloudflare's CDN, which is fine since you're already on R2). Not all S3 features (versioning quirks, lifecycle policies) are 100% identical.
Comparison alternatives (not used)¶
Backblaze B2¶
S3-compatible, even cheaper than R2 for cold storage. No app currently uses it — the cost difference doesn't justify a third storage backend.
DigitalOcean Spaces / Linode Object Storage¶
Same shape as S3. Not in use; the portfolio doesn't run on DO/Linode.
Azure Blob Storage / GCS¶
Used for clients on those clouds. Not in this portfolio.
Supabase Storage¶
Postgres-backed file metadata + S3 storage with RLS. Convenient when you're already on Supabase. Portfolio is self-hosted Postgres, so no Supabase Storage either.
Common patterns¶
Pre-signed URLs¶
The server signs a short-lived (~5 min) URL granting upload or download rights to a specific object key. Browser uploads directly to S3/MinIO/R2 — server never sees the bytes.
Used in: FamilyChat (media uploads), GoGreen-DOC-AI (large PDF uploads), Ecom-Sales (product image uploads).
Multi-tenant key prefix¶
Object keys are namespaced like tenants/{tenant_id}/uploads/{file_id}. RLS-style isolation at the storage layer.
Used in: GoGreen-AI-Concierge, GoGreen-SmartForms, FamilyChat, Ecom-Sales (per-tenant storage backend choice — MinIO/S3/R2).
Signed download (CDN-fronted)¶
Generate a signed CloudFront URL for the file → CDN serves it directly to the user, server never proxies. Cuts cost and latency.
Pattern is set up in Ecom-Sales / GogreenSellerAI per tenant config.
Lifecycle / expiry policies¶
S3/MinIO/R2 all support "delete object after N days." Used for transient generated files (PDFs, exports) that don't need to live forever.