recover(api-key): вернуть в develop осиротевший UI фазы-2 (#506/#533) #572

Merged
vvzvlad merged 3 commits from recover/506-apikey-ui into develop 2026-07-12 19:24:37 +03:00
Collaborator

Восстановление: UI управления API-ключами (#506/#533) осиротел от develop

Проблема (найдено при планировании #556). Фаза-2 UI API-ключей (#533) в develop НЕ попала. #533 смержился в ветку feat/501-mcp-apikey-auth в 17:33 — а сама feat/501 ушла в develop раньше (через #526 в 05:02). Итог: 4 UI-коммита #533 остались на feat/501 и НЕ являются предками develop. Проверено ancestry, не по merged-флагу:

  • git merge-base --is-ancestor 4e64c953 gitea/developNO.
  • В develop apps/client/src/features/api-key/** отсутствует (0 файлов).

Классический orphan стакнутого PR (тот же класс, что #491→#540): merged-флаг зелёный, но контент не в develop.

Восстановление. Черри-пикнул 3 UI-коммита #533 (199a9a17/d6411424/be25b31a — соответствуют оригинальным 90c02a0a/79675825/5e697434) на свежую ветку от develop. Серверная часть фазы-1 уже в develop (через #526), так что тут ровно клиентский UI-делта (1205 строк): страница управления ключами в настройках, create/show-token модалки, query/service/utils, i18n (ru+en), роут/сайдбар/телеметрия.

Конфликт при черри-пике — только translation.json (en+ru): develop добавил свои ключи в ту же alphabetical-зону. Разрешён аддитивно (оба набора ключей сохранены; api-key-ключи 1 year/30 days/90 days встают перед A new version…). JSON валиден, дублей нет (1 year count = 1).

Верификация. api-key vitest 68/68 (4 файла) на текущем develop. Маркеров нет.

Это re-land кода, уже прошедшего ревью как #533 — но пусть ревьюер подтвердит корректность восстановления (ставлю review/needs, сам approve не ставлю). Без этого PR у #556 фазы 3A нет UI-поверхности (copy-button), и операторам нечем выпускать ключи перед cutover фазы 3B.

Всплыло при планировании #556 (API-ключи фаза 3).

## Восстановление: UI управления API-ключами (#506/#533) осиротел от develop **Проблема (найдено при планировании #556).** Фаза-2 UI API-ключей (#533) в develop НЕ попала. #533 смержился в ветку `feat/501-mcp-apikey-auth` в 17:33 — а сама `feat/501` ушла в develop раньше (через #526 в 05:02). Итог: 4 UI-коммита #533 остались на `feat/501` и НЕ являются предками develop. Проверено ancestry, не по merged-флагу: - `git merge-base --is-ancestor 4e64c953 gitea/develop` → **NO**. - В develop `apps/client/src/features/api-key/**` **отсутствует** (0 файлов). Классический orphan стакнутого PR (тот же класс, что #491→#540): merged-флаг зелёный, но контент не в develop. **Восстановление.** Черри-пикнул 3 UI-коммита #533 (`199a9a17`/`d6411424`/`be25b31a` — соответствуют оригинальным `90c02a0a`/`79675825`/`5e697434`) на свежую ветку от develop. Серверная часть фазы-1 уже в develop (через #526), так что тут ровно клиентский UI-делта (1205 строк): страница управления ключами в настройках, create/show-token модалки, query/service/utils, i18n (ru+en), роут/сайдбар/телеметрия. **Конфликт при черри-пике** — только `translation.json` (en+ru): develop добавил свои ключи в ту же alphabetical-зону. Разрешён аддитивно (оба набора ключей сохранены; api-key-ключи `1 year`/`30 days`/`90 days` встают перед `A new version…`). JSON валиден, дублей нет (`1 year` count = 1). **Верификация.** api-key vitest **68/68** (4 файла) на текущем develop. Маркеров нет. Это re-land кода, уже прошедшего ревью как #533 — но пусть ревьюер подтвердит корректность восстановления (ставлю review/needs, сам approve не ставлю). Без этого PR у #556 фазы 3A нет UI-поверхности (copy-button), и операторам нечем выпускать ключи перед cutover фазы 3B. _Всплыло при планировании #556 (API-ключи фаза 3)._
agent_coder added 3 commits 2026-07-12 19:22:25 +03:00
Фаза 2 поверх серверных эндпоинтов #501: страница «Настройки → Аккаунт →
API-ключи» (lazy-роут, отдельный чанк) — список, создание, показ токена
один раз и отзыв.

- Список: явная дата истечения (не «через N дней»), подсветка ключей с
  истечением < 30 дней, «использован» с семантикой «в течение последнего
  часа» (last_used_at троттлится на 1 ч серверно).
- Создание: имя + срок (30д/90д/1 год[дефолт]/бессрочный → null). После
  submit — модалка показа токена один раз с копированием и явной датой.
- Токен-материал живёт ТОЛЬКО в state открытой модалки: mutateAsync +
  reset() чистит копию из query-cache, ничего не пишется в localStorage.
  Закрытие модалки — токен исчезает навсегда.
- Отзыв: подтверждение → revoke → строка уходит из списка.
- Admin (CASL Manage на API = owner/admin) видит ключи всего воркспейса с
  колонкой «автор»; обычный член — только свои.

Тесты (vitest): показ-один-раз + отсутствие токена в localStorage/кэше,
явная дата + подсветка < 30 дней, отзыв убирает строку, admin/member вид,
дефолт срока = 1 год и «бессрочный» → null. Стаб ResizeObserver добавлен в
общий vitest.setup для рендера Mantine ScrollArea/Table.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fix 1: an already-expired key rendered the forward-looking "Expiring soon"
badge/tooltip ("expires within 30 days"), which is false for a past expiry.
Add a pure isExpired() helper and, in ApiKeysManager, render a red "Expired"
badge ("This key has expired") for past expiries; keep the orange "Expiring
soon" badge only for keys expiring in the future within 30 days (the two
states are made mutually exclusive at the call site). Extend utils.test.ts
with isExpired coverage (past/future/null/exact-now boundary) and add a
component assertion that an expired key shows "Expired" and NOT "Expiring
soon".

Fix 2: the response-contract unwrap (res.data turning the server envelope
{data:{token,apiKey},success,status} into {token,apiKey}) was exercised by no
test — component tests fully mock the service. Add a service-layer unit test
that mocks the api-client (axios instance) and asserts createApiKey unwraps to
the inner {token,apiKey} payload and getApiKeys resolves to the row array.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
en-US (source of truth) and ru-RU were missing ~25 strings introduced by the
api-key management UI, so Russian users saw the controls in English and en-US
was incomplete. Add every new t() key to both locales (24 new in en-US, 26 in
ru-RU) with natural Russian translations, placeholders ({{name}}/{{date}})
preserved; existing keys left untouched (insertions only, no reordering).

Also fix the createApiKey() lifecycle comment: the gcTime:0 + invalidation
lives in queries/api-key-query.ts (there is no use-api-key-query file) and the
reset()-after-read of the token lives in components/api-keys-manager.tsx
handleCreate (create-api-key-modal.tsx only resets the form).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
agent_coder added the review/needs label 2026-07-12 19:22:28 +03:00
vvzvlad merged commit 78fc7c4842 into develop 2026-07-12 19:24:37 +03:00
Sign in to join this conversation.