semantic-release провалился с 'HTTP Basic: Access denied' потому что:
1. CI default git remote использует CI_JOB_TOKEN scope — не может push'ить
tags/commits в protected refs (main branch).
2. GITLAB_TOKEN ещё не настроен в Settings → CI/CD → Variables.
3. Без explicit git remote rewrite semantic-release/git plugin падает
с cryptic 'Authentication failed' вместо понятного 'token missing'.
Fixes:
- before_script: fail-fast если GITLAB_TOKEN пустой — печатает setup
инструкцию (write_repository + api scopes, Masked + Protected flags)
и exit 0. Pipeline не краснеет (allow_failure: true).
- git remote set-url origin https://gitlab-ci-token:${GITLAB_TOKEN}@... —
переопределяет default remote чтобы git push мог работать с
Project Access Token'ом.
- git config user.email/name — semantic-release commit author.
После настройки GITLAB_TOKEN в GitLab UI следующий push в main создаст
первый авто-tag (v1.3.0 minimum по conventional commits с момента v1.2.2).
Реальные измерения через DevTools на staging выявили 3 бага после MR !47:
Bug 1: text-title-md/lg/xl inherited Tektur от @nstart/ui Card parent.
Handoff: 'Inter for all headings'. Computed: Tektur.
Fix: добавил font-family: var(--font-sans) explicit на text-title-*
и text-body/text-cell. После Stage 3.9 (nstart gone) можно убрать —
body inherit будет достаточно.
Bug 2: text-cap + font-mono cohabit (catalog scope chips, time-travel
presets) → Tailwind v4 cascade order: font-mono идёт после text-cap
в bundled CSS → JetBrains Mono перебивает Tektur. text-cap baked
font-display, font-mono token redundant.
Fix: codemod strip font-mono где есть text-cap (4 sites). Computed
font-family теперь правильно Tektur.
Bug 3: @nstart/ui PageHeader рендерил h1 'DICTIONARIES' в Tektur
36px/700 uppercase (font-primary text-4xl). Handoff page title:
17px/600 Inter normal case. Наш src/ui/components/page-header.tsx
написан но не экспортирован через barrel — все routes резолвили
PageHeader к nstart версии.
Fix: добавил 'export { PageHeader }' override в src/ui/index.ts.
Все 7 PageHeader usages (catalog/search/reviews/webhooks/outbox/
my-drafts/graph) теперь получат handoff-conformant heading.
Bug 4 (small): catalog counter '37/37' использовал text-cap но это
numeric value — handoff role text-mono (11px JetBrains Mono).
Fix: text-cap → text-mono + tabular-nums для grid alignment.
Verified via injected test elements + CDP computed styles:
text-title-xl: 22/600 Inter
text-title-lg: 17/600 Inter
text-title-md: 15/600 Inter
text-body: 13/400 Inter
text-cell: 12.5/500 Inter
text-mono: 11/500 JetBrains Mono
text-cap: 10.5/600 Tektur
Все 7 utilities точно matches handoff scale.
Files: 4 modified. TS strict + 116 tests pass.
Закрывает эту тему окончательно. После merge в main CI анализирует
conventional commits с последнего tag'а, бампит package.json + CHANGELOG.md
и пушит git tag vX.Y.Z. Tag pipeline далее собирает images и ждёт
manual gate на trigger-deploy-prod.
Что добавил:
- ordinis-admin-ui/.releaserc.json — config (commit-analyzer, release-notes,
changelog, npm[no-publish], git, gitlab). branches: ['main']. Маппинг
conventional-commit types к bump levels.
- ordinis-admin-ui/package.json — devDeps: semantic-release@24.2 + 6 plugins.
- .gitlab-ci.yml — new 'release' stage + release job:
- needs: trigger-deploy-staging (release ТОЛЬКО после зелёного staging)
- image: node:22-alpine + pnpm@9.15.4
- GL_TOKEN из CI variable GITLAB_TOKEN (semantic-release/gitlab требует
именно GL_TOKEN env name)
- allow_failure: true (нет релизных commits = OK, не блокирует pipeline)
- RELEASE.md — operator docs:
- One-time setup: создать Project Access Token + GITLAB_TOKEN CI var
- Commit conventions table (feat→minor, fix→patch, breaking→major)
- Skip release (use chore: type или [skip ci])
- Dry-run command для local validation
Prod safety: trigger-deploy-prod остаётся manual (when: manual). Автоматизация
ТОЛЬКО tag-создания, не deploy. Tag → CI runs → human кликает Deploy.
ACTION REQUIRED от user (one-time):
1. GitLab → Settings → Access Tokens → создать Project Access Token
scopes: write_repository + api, role: Maintainer
2. GitLab → Settings → CI/CD → Variables → GITLAB_TOKEN (Masked, Protected)
Без этого release job будет fail'ить (но pipeline не покраснеет — allow_failure).
Stale package.json создавал ложное впечатление rollback'а: staging
показывал "v1.2.0" хотя последний tag — v1.2.2 (package.json не bump'ился
со времён v1.2.0 release).
Vote A — branch builds НЕ используют package.json как version label.
Vite определяет channel:
serverTag != none → что прод/staging RUNS
clientTag → что build'ил CI tag pipeline (CI_COMMIT_TAG set)
CI без tag → 'dev' literal (staging / branch CI build)
локально → 'local' literal (pnpm dev)
Detection через новый __APP_CI__ define из process.env.CI (GitLab сетает
CI=true). Local pnpm dev: CI undefined → channel='local'.
package.json.version всё ещё инжектится как __APP_VERSION__ и видна в
tooltip badge'а как 'floor vX.Y.Z' — не как primary label.
Files:
- vite.config.ts: + APP_CI from process.env.CI
- src/vite-env.d.ts: + __APP_CI__ declare
- src/components/version/useAppVersion.ts: + clientCI
- src/components/version/VersionBadge.tsx: channel logic вместо fallback
Verify all three modes:
local → 'local · {commit}'
CI branch → 'dev · {commit}'
CI tag v1.3.1 → 'v1.3.1 · {commit}'
Tests: 116 pass.
Dictionary editor route теперь имеет TabBar (handoff design Stage 3.4):
Records | Relations | Fields | JSON | Events | History
URL-synced через ?tab= (default: records). Backward-compat: старый
?view=hub auto-remap'нется в ?tab=relations при mount'е.
Tab contents:
- records (default): существующий records table + filters + edit modal
flow — без изменений, обёрнут в conditional render
- relations: DictionaryHubView (был раньше при view=hub)
- fields: schema properties summary — name/type/required/unique/i18n/FK/desc
- json: pretty-printed schemaJson read-only
- events: link к /audit с pre-filled dict filter
- history: placeholder (schema version timeline — backend endpoint pending)
EditorTabBar — inline component с handoff styling (border-b border-line +
active accent border + font-semibold), -mb-px overlap для clean look.
Hub view's neighbor cards теперь search={tab:'relations'} вместо
view='hub' (consistent с new param).
DictionaryDependentsPanel рендерится только в Records tab — auto Hub view
в Relations tab уже включает dependents через свой layout.
Tests: 116/116 PASS, build green, TS clean.