Files
mdm-ordinis/DESIGN.md
T
2026-05-14 14:40:35 +00:00

14 KiB
Raw Blame History

DESIGN.md — Ordinis Admin UI Design System

Status: v0 baseline (2026-05-14). Captured from observed patterns в codebase after approval workflow saga (MR !179!190). To be refined через /design-consultation skill in a dedicated sprint.

Goal: Lock the implicit design system как source of truth для будущих features (Phase 4 webhook approvals, notifications surfaces, MDM expansion). Document invariants (tokens, primitives, semantic rules) — NOT specific components.


1. Voice & Tone

  • Russian-first. UI primary language ru-RU; en-US is parallel mirror. Every user-facing string registered in src/i18n.ts.
  • Operational, not aspirational. Copy describes what user sees / does ("Очередь чистая", "Reject требует comment") — no marketing-speak.
  • Domain-precise. Use exact role names (maker / reviewer / publisher) and operation codes (CREATE / UPDATE / CLOSE) — no generic "user".
  • Apologize on failure. Empty states + error messages name what went wrong и what to do next ("Refresh page + retry", "Укажите причину").

2. Color Tokens

CSS variables defined в src/styles.css. Three themes: default (light Anthropic warm), nstart (medium contrast brand), dark (Anthropic dark).

Semantic roles

Token Light Dark Use
--color-ink #1a1714 #f0ece4 Primary text
--color-ink-2 #52483d #c8c1b3 Secondary text
--color-mute #8c8276 #8a8474 Tertiary text / placeholders
--color-bg #faf9f5 #1c1a17 App background
--color-surface #ffffff #262421 Card / panel surface
--color-surface-2 #f5f3ec #2e2b27 Hover / nested surface
--color-line #e6e1d4 #3a3733 Dividers / borders
--color-line-2 #efeae0 #2d2a27 Subtle dividers
--color-accent #b05a2e #d97757 Primary CTA / links
--color-accent-bg accent @ 11% accent @ 16% Accent tint
--color-on-accent #ffffff #1c1a17 Text on accent
--color-green #4f7038 #4a7d4f Success / APPROVED
--color-green-bg #e4ead0 #dde9da Success tint
--color-warn #a8762a #b97c2f Warning / CHANGES_REQUESTED
--color-warn-bg #f6e8bc #fcecc7 Warning tint
--color-pink #a64636 #b34d6a Danger / REJECTED
--color-pink-bg #f4d9cd #f8d8de Danger tint

Rules

  • Never hard-code hex. Use bg-line, text-mute, border-accent через Tailwind utilities mapped to these tokens.
  • Status colors are stable across themes. success always green-family; danger always pink-family.
  • Tint backgrounds (*-bg) use 11-16% alpha — for badge backgrounds and subtle highlights. Never tint at higher opacity (loses contrast).

3. Typography

Font families

Token Stack Use
--font-sans Inter, -apple-system, BlinkMacSystemFont, sans-serif Body, UI
--font-mono JetBrains Mono, SF Mono, monospace Code, UUIDs, business keys, versions
--font-display Tektur, Inter, sans-serif Caps headers, brand mark

Type scale (Tailwind utilities)

Utility Use
text-title-md Section headings (Panel title)
text-body Body copy
text-cell Table cell, dense info
text-cap Caps tracking-wide labels (column headers) — uses --font-display
text-mono Code / monospaced

Rules

  • Mono для identity: UUIDs (truncated slice(0,8)…), business keys, version strings (v1.1.0). Reads as "this is an exact identifier".
  • Display caps для column headers: text-cap text-mute font-display uppercase tracking-wider — visual hierarchy через caps, not size.
  • tabular-nums для timestamp + count columns — prevents jitter on refresh.
  • Never use system-ui / -apple-system as primary display font. Inter is fallback only.

4. Spacing & Layout

Base scale

Tailwind default 4px scale (gap-1 = 4px, gap-2 = 8px, gap-3 = 12px, gap-4 = 16px). Avoid arbitrary spacing values (mt-[13px]) — use scale or extend tokens.

Layout primitives

  • Page chrome: <PageHeader title description> for top of every route
  • Content area: space-y-4 (16px) between top-level sections
  • Panel: <Panel> wraps tables / forms with bg-surface border border-line
  • Card: <Card> для individual content blocks (bg-surface-2)
  • Drawer: Right-side slide-in for detail views (review draft, schema draft, history)
  • Modal: Centered overlay для destructive confirmations + create flows

Drawer-vs-Modal rules

Pattern Use Drawer Use Modal
Review existing entity
Read-only history
Diff side-by-side ✓ (max-w-3xl)
Create new entity
Destructive confirmation ✓ (size=sm)
Maker action requiring focus

Drawer = "look at this thing, maybe act on it". Modal = "do this thing now, then dismiss".

Width caps

  • Drawer: max-w-md (notifications), max-w-xl (schema draft), max-w-3xl (record review with diff panes)
  • Modal: size="sm" (confirm), "md" (form), "xl" (JSON editor)
  • Body copy: implicit via Panel padding; for description text apply max-w-prose если viewport wide

5. Component Primitives

Locations: src/ui/components/*.tsx. Re-exported via @/ui.

Stable primitives (use freely)

  • <Button variant size>primary | secondary | ghost | danger, sm | md | lg
  • <Badge variant>info | success | warning | danger | default | primary | outline
  • <Panel> — surface wrapper для table/form blocks
  • <Card> — content block (lighter surface than Panel)
  • <Drawer isOpen onClose title side widthClassName> — slide-in detail view
  • <Modal isOpen onClose title size> — centered overlay
  • <Table TableHead TableRow TableHeaderCell TableBody TableCell> — tabular data
  • <Tabs items value onValueChange> — Radix-based tabs with badge slot
  • <EmptyState icon title description action> — no-data fallback
  • <Alert variant title> — banner with info | success | warning | error
  • <LoadingBlock size label> — skeleton / spinner
  • <QueryErrorState error onRetry> — generic 4xx/5xx state с retry
  • <UserCell uuid> — resolves sub → display name (three-tier cache)
  • <TextInput TextArea Checkbox Select MultiSelect> — form inputs

Domain-specific (in src/components/)

  • <ReviewDrawer> — record draft review (records tab + Мои tab)
  • <SchemaDraftDrawer> — schema draft review (dict page + Мои tab redirect)
  • <DictionaryEditorDialog> — schema-aware editor с approval flow
  • <MyDraftsPanel> — Мои tab on /reviews
  • <NotificationsDrawer> + <NotificationsBell> — TODO 7 notification surfaces
  • <ChangelogDiffModal> — historical schema diff viewer
  • <TimeTravelModal> — record at point-in-time

6. Badge Variant Mapping

Visual category по semantic role, applied везде через <Badge variant=…>:

Operations (DraftOperation)

Op Variant Color Reason
CREATE success green Net-new record — positive change
UPDATE info accent Most common; neutral default
CLOSE warning warn Soft-delete; destructive but reversible

Record draft status (DraftStatus)

Status Variant Reason
PENDING info Awaiting reviewer action
APPROVED success Terminal positive
REJECTED danger Terminal negative
WITHDRAWN default Maker-initiated cancel, neutral

Schema draft status (SchemaDraftStatus)

Status Variant Reason
draft warning Pre-submit, maker action pending
review_pending info Reviewer queue
approved success Awaiting publish
changes_requested warning Bounced to maker
rejected danger Terminal negative
published primary Terminal live (strongest signal)
withdrawn default Maker cancel

Notification event type

Pattern in eventType Variant
*Approved, *Published success
*Rejected, *Withdrawn danger
*Submitted, *ChangesRequested info
other default

7. Code / Diff Visual Language

Live vs proposed panes

  • Live (current state): bg-line/30 background — muted, "established"
  • Proposed (draft): bg-accent/4 background — accent-tinted, "your suggestion"
  • CLOSE op note: text-aurora italic — call-out пустой proposed pane

Diff summary chips (above panes)

  • +N added: text-aurora (green-family) with + prefix
  • M removed: text-danger with prefix
  • ~K changed: text-warn with ~ prefix
  • Bucket details в text-mute lowercase parens

Rendered via shallowDiffSummary() from src/lib/diff.ts.


8. Interaction States

Required for all interactive elements

  • hover:bg-line/30 или similar hover affordance
  • focus-visible:ring-2 focus-visible:ring-ring focus ring (NEVER outline: none без replacement)
  • disabled:opacity-50 disabled:cursor-not-allowed для disabled
  • Touch target ≥ 44×44 — use min-h-[44px] for icon buttons (current gap; audit findings P1 in TODOS.md TODO 6)

Success / error affordances

  • Mutation success: прокачка через toast.success() (sonner) — auto-dismiss 4s
  • Mutation error: toast.error() с structured message via extractReviewError() / humanizeBulkReason() mappings
  • In-form validation: inline error under input с role="alert" + aria-invalid + aria-describedby
  • Approve/reject decision flash: 600ms bg-green-bg/30 или bg-pink-bg/30 band на drawer footer перед onClose() — ack ack для reviewer

Empty states (warmth required)

Every <EmptyState> MUST have:

  • icon — phosphor duotone, size 28-32
  • title — outcome-framed ("Очередь пуста", not "No results")
  • description — actionable hint (what to do next, where data appears)
  • action (optional) — Link / Button to relevant route

9. Term Glossary (canonical)

Code EN RU Definition
maker maker автор User who creates / submits a draft
reviewer reviewer ревьюер User who approves / rejects drafts
publisher publisher публикатор User who publishes approved schema drafts
draft draft черновик Pending change awaiting approval
pending pending на ревью Status: awaiting reviewer decision
approved approved одобрено Status: reviewer approved (record published OR schema awaits publish)
rejected rejected отклонён Status: reviewer rejected (terminal)
withdrawn withdrawn отозван Status: maker cancelled (terminal)
WIP in progress в работе Schema draft pre-submit OR changes_requested
decided decided закрыты Any terminal status — APPROVED + REJECTED + WITHDRAWN
changes requested changes requested запрошены правки Reviewer bounced schema draft back to maker
published published опубликован Schema draft → live (terminal positive)

Source: backend domain types (DraftStatus, SchemaDraftStatus, DraftOperation). NEVER use synonyms ("submitter" for maker, "validator" for reviewer) — breaks consistency with audit log + RBAC roles.


10. RBAC & Role Visibility

Backend gates (single source of truth). Frontend hide UI elements when roles missing — backend still enforces if frontend leaks.

Composite role Members UI surface
ordinis:reviewer schema:reviewer + record:reviewer /reviews tabs (Records, Schemas) — approve/reject buttons
(maker is implicit) any authenticated user /reviews Мои tab, draft create modals, dict editor

Identity check pattern (in components):

const auth = useAuth()
const currentSub = auth.user?.profile?.sub
const isMine = draft.makerId === currentSub

For role gating use usePermissions() (src/auth/usePermissions.ts).


11. AI Slop Anti-Patterns (banned)

Per /design-review gstack skill plus our own observations:

  • Purple/violet/indigo gradient backgrounds
  • 3-column feature grid with icon-in-circle headers
  • Decorative blobs / wavy SVG dividers / floating circles
  • Emoji as design elements (rocket in heading)
  • Colored left-border-only cards
  • Generic hero copy ("Welcome to Ordinis", "Unlock the power…")
  • Bubbly uniform rounded-full on every element
  • Centered everything (text-align: center on all body content)
  • system-ui / -apple-system as PRIMARY display font

Pass test: every visual element should be there because it does a job, not because empty space looks empty.


12. Open Items (gaps to address in /design-consultation sprint)

  • Responsive breakpoint policy (mobile 375, tablet 768, desktop 1024, wide 1440 — confirm + lint)
  • Touch target enforcement (P1 in TODO 6 a11y findings)
  • Loading state taxonomy (skeleton vs spinner vs LoadingBlock vs Suspense — when to use which)
  • Motion duration policy (currently ad-hoc — set 150ms quick / 300ms medium / 500ms entrance)
  • Long-content overflow rules (truncate vs wrap vs ellipsis vs scroll — per surface type)
  • Dark mode parity audit (some tokens have alpha inconsistency between themes)
  • Notifications channel UI policy (in-app vs email vs both — currently every event goes to all enabled channels; should be user-configurable)

Changelog

  • 2026-05-14 v0 — Initial document. Captured tokens, components, badge semantics, term glossary, drawer-vs-modal rules from approval workflow saga codebase. Marked open items для full /design-consultation sprint. Authored as part of TODO 5 closeout.