# Evie Object Storage Governance (Optie 3) **Doel:** 1 bucket per omgeving (staging / prod), met **prefixen per tenant**. Duidelijke scheiding van datatypes (documents vs assets), lage beheerlast, goed schaalbaar. ------------------------------------------------------------------------ ## 1) Structuur & naamgeving ### Buckets (per omgeving) - **staging:** `evie-staging` - **prod:** `evie-prod` > Buckets zijn S3-compatibel op Scaleway > (`https://s3..scw.cloud`). Houd buckets "plat" (alle tenants > als prefix). ### Prefix layout (per tenant) / tenant-/ documents/ ... assets/ ... **Conventies** - **Tenant prefix:** `tenant-` (tenantId = interne stabiele sleutel; geen PII). - **Datatypes:** `documents/` en `assets/` (harde scheiding). - **Bestandsnamen:** `snake-case` of `kebab-case`; voeg optioneel datum/uuid toe bij uploads die kunnen conflicteren. ------------------------------------------------------------------------ ## 2) Toegang & secrets ### IAM-model - **Één IAM Application per omgeving** - `evie-staging-app` → keys in **staging** k8s Secret\ - `evie-prod-app` → keys in **prod** k8s Secret\ - Toegang **alleen** tot het eigen bucket (`evie-staging` of `evie-prod`). ### App-side secrets (env) - `S3_ENDPOINT=https://s3..scw.cloud` - `S3_BUCKET=evie-` - `S3_ACCESS_KEY=***` - `S3_SECRET_KEY=***` - `S3_REGION=` (bv. `fr-par`) - (optioneel) `S3_FORCE_PATH_STYLE=false` > **Presigned uploads**: genereer **server-side** presigned URL's per > tenant/prefix; geef nooit de master-keys aan de client. ------------------------------------------------------------------------ ## 3) Policies (conceptueel) - **Bucket policy**: sta alleen requests toe met geldige credentials van de Evie-app van die omgeving. - **Prefix scope** (in app-logica): alle reads/writes **moeten** met pad beginnen op `tenant-/...`. - **Optioneel** (later): extra policy-groepen voor specifieke workflows (vb. tijdelijke ingest job). > **Belangrijk:** autorisatie op tenantniveau afdwingen in **je > applicatie** (context = `tenantId`). Nooit paden samenstellen vanuit > user input zonder whitelisting/validation. ------------------------------------------------------------------------ ## 4) Lifecycle & retentie **Doel:** kosten beheersen, assets sneller "kouder", documenten langer bewaren. ----------------------------------------------------------------------- Scope (Filter) Regel ----------------------------------- ----------------------------------- `tenant-*/assets/` → One Zone-IA na 30 dagen `tenant-*/assets/` → Glacier/Archive na 180 dagen (optioneel) `tenant-*/documents/` → Standard (geen transition) of IA na 180d `tenant-*/documents/` (tijdelijke Expire (delete) na 7--14 dagen previews) ----------------------------------------------------------------------- > Lifecycle definieer je **per bucket** met **prefix filters**, zodat > regels verschillend zijn voor `assets/` en `documents/`. ------------------------------------------------------------------------ ## 5) CORS & distributie - **CORS**: indien browser direct upload/download doet, whitelist de domeinen van je app (origin), en methodes `GET, PUT, POST`. Alleen benodigde headers toestaan. - **Publieke distributie** (indien nodig): - Kleine public-reads via presigned URL's (aanbevolen).\ - Of activeer publieke read op een **specifieke** `public/`-prefix (niet op de hele bucket).\ - Overweeg een CDN/edge-lag via Scaleway Edge Services voor veelgevraagde assets. ------------------------------------------------------------------------ ## 6) Observability & beheer - **Logging/metrics**: - App: log alle S3 calls met `tenantId` + object key.\ - Platform: gebruik Scaleway Cockpit voor capacity & request metrics. - **Quota & limieten**: - 1 bucket per omgeving beperkt "bucket-sprawl".\ - Objecten en totale grootte zijn praktisch onbeperkt; plan wel lifecycle om groei te managen. - **Monitoring**: - Alerts op snelgroeiende **assets**-prefixen, high error rates (4xx/5xx), en mislukte lifecycle-transities. ------------------------------------------------------------------------ ## 7) Operationele workflows ### Tenant aanmaken 1. DB schema provisionen. 2. (S3) **Geen nieuwe bucket**; enkel **prefix**: `tenant-/documents/` en `tenant-/assets/` zijn impliciet. 3. (Optioneel) Init bestanden/placeholder objecten. 4. App-config linkt de tenant aan zijn prefix (centrale mapping). ### Upload (app -\> S3) 1. App valideert `tenantId` en datatype (`documents|assets`).\ 2. App construeert **canonical path**: `tenant-//<...>`\ 3. App genereert **presigned PUT** (tijdelijk) en geeft terug aan frontend.\ 4. Frontend uploadt rechtstreeks naar S3 met presigned URL. ### Download / Serve - Interne downloads: app signed GET of server-side stream.\ - Externe/public: **presigned GET** met korte TTL of via public-only prefix + CDN. ### Opruimen & lifecycle - Tijdelijke artefacten: app scheduled cleanup (of lifecycle "Expiration").\ - Archivering: lifecycle transitions per prefix. ------------------------------------------------------------------------ ## 8) Beveiliging - **Least privilege**: IAM-keys enkel voor het bucket van de omgeving.\ - **Encryptie**: server-side encryption (default) volstaat vaak; overweeg KMS als apart key-beleid nodig is.\ - **Auditing**: log alle **write**-operaties met gebruikers- en tenantcontext.\ - **Backups**: documenten zijn de "bron"? Zo ja, S3 is primaire opslag en RAG-index kan herbouwd worden. Anders: definieer export/replica-strategie. ------------------------------------------------------------------------ ## 9) Migratie van MinIO → Scaleway 1. **Freeze window** (kort): pauzeer uploads of werk met **duale write** (MinIO + S3) gedurende migratie.\ 2. **Sync**: gebruik `rclone` of `mc mirror` om `minio://bucket/tenant-*/{documents,assets}/` → `s3://evie-/tenant-*/...`.\ 3. **Verifieer**: random checksums / sample reads per tenant.\ 4. **Switch**: zet `S3_ENDPOINT` en keys naar Scaleway; laat nieuwe writes enkel naar S3 gaan.\ 5. **Decom**: na grace-periode MinIO uitfaseren. ------------------------------------------------------------------------ ## 10) Checklist (TL;DR) - [ ] Buckets: `evie-staging`, `evie-prod`.\ - [ ] Prefix: `tenant-/{documents,assets}/`.\ - [ ] IAM: 1 Application per omgeving; keys in k8s Secret.\ - [ ] Policy: alleen app-toegang; app dwingt prefix-scope per tenant af.\ - [ ] Lifecycle: assets sneller koud, docs langer.\ - [ ] CORS: alleen noodzakelijke origins/methods.\ - [ ] Presigned URLs voor browser interacties.\ - [ ] Logging/metrics/alerts ingericht.\ - [ ] Migratiepad van MinIO uitgewerkt en getest.