Files

7.3 KiB
Raw Permalink Blame History

TODOS

Design debt and follow-ups surfaced by /plan-design-review of the approval workflow UX (2026-05-14). Each entry is self-contained: pick one up and read the Context to understand the motivation without re-running the review.

Session summary 2026-05-14 — all original TODOs closed

# Title Status Artifact
1 "Мои" tab on /reviews shipped MR !188 (v2.25.1)
2 Interaction state polish (5 fixes) shipped MR !189 (v2.26.0)
5 DESIGN.md baseline shipped DESIGN.md v0
6 A11y audit on staging findings captured 10 issues P0P3 (fix loop = follow-up polish MR)
7 Notifications: toast + email + bell shipped MR !190 (v2.26.x)

New follow-up: TODO 6 punch list → groupy fix MR. ~15 LOC each except touch-target sweep across TopBar + Sidebar + Tabs components.


1. /reviews "Мои" tab — maker visibility SHIPPED MR !188

Closed via MR !188 (2026-05-14). Final shape: flat mixed timeline (records

  • schemas together sorted DESC), filter chips All/Pending/WIP/Decided with per-bucket counts, ReviewDrawer status-aware (read-only decision banner for terminal states, Withdraw for own-pending). 13 unit tests on classifiers + 32 i18n keys. Schema rows link to /dictionaries/$name (existing drawer there); record rows reuse ReviewDrawer with status-gated footer.

2. Interaction state pass — reviews page polish SHIPPED MR !189

Closed in MR !189 — all 5 fixes in one MR:

  1. Records empty state — icon + description + audit link
  2. Reject reason inline validation — aria-invalid + role=alert
  3. SchemaDraftDrawer empty state — QueryErrorState для errors + dashed block для no-draft
  4. Approve/reject success flash — 600ms green/pink band before close
  5. Bulk failed reasons humanized — extracted humanizeBulkReason() lib + 7 unit tests

5. DESIGN.md for the admin UI SHIPPED v0 baseline

Authored as DESIGN.md at repo root (2026-05-14). 12 sections covering: voice & tone, color tokens (3 themes), typography, spacing/layout, component primitives, badge variant mapping (operations / record status / schema status / notifications), code/diff visual language, interaction states, term glossary, RBAC, AI slop anti-patterns, open items для future /design-consultation sprint.

Full /design-consultation skill run deferred — v0 captures observed patterns as fact-based source of truth; later sprint can refine policy gaps listed in Section 12 (responsive breakpoints, motion durations, loading state taxonomy, etc.).


6. A11y audit post-deploy via /design-review Punch list captured 2026-05-14

Ran focused live audit on https://ordinis.k8s.265.nstart.cloud/reviews (staging v2.25.x, anonymous + read-only state). Findings captured below; fix loop deferred to standalone polish MR.

P0 — Severe

  • A11y-1: Bell badge "9+" lacks contextual aria-label. Screen reader reads literal "9+" without "unread notifications" context. The <span> carrying the digit needs its own aria-label={t('notifications.unreadCount', {count})}. TopBar.tsx NotificationsBell. (Already addressed in MR !190 — verify in deploy.)
  • A11y-2: i18n leak — "СВЕРНУТЬ" hardcoded RU. When EN locale active (sidebar reads Home/Dictionaries/Search), sidebar collapse button at bottom still shows " СВЕРНУТЬ". Either missing translation key or hardcoded label. Find in Sidebar.tsx near collapse handler.

P1 — High

  • A11y-3: Touch targets below WCAG 44×44 minimum. Measured on staging:
    • Bell button: 28×28
    • Theme switches (Light/Dark/System): 28×26
    • Lang switch button "EN": 37×28
    • Sidebar nav items: ~32px tall
    • Tabs: 78×40 (Records) and 112×40 (Schemas) — height below 44
    • "Open →" action link in schema queue row: ~50×18 (text link only) Mobile/touch use is uncomfortable. Add min-h-[44px] to icon buttons in TopBar + Sidebar footer. Tab height needs h-11 instead of h-10.
  • A11y-4: UserCell raw UUID fallback ugly when fetch fails. 77ec2cc8 shown literally in AUTHOR column when the user-display lookup 401s (anon) or returns empty. Fall back to t('user.unknown') ("Неизвестный пользователь") instead of UUID slice.
  • A11y-5: No aria-live on tab panel. Switching Records → Schemas → Mine doesn't announce content change to screen readers. Add aria-live="polite" on the panel container or rely on Radix <Tabs.Content> which already manages focus.

P2 — Medium

  • A11y-6: Radix Tabs inline style="outline:none". Tablist has style="outline: none" inline that defeats default focus ring. Verify :focus-visible styling kicks in for keyboard nav — if not, remove the inline override or add a Tailwind focus ring.
  • A11y-7: Anonymous Mine tab handling. Need to verify what happens for unauthenticated user clicking Mine — should redirect to /sign-in or render "Sign in to see your drafts" empty state (current behavior likely error toast or blank query).
  • A11y-8: Description text has no max-width. "Pending drafts from makers awaiting…" body copy stretches to viewport edge on wide screens (>1440px). Apply max-w-prose for readable measure (45-75 chars).

P3 — Polish

  • A11y-9: Column header tracking-wide ALL CAPS ("DICTIONARY", "FROM VERSION", "AUTHOR") creates uneven scan rhythm against lowercase data rows. Verify against design tokens — likely intentional cap-style but worth a visual review at narrow widths.
  • A11y-10: "Open →" link should be Button. It's a text Link in Action column; better as a Button variant="ghost" to align with the existing Records tab "Review" CTA pattern.

Status

Punch list compiled. Fix loop deferred — group into separate "a11y polish" MR after current notifications work (!190) lands. Most fixes are 2-5 LOC each except touch-target sweep which touches 5+ components.


7. Notifications service: draft decision toast + email SHIPPED MR !190

Closed in MR !190.

Backend (ordinis-notifications + ordinis-rest-api + ordinis-app):

  • NotificationsDispatcher — mirrors WebhookDispatcher pattern, reads outbox events of type RecordDraftApproved/Rejected/Withdrawn/Submitted, fan-outs via IdempotencyGuard + EmailChannel
  • UserDisplayPort SPI in notifications module (anti-corruption layer)
  • NotificationsUserDisplayBridge wires port → UserDisplayService in ordinis-app (avoids circular dep)
  • MeNotificationsController GET /api/v1/me/notifications + POST /{id}/read + /read-all
  • Migration 0024 notification_read_state(user_id, notification_id, read_at)
  • 5 unit tests (mock-maker-subclass for Java 25 compat)

Frontend:

  • useMyNotifications query (30s refetch + background poll for badge)
  • useMarkNotificationRead + useMarkAllNotificationsRead mutations
  • NotificationsDrawer right-side drawer with per-row mark-read + footer mark-all
  • NotificationsBell replaces placeholder — unread badge (capped "9+") + delta-toast on poll-detected new arrivals when drawer closed
  • 14 ru-RU + 14 en-US i18n keys

Email templates already existed (draft_submitted, draft_decision, draft_withdrawn) in notifications_{ru,en}.properties — reused as-is.