Skip to content

# Assets Proxy — Документація

## Огляд

DAARION використовує MinIO (S3-compatible object storage) для зберігання assets (логотипи, банери, аватарки). Для доступу до assets без налаштування DNS для `assets.daarion.space` використовується Asset Proxy через `city-service`.

## Архітектура

    ┌─────────────┐
    │   Frontend  │ → /api/city/assets/proxy/microdao/logo/...
    └─────────────┘
           │
           ↓
    ┌─────────────┐
    │ city-service│ → /city/assets/proxy/{path}
    │  (FastAPI)  │
    └─────────────┘
           │
           ↓
    ┌─────────────┐
    │    MinIO    │ → daarion-assets/microdao/logo/...
    │  (Docker)   │
    └─────────────┘

## Контракт normalizeAssetUrl ↔ Asset Proxy

### Вхідний URL з БД

    https://assets.daarion.space/daarion-assets/microdao/logo/2025/12/02/abc123.png

### Вихідний URL для фронта (після normalizeAssetUrl)

    /api/city/assets/proxy/microdao/logo/2025/12/02/abc123.png

### Шлях до MinIO (всередині proxy)

    daarion-assets/microdao/logo/2025/12/02/abc123.png

Важливо: `normalizeAssetUrl` відрізає `daarion-assets/` з URL, тому proxy отримує шлях без префіксу бакету. Proxy додає `ASSETS_BUCKET` автоматично.

## Використання в компонентах

ЗАВЖДИ використовуйте `normalizeAssetUrl` для всіх asset URLs:

    import { normalizeAssetUrl } from '@/lib/utils/assetUrl';

    // ✅ ПРАВИЛЬНО
    <img src={normalizeAssetUrl(logo_url)!} alt="Logo" />

    // ❌ НЕПРАВИЛЬНО
    <img src={logo_url} alt="Logo" />

## Endpoint

### City Service

- Path: `/city/assets/proxy/{path:path}`
- Method: `GET`
- Router prefix: `/city` (монтується в `main.py` без додаткового префіксу)
- Повний URL: `/api/city/assets/proxy/{path}`

### Параметри

- `path` — шлях до файлу в MinIO (без префіксу бакету)
- Приклад: `microdao/logo/2025/12/02/abc123.png`

### Відповідь

- 200 OK — файл знайдено
- `Content-Type`: `image/png`, `image/jpeg`, тощо
- `Cache-Control`: `public, max-age=86400, immutable`

- `Access-Control-Allow-Origin`: `*`

- 404 Not Found — файл не знайдено в MinIO

## ENV змінні

### City Service

    MINIO_ENDPOINT=http://minio:9000
    MINIO_ROOT_USER=assets-admin
    MINIO_ROOT_PASSWORD=<password>
    ASSETS_BUCKET=daarion-assets
    ASSETS_PUBLIC_BASE_URL=https://assets.daarion.space/daarion-assets

Примітка: `ASSETS_PUBLIC_BASE_URL` використовується тільки для генерації URL при завантаженні. Для читання використовується proxy.

## Приклади

### Завантаження asset

    from lib.assets_client import upload_asset

    url = upload_asset(
        file_obj,
        content_type="image/png",
        prefix="microdao/logo",
        filename="logo.png"
    )
    # Повертає: https://assets.daarion.space/daarion-assets/microdao/logo/2025/12/02/abc123.png

### Відображення asset на фронті

    const logoUrl = "https://assets.daarion.space/daarion-assets/microdao/logo/2025/12/02/abc123.png";
    const normalized = normalizeAssetUrl(logoUrl);
    // normalized = "/api/city/assets/proxy/microdao/logo/2025/12/02/abc123.png"

    <img src={normalized} alt="Logo" />

## Troubleshooting

### 404 Not Found

1. Перевірте чи файл існує в MinIO: `bash docker exec daarion-minio mc ls minio/daarion-assets/microdao/logo/2025/12/02/`

2. Перевірте чи правильний шлях передається в proxy: `bash curl -I "https://daarion.space/api/city/assets/proxy/microdao/logo/2025/12/02/abc123.png"`

3. Перевірте логи city-service: `bash docker logs daarion-city-service | grep "assets/proxy"`

### 500 Internal Server Error

1. Перевірте ENV змінні в docker-compose: `bash docker exec daarion-city-service env | grep MINIO`

2. Перевірте чи MinIO доступний: `bash docker exec daarion-city-service curl -I http://minio:9000/minio/health/live`

### Assets не відображаються на фронті

1. Перевірте чи компонент використовує `normalizeAssetUrl`: ```typescript // ✅ ПРАВИЛЬНО src={normalizeAssetUrl(url)}

// ❌ НЕПРАВИЛЬНО src={url} ```

1. Перевірте в DevTools Network tab:
2. Чи запити йдуть на `/api/city/assets/proxy/...`?
3. Який статус відповіді (200/404/500)?

## Додавання нових компонентів

При додаванні нового компонента, який відображає assets:

1. Імпортуйте `normalizeAssetUrl`: `typescript import { normalizeAssetUrl } from '@/lib/utils/assetUrl';`

2. Використовуйте для всіх asset URLs: `typescript <img src={normalizeAssetUrl(logo_url)!} alt="Logo" /> <div style={{ backgroundImage: `url(${normalizeAssetUrl(banner_url)})` }} />`

3. НЕ використовуйте прямі URLs з БД без нормалізації.

## Міграція зі старих URL

Якщо в БД є старі формати URL:

- `/static/uploads/logo.png` → автоматично конвертується в `/api/static/uploads/logo.png`
- `/assets/logos/logo.png` → залишається як є
- `https://assets.daarion.space/...` → конвертується в `/api/city/assets/proxy/...`

`normalizeAssetUrl` обробляє всі ці випадки автоматично.