Commit Graph

824 Commits

Author SHA1 Message Date
Александр Зимин 6eb56cffe4 feat(records): auto-route create/edit через draft когда approvalRequired 2026-05-13 15:29:11 +00:00
semantic-release-bot daa4b284c9 chore(release): v2.20.0
## [2.20.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.19.2...v2.20.0) (2026-05-13)

###  Features

* **my-drafts:** schema drafts тоже в "Мои черновики" ([f096b57](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/f096b5746d256220f569616813b8ec886b27247d))
2026-05-13 12:54:56 +00:00
Александр Зимин 7a173adf5d Merge branch 'feat/my-schema-drafts-endpoint' into 'main'
feat(my-drafts): schema drafts тоже в "Мои черновики"

See merge request 2-6/2-6-4/terravault/ordinis!170
2026-05-13 12:45:45 +00:00
Александр Зимин f096b5746d feat(my-drafts): schema drafts тоже в "Мои черновики" 2026-05-13 12:45:45 +00:00
Александр Зимин 1b20db5059 Merge branch 'chore/auto-bump-staging-image' into 'main'
chore(ci): propose-image-bump патчит staging values тоже

See merge request 2-6/2-6-4/terravault/ordinis!169
2026-05-13 12:33:50 +00:00
Александр Зимин aad33c3bf1 chore(ci): propose-image-bump патчит staging values тоже 2026-05-13 12:33:50 +00:00
semantic-release-bot 4af79669f8 chore(release): v2.19.2
## [2.19.2](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.19.1...v2.19.2) (2026-05-13)

### 🐛 Fixes

* **auth:** read roles из access_token, не id_token (sidebar reviews hidden bug) ([b6ee703](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/b6ee703577eb868b4dc452b64b87e3ba779b3596))
2026-05-13 11:45:51 +00:00
Александр Зимин ab23f9a471 Merge branch 'fix/sidebar-roles-from-access-token' into 'main'
fix(auth): read roles из access_token, не id_token (sidebar reviews hidden bug)

See merge request 2-6/2-6-4/terravault/ordinis!168
2026-05-13 11:39:45 +00:00
Александр Зимин b6ee703577 fix(auth): read roles из access_token, не id_token (sidebar reviews hidden bug) 2026-05-13 11:39:45 +00:00
semantic-release-bot a25a997f34 chore(release): v2.19.1
## [2.19.1](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.19.0...v2.19.1) (2026-05-13)

### 🐛 Fixes

* **webhook:** scope_filter Hibernate ordinal bug + UI toggle для active ([d4ee30a](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/d4ee30a7dd09119b5d38c50b5dda212b5b3e8f88))
2026-05-13 11:20:20 +00:00
Александр Зимин b1b66bf6a8 Merge branch 'fix/webhook-scope-filter-enum-storage' into 'main'
fix(webhook): scope_filter Hibernate ordinal bug + UI toggle active

See merge request 2-6/2-6-4/terravault/ordinis!167
2026-05-13 11:05:09 +00:00
semantic-release-bot e03743b250 chore(release): v2.19.0
## [2.19.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.18.0...v2.19.0) (2026-05-13)

###  Features

* **sidebar:** role-based visibility для /reviews ([5fb1658](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/5fb1658880ad62cc641a939ae9344ec93ca594ad))

### 🐛 Fixes

* **auth:** @Autowired на WorkflowRoles main ctor ([4fe7f1e](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/4fe7f1e800b4ebe304a8011f5fc2cbb0bab67f40))
2026-05-13 11:04:11 +00:00
Zimin A.N. d4ee30a7dd fix(webhook): scope_filter Hibernate ordinal bug + UI toggle для active
Два бага в /webhooks (user report):

1. **500 при выборе scope в форме**

POST /admin/webhooks/subscriptions с scopeFilter:["PUBLIC"] возвращал 500.

Root cause: WebhookSubscription.scopeFilter был List<DataScope> с
@JdbcTypeCode(SqlTypes.ARRAY). Hibernate сериализовал enum в TEXT[] как
ordinal (е.g. {0} для PUBLIC), а DB CHECK constraint
chk_webhook_scope_filter ожидает строковые имена. Insert падал
DataIntegrityViolationException → 500.

Fix: field теперь List<String> (raw enum names). Getter/setter
конвертируют в/из DataScope — API surface (DTO, service signatures,
WebhookDispatcher) не меняется.

2. **Нет toggle active/inactive в UI**

useUpdateWebhook hook был, но не использовался в UI. Status показывался
только read-only badge'ом. Невозможно деактивировать webhook через UI.

Fix: добавлен toggle button рядом с Status badge на /webhooks/:id.
Sends PUT с inverted active flag (backend treats PUT как full replace,
поэтому пересобираем full payload).

i18n: 'webhooks.action.activate' / 'deactivate' default labels (RU).
2026-05-13 14:02:35 +03:00
Александр Зимин 4bdc7d2245 Merge branch 'feat/sidebar-role-based-visibility' into 'main'
feat(sidebar): role-based visibility для /reviews

See merge request 2-6/2-6-4/terravault/ordinis!166
2026-05-13 10:54:24 +00:00
Zimin A.N. 5fb1658880 feat(sidebar): role-based visibility для /reviews
Phase 1d enhancement: 'Согласования' пункт сайдбара скрыт если у user'а
нет approver/reviewer ролей. Раньше показывался любому authenticated —
оператор без reviewer прав видел queue, кликал и получал пустую
страницу (или 403 если бы пробовал approve).

Visibility rules:
- 'Мои черновики' — auth (maker может быть любой)
- 'Согласования' — auth + (ordinis:schema:reviewer OR ordinis:record:reviewer
  OR ordinis:admin super-role) — иначе hidden
- 'Outbox' / 'Webhooks' / 'Аудит' — auth (admin-y но backend не gated
  отдельной ролью)

Новый NavItem.reviewerOnly flag — фильтр в visibleSections учитывает
оба flag'а (authRequired + reviewerOnly).

Применено и к desktop Sidebar и к MobileSidebar (DRY refactor — отдельный
task).
2026-05-13 13:52:40 +03:00
Александр Зимин efe3fe08e5 Merge branch 'fix/workflow-roles-autowire-ctor' into 'main'
fix(auth): @Autowired на WorkflowRoles main ctor (super-role override fix)

See merge request 2-6/2-6-4/terravault/ordinis!165
2026-05-13 10:51:38 +00:00
Zimin A.N. 4fe7f1e800 fix(auth): @Autowired на WorkflowRoles main ctor
Класс имеет два constructor'а (main + test). Без явной @Autowired
аннотации Spring может выбрать no-arg ctor → props=null →
rolesClaimPath() fallback на realm_access.roles несмотря на
env var ORDINIS_AUTH_ROLES_CLAIM=resource_access.ordinis.roles.

Симптом: 403 forbidden_role с message 'Требуется realm role:
ordinis:schema:reviewer' для user с ordinis:admin в
resource_access.ordinis.roles (super-role override не работал
потому что currentRoles() возвращал пустой set из неправильного
claim path).

Fix: @Autowired на main ctor — Spring выбирает его, props
инжектится, rolesClaim читается из env var правильно.
2026-05-13 13:49:07 +03:00
Александр Зимин 19f560e60a Merge branch 'chore/restore-nstart-runner-tag' into 'main'
chore(ci): restore nstart tag (revert !157)

See merge request 2-6/2-6-4/terravault/ordinis!164
2026-05-13 10:33:21 +00:00
semantic-release-bot e183ff1d6c chore(release): v2.18.0
## [2.18.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.17.0...v2.18.0) (2026-05-13)

###  Features

* **auth:** WorkflowRoles configurable claim path + ordinis:admin super-role ([36c06ae](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/36c06ae1da52ebf515eaa5227c942f8343071188))
2026-05-13 10:29:04 +00:00
Zimin A.N. 09e9b80b0c chore(ci): restore nstart tag на default runner constraint
Revert MR !157 (removal). Shared runner pool снова показал queue
contention в часы пик. nstart-tagged выделенный pool обратно — лучше
predictable wait times для CI.

resource_group docker-builds-v2 (для parallel docker builds) остаётся
без изменений — orthogonal к runner tag selection.
2026-05-13 13:28:17 +03:00
Александр Зимин d0f49250eb Merge branch 'feat/phase-1d-configurable-claim-path-admin-override' into 'main'
feat(auth): configurable claim path + ordinis:admin super-role

See merge request 2-6/2-6-4/terravault/ordinis!163
2026-05-13 10:20:59 +00:00
Zimin A.N. 36c06ae1da feat(auth): WorkflowRoles configurable claim path + ordinis:admin super-role
User report: token has roles в resource_access.ordinis.roles (client-scoped),
backend WorkflowRoles читал hardcoded realm_access.roles → forbidden_role
для всех reviewer actions.

Backend:
- WorkflowRoles: depends OrdinisAuthProperties → reads via rolesClaim path
  (же что ScopeContext). Default realm_access.roles, на staging/prod env
  var ORDINIS_AUTH_ROLES_CLAIM=resource_access.ordinis.roles (уже wired
  в helm helper).
- Nested claim path resolver — mirror ScopeContext.readClaimByPath
- New super-role ADMIN ('ordinis:admin') — holder автоматически проходит
  любой workflow check без явного назначения отдельных ролей. Convenience
  для small teams.

Frontend (usePermissions.ts):
- tokenRoles() читает оба claim path (realm_access.roles +
  resource_access.ordinis.roles) и объединяет — UI gate работает
  независимо от backend config
- hasRole() recognizes 'ordinis:admin' как super-role override
- ROLE_ADMIN exported

Docs:
- docs/operator/rbac.md: добавлен ordinis:admin row, JWT claim path note,
  Admin profile updated (super-role vs composite explanation)
2026-05-13 13:17:54 +03:00
semantic-release-bot 031a582167 chore(release): v2.17.0
## [2.17.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.16.4...v2.17.0) (2026-05-13)

###  Features

* **auth:** Phase 1d — backend role enforcement для workflow ([24aa94d](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/24aa94d13007b7d2d9716a6afb7fdbc54a32d8ba))

### ♻️ Refactoring

* **auth:** domain-specific role names (consistent convention) ([c5b00ff](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/c5b00ff62314942f6b2cee09993d9ddd8648e8e2))

### 📝 Docs

* **rbac:** добавить матрицу realm-ролей Keycloak ([1dba947](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/1dba9476db036d4f5688d409aae4c39b5b5a441c))
2026-05-13 10:06:16 +00:00
Александр Зимин 47b47f4abc Merge branch 'feat/phase-1d-workflow-roles' into 'main'
feat(auth): Phase 1d — backend role enforcement для workflow

See merge request 2-6/2-6-4/terravault/ordinis!162
2026-05-13 09:57:44 +00:00
Zimin A.N. ce3a29f08d test(e2e): assign ordinis:record:reviewer role в reviewer JWT tokens
Phase 1d enforcement в DraftService.approve()/.reject() требует
realm role 'ordinis:record:reviewer'. Test fixtures используют
JwtTestSupport.signJwt() — добавляем role в JWT для reviewer'ов.

Changes в ApprovalWorkflowE2ETest:
- Новый helper reviewerTokenFor(subject) — internal scope + record:reviewer
- 4 reviewer call sites (bob/dave/julia/leo) → reviewerTokenFor()
- eve-solo (selfApproveBlocked test) тоже → reviewerTokenFor() чтобы
  достичь self-approve check, иначе forbidden_role срабатывает раньше

Maker callsites (alice/carol/frank/ivan/kate) остаются на tokenFor()
без reviewer role — backend гейтит только approve/reject методы.

Fix для 4 failures в pipeline 6898:
- happyFlow_submitApprove_recordLiveAndOutboxEvent
- rejectFlow_keepsDraft_noLiveRecord
- selfApproveBlocked_409
- rejectWithoutComment_400
2026-05-13 12:55:15 +03:00
Zimin A.N. 1dba9476db docs(rbac): добавить матрицу realm-ролей Keycloak
operator/rbac.md — новая страница с полной матрицей RBAC:
- Scope ACL (ordinis:client:public/internal/restricted)
- Workflow роли (schema:reviewer, schema:publisher, record:reviewer)
- Action matrix (endpoint → required scope + role)
- Типичные профили (consumer, maker, reviewer, publisher, admin)
- Composite role 'ordinis:admin' для one-shot assignment
- Keycloak setup инструкция (Admin Console шаги)
- Диагностика типичных 403 ошибок

toc.yaml — link в раздел Руководство оператора.
operator/index.md, reviewer/index.md — cross-references к rbac.md.

Покрывает Phase 1d enforcement (MR !162) — пользователи теперь
знают какие роли назначать в Keycloak realm 'nstart'.
2026-05-13 12:47:50 +03:00
Zimin A.N. c5b00ff623 refactor(auth): domain-specific role names (consistent convention)
User feedback: универсальный 'ordinis:approver' отступал от convention
'ordinis:<domain>:<action>'. Меняю на domain-specific:

WorkflowRoles constants:
- APPROVER → SCHEMA_REVIEWER ('ordinis:schema:reviewer')
- PUBLISHER → SCHEMA_PUBLISHER ('ordinis:schema:publisher')
- Новая RECORD_REVIEWER ('ordinis:record:reviewer')

Applied:
- SchemaDraftService.decide() → require SCHEMA_REVIEWER
- SchemaDraftService.publish() → require SCHEMA_PUBLISHER
- DraftService.approve() / .reject() → require RECORD_REVIEWER

Frontend usePermissions.ts:
- ROLE_APPROVER + ROLE_PUBLISHER → ROLE_SCHEMA_REVIEWER +
  ROLE_SCHEMA_PUBLISHER + ROLE_RECORD_REVIEWER
- Новый hook useCanReviewRecord() для record draft actions

Keycloak setup (updated):
- ordinis:schema:reviewer
- ordinis:schema:publisher
- ordinis:record:reviewer
(Composite role 'ordinis:admin' = all три + scope roles — для удобства.)
2026-05-13 12:44:23 +03:00
Zimin A.N. 24aa94d130 feat(auth): Phase 1d — backend role enforcement для workflow
User explicitly requested 'Phase 1d пора'. До этого MR'а backend гейтил
только maker-checker (self_approve_forbidden), frontend hooks возвращали
auth.isAuthenticated.

Реализация:

Backend WorkflowRoles (ordinis-rest-api/auth/WorkflowRoles.java):
- Component reads realm_access.roles из JWT claim
- Constants: ordinis:approver (decide/approve/reject), ordinis:publisher (publish)
- requireRole(role) throws 403 forbidden_role если missing
- Defensive parse: malformed/missing realm_access → empty roles
- 9 unit tests cover authenticated + anonymous + malformed JWT

Applied gates:
- SchemaDraftService.decide() — require ordinis:approver
- SchemaDraftService.publish() — require ordinis:publisher
- DraftService.approve() — require ordinis:approver
- DraftService.reject() — require ordinis:approver

WorkflowRoles is Optional в test ctors → unit tests без auth setup
не ломаются. Все existing tests должны проходить (legacy ctor overloads
сохранены).

Frontend usePermissions.ts:
- Stub return auth.isAuthenticated заменён на real role decode из
  auth.user.profile.realm_access.roles
- ROLE_APPROVER + ROLE_PUBLISHER constants exported
- Defensive parsing — graceful с missing/malformed claims
- useCanCreateSchemaDraft остаётся permissive (любой auth — maker'ом
  может быть anyone, scope ACL заведует видимостью)

Naming convention — colon-separated (consistent с ordinis:client:*
scope ролями), aligned с MR !161.

MIGRATION (BREAKING без правильной Keycloak setup):
1. Keycloak realm 'nstart' → Realm Roles → Create:
   - ordinis:approver
   - ordinis:publisher
2. Users → assign roles:
   - reviewer/approver users → ordinis:approver
   - publisher users → ordinis:approver + ordinis:publisher
3. После refresh JWT (logout/login) роли появляются в realm_access.roles

Без этого все decide/publish операции вернут 403 forbidden_role.
2026-05-13 12:36:53 +03:00
Александр Зимин 8bc6916dbf Merge branch 'chore/rename-schema-roles-colon-convention' into 'main'
chore(auth): rename schema workflow roles к colon-convention

See merge request 2-6/2-6-4/terravault/ordinis!161
2026-05-13 09:29:51 +00:00
Zimin A.N. 1281654d32 chore(auth): rename schema workflow roles к colon-convention
Project uses Altum-style colon-separated realm roles:
- ordinis:client:public / internal / restricted (scope ACL, уже active)

Schema workflow roles (Phase 1d TODO) приводим к той же convention:
- ordinis:schema:reviewer (был ordinis-schema-reviewer)
- ordinis:schema:publisher
- ordinis:schema:maker

Изменения в usePermissions.ts:
- JSDoc обновлён с новой convention
- Constants ROLE_SCHEMA_* для discoverable rename'а в Phase 1d
- TODO comments указывают на constants, не bare strings

Phase 1d (когда подключится backend role check):
1. Uncomment role check в hooks
2. Backend SchemaDraftService.decide() — require role
2026-05-13 12:27:33 +03:00
semantic-release-bot dc556d12c8 chore(release): v2.16.4
## [2.16.4](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.16.3...v2.16.4) (2026-05-13)

### 🐛 Fixes

* **ui:** shared UserCell для display UUID actor'ов везде ([e6294ce](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/e6294ce79cc07c6f57c8d45e81a92507e01bb97b))
* **ui:** кнопки в schema draft drawer — RU label + flow row ([6ee88a8](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/6ee88a86bd32cfaa34ceb8dee140c00e629172b8))
2026-05-13 08:53:35 +00:00
Александр Зимин 97c2835bcf Merge branch 'fix/user-display-helper-reviews-audit' into 'main'
fix(ui): shared UserCell для UUID actor display (reviews + audit + drawer)

See merge request 2-6/2-6-4/terravault/ordinis!160
2026-05-13 08:48:00 +00:00
Zimin A.N. 6ee88a86bd fix(ui): кнопки в schema draft drawer — RU label + flow row
User feedback (screenshot): 'Approve' остался английским в RU локали +
'Отозвать' улетал на отдельную строку справа из-за ml-auto.

Fix:
- i18n.ts: 'workflow.schemaDraft.actions.approve' default 'Approve' →
  'Одобрить'. EN остался 'Approve'.
- SchemaDraftDrawer.tsx: убрал ml-auto на withdraw button. Раньше это
  force pushed его в конец строки → flex-wrap отправлял на новую строку
  правым краем. Сейчас withdraw сидит сразу после reject в той же
  flow-row, с danger color для визуальной distinction. На узком экране
  всё ещё wrap'нется естественно (без 'плавающего' alignment).
2026-05-13 11:45:29 +03:00
Zimin A.N. e6294ce79c fix(ui): shared UserCell для display UUID actor'ов везде
Browser QA на staging показал что UUID actor'а render'ится raw во многих
местах кроме drawer (MR !158 — там был inline fix):
- /reviews Records tab — column AUTHOR
- /reviews Schemas tab — column AUTHOR
- /audit log — column USER

77ec2cc8-98e3-4d70-8037-94038fcbde67 — нечитаемо для оператора. Тот же
паттерн что я делал в MR !158, теперь shared helper:

src/lib/useUserDisplay.tsx:
- useUserDisplay(uuid) hook — returns { display, isMe, fullId }
- UserCell component — readonly cell с title=fullId tooltip
- Match current user (JWT sub claim) → 'Я • <preferred_username>'
- Other user → short UUID (8 chars) + full в title
- null/undefined → 'anonymous'

Применено:
- reviews.tsx:334,625 — records + schemas table AUTHOR cells
- audit.tsx:476 — USER cell
- SchemaDraftDrawer.tsx — refactor (был inline в MR !158 → теперь shared)

TODO Phase 1d: backend endpoint /admin/users/{sub}/display чтобы и для
не-current-user отображать username.
2026-05-13 11:43:04 +03:00
semantic-release-bot 38764648bf chore(release): v2.16.3
## [2.16.3](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.16.2...v2.16.3) (2026-05-13)

### 🐛 Fixes

* **sidebar,audit:** badges для Outbox + Webhooks, clarify audit scope label ([aec2cdd](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/aec2cdd644b8d6bf1846f0d26d1485ef669f5f98))
* **types:** SchemaReviewQueuePage.total → totalElements (match backend) ([aecd65e](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/aecd65e7d57a6853bf0744571da246d6db236071))
2026-05-13 08:10:21 +00:00
Александр Зимин 6e5691028b Merge branch 'fix/schema-review-queue-page-total-field' into 'main'
fix(sidebar,audit): badges fix + outbox/webhooks counts + clarify audit scope label

See merge request 2-6/2-6-4/terravault/ordinis!159
2026-05-13 08:05:15 +00:00
Zimin A.N. aec2cdd644 fix(sidebar,audit): badges для Outbox + Webhooks, clarify audit scope label
Sidebar:
- Outbox: бэйдж = outbox.pending (события queued, не отосланы). DLQ
  отдельно — alarming но не actionable из бэйджа, видно на /outbox.
- Webhooks: бэйдж = count активных subscriptions (w.active === true).
  User feedback: 'вебхуки активные есть а цифры с бэйджем нет'.

Audit log column header:
- 'Scope' → 'Доступ актора' (ru) / 'Actor scope' (en)
- Backend audit_log хранит userScope (claim из JWT актора), НЕ scope
  изменённого ресурса. User confusion: 'правки в public были а тут
  RESTRICTED' — потому что у пользователя scope-привилегия RESTRICTED.
  Уточнённая label убирает путаницу.
- TODO: backend feature — добавить dictionaryScope в AuditEntry чтобы
  показать обе ('Актор: RESTRICTED → Ресурс: PUBLIC' — двусторонний
  audit trail для compliance).
2026-05-13 11:03:47 +03:00
Zimin A.N. aecd65e7d5 fix(types): SchemaReviewQueuePage.total → totalElements (match backend)
User reported бэйдж 'Согласований' в sidebar показывал 0 несмотря на 1
pending schema draft. Root cause:

Backend сериализует Spring Page<SchemaDraft> как:
{items, page, size, totalElements, totalPages}

Но TS type SchemaReviewQueuePage объявлял поле как 'total' (mismatch
именования). Consumers читали data?.total → undefined → fallback 0:

- useReviewsBadgeCount (queries.ts:650) — sidebar badge падал на 0
- reviews.tsx:61 — header count в Schemas tab (но fallback на
  items.length скрывал bug в UI)
- reviews.tsx:593-594 — schema queue subtitle 'N drafts ждут ревью'

Fix:
- client.ts SchemaReviewQueuePage: total → totalElements + totalPages
- 3 consumer'а обновлены на .totalElements
- Backend контракт не меняется — это чисто frontend type alignment

После prod deploy v2.16.3 sidebar badge заработает корректно.
2026-05-13 10:58:48 +03:00
semantic-release-bot 894fcea81b chore(release): v2.16.2
## [2.16.2](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.16.1...v2.16.2) (2026-05-13)

### 🐛 Fixes

* **schema-draft:** автор display + gate Отозвать только maker'у ([fbf978a](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/fbf978aa397b66a309fafb35caa611e3f73164b8))
* **sidebar:** подключить reviews badge к real count ([252939f](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/252939f63a9c997b94603aefa43b9bae287f3eb3))
2026-05-13 07:46:14 +00:00
Александр Зимин 441bbedadf Merge branch 'fix/schema-draft-author-display-and-withdraw-gate' into 'main'
fix(schema-draft): author display + gate Отозвать только maker'у

See merge request 2-6/2-6-4/terravault/ordinis!158
2026-05-13 07:39:59 +00:00
Александр Зимин 137c07c9e4 Merge branch 'fix/sidebar-reviews-badge-count' into 'main'
fix(sidebar): подключить reviews badge к real count

See merge request 2-6/2-6-4/terravault/ordinis!156
2026-05-13 07:35:03 +00:00
Zimin A.N. fbf978aa39 fix(schema-draft): автор display + gate Отозвать только maker'у
Два бага в SchemaDraftDrawer (видны на review pending):

1. АВТОР показывал raw UUID (77ec2cc8-98e3-4d70-8037-...). Резолвим:
   - Если maker = current user (JWT sub claim) → 'Я • <preferred_username>'
   - Иначе → short UUID (первые 8 символов) с full в title attribute
   - Стилизация: 'Я' — text-ink (читаемая), чужой — font-mono text-mute
   - TODO Phase 1d: backend endpoint для resolve чужих sub → display name

2. Кнопка 'Отозвать' показывалась всем юзерам, не только автору.
   - Backend всё равно 403'нет non-maker withdraw — но UI confusion:
     reviewer видел кнопку которая всегда fail'ит.
   - Gate: показываем только когда auth.user.profile.sub === draft.makerId.
   - Reviewer теперь видит чистый action row (Approve / Запросить правки /
     Отклонить), без danger-button мимо контекста.

Реальный случай: см. user screenshot на v2.16.x — Reviewer modal с UUID
автора и кнопкой 'Отозвать' справа внизу.
2026-05-13 10:33:02 +03:00
Александр Зимин 354561f192 Merge branch 'ci/remove-nstart-runner-tag' into 'main'
ci: remove nstart tag из default runner constraint

See merge request 2-6/2-6-4/terravault/ordinis!157
2026-05-13 07:30:48 +00:00
Zimin A.N. a0236c38e8 ci: remove nstart tag из default runner constraint
Раньше все jobs pin'ились к runner'ам с tag 'nstart' (выделенный pool).
Runner topology обновлена — все available runner'ы equally provisioned,
сегрегация по тегам больше не нужна.

После remove'а jobs scheduler'ятся на любого available runner'а →
быстрее picks-up в часы пик когда nstart runner был busy. Parallel
docker-* serialize'я по-прежнему работает через resource_group:
docker-builds-v2 (см. .docker_base).
2026-05-13 10:27:54 +03:00
Zimin A.N. 252939f63a fix(sidebar): подключить reviews badge к real count
Бэйдж 'На ревью' в sidebar (desktop + mobile) был захардкожен в 0 —
TODO comment ждал cheap /drafts/pending/count endpoint. На самом деле
existing /admin/reviews/pending и /admin/schema-reviews/pending уже
возвращают paged response с totalElements/total в metadata — request
size=1 даёт нужный counter с минимальным payload (~1 строка + 4
metadata field'а).

Новый hook useReviewsBadgeCount():
- Параллельно дёргает обе queue (record + schema)
- Суммирует totalElements (record) + total (schema)
- Полл каждые 60s (lighter чем 30s queue refresh — badge не critical)
- Gated на auth.isAuthenticated (anonymous не должен дёргать admin endpoint'ы)

Sidebar.tsx (оба варианта — desktop + mobile MobileSidebar):
- reviewsCount: 0 → reviews.total
2026-05-13 10:08:57 +03:00
Александр Зимин 0d157de803 Merge branch 'ci/forbid-skip-ci-literal' into 'main'
ci(lint): forbid literal skip-ci marker в commit messages

See merge request 2-6/2-6-4/terravault/ordinis!155
2026-05-12 22:00:45 +00:00
Zimin A.N. 41aa26b7f8 ci(lint): только MR pipeline'ах, не branch-push
Branch-push pipeline сканировал HEAD~10..HEAD range — включал исторические
commit'ы (например b7e1f12 из MR !154 который сам и привёл к появлению
этого lint'а) → false fail на legacy commits которые уже в main.

MR pipeline использует CI_MERGE_REQUEST_DIFF_BASE_SHA..HEAD — только новые
commit'ы данного MR'а. Это правильный gate: contributor opens MR → lint
валидирует только новый код → fail/pass без noise от старого.

Pipeline 6833 (branch ci/forbid-skip-ci-literal) демонстрирует проблему —
поймал historical commit вместо проверки нашего MR-fix'а.
Pipeline 6834 (MR !155) прошёл — это правильное поведение.
2026-05-13 00:58:39 +03:00
Zimin A.N. 1da515276c ci(lint): forbid literal skip-ci marker в commit messages
GitLab платформа skip'ает pipeline на любом commit'е чей subject или body
содержит pattern с square brackets вокруг 'skip ci'. Trap: semantic-release
включает release notes из всех commit'ов в release commit body — если хотя
бы один commit имеет этот pattern в subject/body, release tag pipeline
скипается → нет images → нет auto-PR.

Реальный случай: v2.16.1 — commit fix(release): 'remove ... из semantic-
release commit message' содержал паттерн дословно. Pipeline 6831 (v2.16.1
tag) skipped → пришлось trigger через API.

Новый CI job 'commit-msg-lint' (stage: test):
- Запускается на MR pipeline'ах и feature-branch push'ах
- Скипает chore(release) commit'ы (semantic-release auto-bot)
- Для каждого commit'а в range проверяет subject+body на square-bracket
  skip-ci pattern
- Fails CI с ясной подсказкой (как переформулировать) при match

RELEASE.md обновлён с разделом 'Skip-ci marker trap': примеры
правильных формулировок (skip-ci marker, the directive, etc) и
escape hatch (manual API trigger).
2026-05-13 00:54:19 +03:00
semantic-release-bot 1e5e6b59cb chore(release): v2.16.1
## [2.16.1](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.16.0...v2.16.1) (2026-05-12)

### 🐛 Fixes

* **ci:** use printf для commit/MR description avoiding YAML literal block break ([cac6b6a](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/cac6b6a98180faab308594912248a26e01f2f97a))
* **release:** remove [skip ci] из semantic-release commit message ([b7e1f12](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/b7e1f12bc47031f7a1b817a2d025d5472712220e))
2026-05-12 21:39:15 +00:00
Александр Зимин 75474bca45 Merge branch 'ci/auto-pr-prod-image-bump' into 'main'
ci(release): auto-PR в ordinis-infra с image tag после release

See merge request 2-6/2-6-4/terravault/ordinis!154
2026-05-12 21:33:04 +00:00