# Временное Test API для бесплатной загрузки аватаров в Arweave

> Статус: **временное тестовое решение**.
> Все операции из этого файла начинаются с `Test...`, чтобы это было видно сразу и в коде, и в UI.

## Назначение

Этот временный API даёт пользователю ограниченную бесплатную загрузку маленьких аватаров в Arweave:

- загрузка идёт через **серверный Arweave-кошелёк**;
- лимит на пользователя: по умолчанию `3` загрузки за всё время;
- лимит хранится в SQLite-таблице `test_free_avatar_uploads`;
- если лимит исчерпан, сервер возвращает понятную ошибку;
- загружать можно только маленький итоговый файл аватара, по умолчанию до `128 KB`.

## Настройки сервера

В `application.properties`:

```properties
test.freeAvatar.enabled=true
test.freeAvatar.gateway=https://arweave.net
test.freeAvatar.limitPerUser=3
test.freeAvatar.maxBytes=131072
test.freeAvatar.walletAddress=
test.freeAvatar.walletJwkPath=
```

Пояснения:

- `test.freeAvatar.enabled` - включить или выключить временный API;
- `test.freeAvatar.gateway` - Arweave gateway для `price/tx/wallet`;
- `test.freeAvatar.limitPerUser` - пожизненный бесплатный лимит на пользователя;
- `test.freeAvatar.maxBytes` - максимальный размер итогового файла;
- `test.freeAvatar.walletAddress` - публичный адрес серверного Arweave-кошелька;
- `test.freeAvatar.walletJwkPath` - путь к приватному JWK-файлу серверного кошелька.

Важно:

- приватный JWK хранится вне кода;
- если `walletAddress` указан и не совпадает с адресом, вычисленным из JWK, сервер вернёт ошибку настройки.

## `TestGetFreeAvatarQuota`

Возвращает остаток бесплатных загрузок для текущего авторизованного пользователя.

### Запрос

```json
{
  "op": "TestGetFreeAvatarQuota",
  "requestId": "req-test-avatar-quota-1",
  "payload": {}
}
```

### Успешный ответ

```json
{
  "op": "TestGetFreeAvatarQuota",
  "requestId": "req-test-avatar-quota-1",
  "status": 200,
  "ok": true,
  "payload": {
    "enabled": true,
    "limit": 3,
    "usedCount": 1,
    "remainingCount": 2,
    "maxBytes": 131072
  }
}
```

### Поля ответа

- `enabled` - временный API сейчас включён на сервере или нет;
- `limit` - полный лимит бесплатных загрузок;
- `usedCount` - сколько уже израсходовано;
- `remainingCount` - сколько ещё осталось;
- `maxBytes` - максимальный размер итогового файла.

### Ошибки

- `422 NOT_AUTHENTICATED` - требуется авторизация.

## `TestUploadFreeAvatar`

Временная бесплатная загрузка маленькой аватарки в Arweave через серверный кошелёк.

### Правила

- операция требует авторизованную сессию;
- сервер использует текущий login из сессии;
- сервер принимает только:
  - `image/jpeg`
  - `image/png`
  - `image/webp`
- размер итогового файла должен быть не больше `maxBytes` из квоты;
- если пользователь уже сделал `limit` бесплатных загрузок, операция запрещена.

### Запрос

`fileBytesBase64` - это обычный Base64 байт итогового подготовленного файла.

```json
{
  "op": "TestUploadFreeAvatar",
  "requestId": "req-test-avatar-upload-1",
  "payload": {
    "contentType": "image/webp",
    "fileBytesBase64": "UklGRiQAAABXRUJQVlA4WAoAAAAQAAAA...",
    "sha256Hex": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
  }
}
```

### Успешный ответ

```json
{
  "op": "TestUploadFreeAvatar",
  "requestId": "req-test-avatar-upload-1",
  "status": 200,
  "ok": true,
  "payload": {
    "txId": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
    "sha256Hex": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
    "usedCount": 2,
    "remainingCount": 1,
    "limit": 3,
    "gateway": "https://arweave.net"
  }
}
```

### Поля ответа

- `txId` - Arweave Transaction ID загруженного файла;
- `sha256Hex` - SHA-256 загруженного файла;
- `usedCount` - сколько бесплатных загрузок уже израсходовано после этой операции;
- `remainingCount` - сколько бесплатных загрузок осталось;
- `limit` - общий лимит;
- `gateway` - gateway, через который сервер отправлял транзакцию.

### Ошибки

- `422 NOT_AUTHENTICATED` - требуется авторизация;
- `400 BAD_FIELDS` - не переданы `contentType` или `fileBytesBase64`;
- `400 BAD_BASE64` - `fileBytesBase64` не декодируется;
- `400 BAD_AVATAR_FILE` - файл не проходит ограничения сервера;
- `400 FREE_AVATAR_LIMIT_EXHAUSTED` - бесплатный лимит аватарок исчерпан;
- `501 FREE_AVATAR_TEMP_DISABLED` - временная функция выключена или сервер не настроен;
- `500 INTERNAL_ERROR` - внутренняя ошибка сервера.

## Как это используется в UI

На экране редактирования профиля в мастере смены аватара есть временный сценарий:

- `Залить аватар бесплатно`

UI:

1. вызывает `TestGetFreeAvatarQuota`;
2. показывает остаток лимита;
3. локально подготавливает уменьшенный файл аватара;
4. проверяет, что итоговый файл не превышает `maxBytes`;
5. вызывает `TestUploadFreeAvatar`;
6. после получения `txId` обычным путём записывает `avatar.ar` в профиль через `AddBlock`.

## Почему решение временное

- используется общий серверный Arweave-кошелёк;
- лимит хранится отдельной технической таблицей;
- операции имеют префикс `Test...`;
- сценарий нужен как переходный бесплатный путь для маленьких аватаров.
