# 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.<regio>.scw.cloud`). Houd buckets "plat" (alle tenants
> als prefix).

### Prefix layout (per tenant)

    <bucket>/
      tenant-<tenantId>/
        documents/
          <subfolders naar keuze>...
        assets/
          <subfolders naar keuze>...

**Conventies** - **Tenant prefix:** `tenant-<tenantId>` (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.<regio>.scw.cloud`
-   `S3_BUCKET=evie-<env>`
-   `S3_ACCESS_KEY=***`
-   `S3_SECRET_KEY=***`
-   `S3_REGION=<regio>` (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-<tenantId>/...`.
-   **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-<id>/documents/` en `tenant-<id>/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-<id>/<datatype>/<...>`\
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-<env>/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-<id>/{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.
