fe7f9cd01f
Acts on the two "build now" items from the design review of the approval
workflow UX (other five went to TODOS.md). Plus the TODOS.md file itself,
authored during the same review.
1. **Inline "Создать черновик с моими изменениями" CTA**
(DictionaryEditorDialog + CreateSchemaDraftModal)
Was: when a maker edited an approval-required dict, Save disabled and a
warning told them to "close the editor and click 'Создать черновик схемы'
on the dict page." Three friction steps and a hunt for a button.
Now: the warning Alert carries an action button — "Создать черновик с
моими изменениями" — that opens CreateSchemaDraftModal in-place with the
maker's in-progress schemaJson pre-loaded. They add a reason and submit.
No retyping, no hunt.
Implementation:
- CreateSchemaDraftModal accepts optional `initialProposedSchema` prop.
Seed order: edit-mode draft → caller pre-fill → live HEAD.
- DictionaryEditorDialog mounts the modal inline and triggers it from the
Alert action. Closes the editor on successful create.
2. **Diff summary chips in ReviewDrawer**
Was: two raw JSON dumps side by side. Reviewer had to eyeball-diff long
records to find the actual edit.
Now: a row of summary chips above the panes — "+N added, −M removed,
~K changed" with the field names inline. Computed shallow client-side
(shallowDiffSummary helper) — ordinis records are flat-ish at the top
level, no need for a backend diff endpoint. Skipped for CLOSE op (no
proposed) and when both sides are null.
3. **Tightened drawer header + trimmed empty-state copy**
Was: single flex-wrap line with four spans (badge + bk + maker + ts) —
visually busy. Plus a verbose empty-state description: "Когда maker
отправит schema draft на ревью, он появится здесь."
Now: two-row layout (identity row on top, provenance row below) so the
eye lands on Badge + BK first. Empty-state copy shortened to "Очередь
пуста" / "Схемы на ревью появятся здесь."
Other five gaps (Мои tab, full state-coverage pass, DESIGN.md, a11y audit,
maker notifications) recorded in TODOS.md.
160 lines
6.9 KiB
Markdown
160 lines
6.9 KiB
Markdown
# 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 `<EmptyState title={t('reviews.empty')} />`
|
|
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 `<pre>` 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.
|