# 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. --- ## 1. `/reviews` "Мои" tab — maker visibility **What.** Add a third tab "Мои" on the `/reviews` page with three sub-sections: Pending (drafts awaiting review), Decided (drafts that received a verdict), WIP (drafts the maker started but did not yet submit). **Why.** Today the maker has no surface to see "where are my drafts?". MR !170 added the backend (`listByMaker` + analogous schema endpoint), but the UI never got the entry point. Reviewer's queue mixes records and schemas — symmetric "my drafts" view is missing. **Pros.** Reuses `/reviews` page chrome. Backend endpoints already exist. Closes the loop on the maker journey ("submit → ??? → ..." now has a destination). **Cons.** Adds two more list queries to the page. Need to think about whether the existing reviewer "Записи / Схемы" toggle nests inside "Мои" too (so 6 panels total) or "Мои" is flat. **Context.** Review pass 1 rated information architecture 6/10 specifically because maker visibility was missing. User chose "third tab on /reviews" over a separate `/my-drafts` route — keeps everything in one place. **Depends on / blocked by.** Nothing — endpoints live (`/admin/dictionaries/*/drafts?makerId=...` and analogous for schemas). --- ## 2. Interaction state pass — reviews page polish **What.** One MR covering five small fixes: - Records empty state: add description + primary action ("Queue is clear, see /audit for past decisions"). Current `` is just a heading. - Reject reason inline validation: today `handleReject` does `if (!comment.trim()) return` silently. Button click → nothing happens. Show inline error or set the TextArea into error state. - Drawer empty state (`workflow.schemaDraft.empty`): distinguish "not loaded", "not found" (deleted), "no permission". Today the same blank message covers all three. - Approve action: drawer closes immediately on success. Add a 500ms success state (or toast) so the reviewer gets visual confirmation. Currently feels like the click might not have registered. - Post-bulk-result polish: the `bulkResult` Alert lists business keys but the failed list shows raw `reason` codes (`self_approve_forbidden`, `draft_not_pending`). Map through `extractReviewError` already in the file. **Why.** Pass 2 rated state coverage 5/10. These are the visible gaps. Each is 10-30 LOC; the value is interaction confidence. **Pros.** All in one place — `reviews.tsx`, `SchemaDraftDrawer.tsx`. Low risk. **Cons.** Five different surfaces in one MR means review surface is wider than a single-purpose change. Still worth grouping because they're all "state polish" semantically. **Context.** Pass 2 finding. None of these block functionality; they're trust builders. Reject silent fail is the most user-visible — a reviewer clicks the button and nothing happens, then notices the TextArea is empty after a beat. **Depends on / blocked by.** Nothing. --- ## 5. DESIGN.md for the admin UI **What.** Run `/design-consultation` skill or stub DESIGN.md manually to lock the implicit design system: drawer-vs-modal usage rules, term glossary (maker / reviewer / publisher and their Russian counterparts), Badge variant mapping (CREATE → success, UPDATE → info, CLOSE → warning — already used consistently but undocumented), code panes pattern (live = `bg-line/30`, proposed = `bg-accent/4`). **Why.** Pass 5 rated design system alignment 4/10. The system *exists* — design tokens are used consistently — but it's tribal knowledge. Next developer building a feature like "Phase 4 webhook approvals" will guess and either match by luck or drift. **Pros.** Half-day work. Pays off on every new feature. Source of truth for `/plan-design-review` calibration on future plans. **Cons.** Documentation has to be maintained or it lies. Mitigated by keeping DESIGN.md to invariants (tokens, primitives, semantic rules), not specific components. **Context.** User chose "defer to /design-consultation sprint" instead of stubbing inline. The decision is to do it properly when the sprint happens, not piecemeal during this review. **Depends on / blocked by.** Nothing. --- ## 6. A11y audit post-deploy via `/design-review` **What.** After the in-flight approval workflow MRs deploy to staging, run `/design-review` skill against the live `/reviews` page + DictionaryEditorDialog flow. The skill does Lighthouse, axe, screen reader walk-through, contrast audit, keyboard navigation testing. **Why.** Pass 6 rated responsive/a11y 5/10. Specific suspects: - Button heights not verified at 44px touch target. - `text-mute` contrast against `bg-surface` — might fail WCAG AA 4.5:1. - Reject reason TextArea has no specified `minHeight`. - Bulk action toolbar wrap behavior at 375px. - Diff `
` panes have no aria-label — screen reader reads JSON literally.
- Keyboard tab order through long diff panes — reviewer may have to tab 50 times
  to reach approve buttons.

**Pros.** Necessary for compliance contexts (gov contracts, accessibility laws).
Catches things static review misses (real screen reader, real touch device).

**Cons.** Requires the in-flight MRs to be deployed first. Cannot do in
plan mode.

**Context.** User chose "defer to /design-review post-deploy". The audit will
produce its own punch list with severity ratings.

**Depends on / blocked by.** MRs !179, !180, !182, !183, !184, !185 deployed
to staging.

---

## 7. Notifications service: draft decision toast + email

**What.** Notifications service subscribes to outbox `RecordDraftApproved /
RecordDraftRejected / RecordDraftWithdrawn` events (now fired thanks to
MR !184) and:

1. Fires email to maker with reviewer comment.
2. Sets a flag (DB or Redis) so on next login the admin UI shows a toast:
   "Your draft for `test1/BK-42` was approved by reviewer X. The record is
   now live."
3. Bell icon in the header gains a badge counter for unread decisions.

**Why.** Maker has no synchronous feedback. They submit, then either:
- Tab "Мои" → Decided (covered by TODO 1) — but only when they come back
- This TODO — push notification so they know without re-visiting

**Pros.** Closes the maker feedback loop. Reuses the outbox infra. Mirrors
existing notification flows in `ordinis-notifications`.

**Cons.** New email template + new in-app toast surface + bell badge. Half-day
to a day of work split between notifications service and admin-ui.

**Context.** Pass 7 unresolved decision. User chose "in-app toast + email via
notifications service" over the lighter "tab badge polling" option. Backend
events already fire (MR !184), so the gate is consumer side.

**Depends on / blocked by.** MR !184 deployed. TODO 1 ("Мои" tab) helps but
is not a hard blocker — the toast and email work without that surface.