Some checks are pending
Backend:
- src/food-market.api/Storage/IObjectStorage.cs — абстракция
(SaveAsync, OpenAsync, DeleteAsync, PublicUrl). Имя реализации (Kind)
для логов.
- LocalObjectStorage — ContentRoot/uploads/{key}. По умолчанию.
- MinioObjectStorage — S3-совместимый bucket, ключ-объекта совпадает с
тем что хранится в БД (products/{id:N}/{guid}.png). PutObject с явным
size (для NetworkStream копируем в MemoryStream).
- StorageOptions: Type=Local|Minio, Endpoint, AccessKey, SecretKey,
UseSsl, Bucket=food-market-uploads.
- StorageBootstrap.AddObjectStorage — DI-регистрация с runtime fallback
на Local если MinIO-config пустой; MinioBootstrap (IHostedService)
создаёт bucket на старте, ловит ошибку и не валит API.
- UploadsController: GET /uploads/{**path} → стримит из IObjectStorage
(cache-control 7 дней). Нужен когда MinIO активен — для Local nginx
раздаёт быстрее, но фолбэк работает.
- ProductImagesController отрефакторен на IObjectStorage; URL'ы в БД
остаются /uploads/products/{id}/{guid}.ext.
Тесты:
- StorageAbstractionTests (3/3 ✓): Local default, round-trip bytes,
PublicUrl pattern.
Stage-готовность:
- deploy/docker-compose.yml на стейдже обновлён (через scp): добавлен
minio container, depends_on в api, env переменные Storage__*.
Bucket автосоздаётся.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
32 lines
1.4 KiB
C#
32 lines
1.4 KiB
C#
namespace foodmarket.Api.Storage;
|
||
|
||
/// <summary>Конфиг секции <c>Storage</c>. Биндится в Program.cs.</summary>
|
||
public sealed class StorageOptions
|
||
{
|
||
/// <summary>Какой backend использовать. <c>Local</c> (default) — диск
|
||
/// в ContentRoot/uploads. <c>Minio</c> — S3-совместимый bucket.</summary>
|
||
public StorageType Type { get; set; } = StorageType.Local;
|
||
|
||
/// <summary>Относительный путь под ContentRoot для Local-стораджа.</summary>
|
||
public string LocalRoot { get; set; } = "uploads";
|
||
|
||
/// <summary>S3/MinIO endpoint (без https). Например
|
||
/// <c>192.168.1.190:9000</c> или <c>minio:9000</c>. Прокидывается через
|
||
/// env <c>Storage__Endpoint</c>.</summary>
|
||
public string? Endpoint { get; set; }
|
||
|
||
/// <summary>S3 access key. env <c>Storage__AccessKey</c>.</summary>
|
||
public string? AccessKey { get; set; }
|
||
|
||
/// <summary>S3 secret key. env <c>Storage__SecretKey</c>.</summary>
|
||
public string? SecretKey { get; set; }
|
||
|
||
/// <summary>HTTPS или HTTP. На staging-vm у нас HTTP.</summary>
|
||
public bool UseSsl { get; set; }
|
||
|
||
/// <summary>Bucket. Создаётся автоматически на старте если не существует.</summary>
|
||
public string Bucket { get; set; } = "food-market-uploads";
|
||
}
|
||
|
||
public enum StorageType { Local, Minio }
|