# UX/UI Designer Audit — GoodGo POS System **Auditor:** UX/UI Designer Agent **Date:** 2026-03-20 **Scope:** `apps/web-client-tpos-net` — Blazor WASM + MudBlazor frontend **Focus:** UI consistency, component reuse, theme & styling, accessibility, UX flows --- ## Executive Summary The GoodGo POS frontend has a **solid design foundation** — centralized theming via `AppTheme.cs`, a reusable auth component library, and responsive multi-layout architecture. However, the codebase suffers from **critical accessibility failures** (no keyboard navigation, missing ARIA attributes, no focus-visible styles), **2,316+ inline style attributes** that undermine design system consistency, and **pervasive hardcoded Vietnamese strings** that break English localization throughout the POS UI. Overall UI/UX maturity: **6/10**. --- ## Critical Issues Issues that block production readiness or violate WCAG 2.1 AA standards. ### 1. Missing `:focus-visible` Styles — WCAG 2.1 §2.4.7 **Files:** `wwwroot/css/admin.css`, `wwwroot/css/pos.css`, `wwwroot/css/auth.css`, `wwwroot/css/marketing.css` **Impact:** Keyboard users cannot see which element has focus — entire app is effectively unusable without a mouse. No CSS file defines `:focus-visible` styles. Browsers' default focus ring is often suppressed by MudBlazor reset styles. **Fix:** ```css /* Add to app.css global scope */ :focus-visible { outline: 2px solid #FF5C00; outline-offset: 2px; border-radius: 4px; } ``` --- ### 2. Clickable `
` Elements Instead of ` ``` --- ### 3. No ARIA Labels on Interactive Icons — WCAG 2.1 §4.1.2 **Files:** `Components/Auth/AuthButton.razor`, `Components/Auth/AuthInput.razor` (line 37), all layout files **Impact:** Icon-only buttons (close, toggle, back) have no accessible names — screen readers announce nothing or raw Unicode. **Example (AuthInput.razor ~line 37):** ```razor ``` --- ### 4. Error/Success Messages Missing `role="alert"` — WCAG 2.1 §4.1.3 **Files:** `Pages/Auth/LoginAdmin.razor` (lines 28–40), `Pages/Pos/Cafe/CafeDesktop.razor` **Impact:** Dynamic status changes (login error, payment success, cart update) are not announced to screen readers. **Example (LoginAdmin.razor ~line 29):** ```razor
@_errorMessage
``` --- ### 5. Hardcoded Vietnamese Strings in POS UI — Localization Failure **File:** `Pages/Pos/Cafe/CafeDesktop.razor` and all POS vertical pages **Impact:** English-language users see Vietnamese text. App cannot support international merchants. **Examples found (CafeDesktop.razor):** | Line | Hardcoded String | Should Be | |------|-----------------|-----------| | 24 | `"Đang tải..."` | `@L["Common_Loading"]` | | 25 | `"Không thể tải dữ liệu"` | `@L["Common_LoadError"]` | | 66 | `"Đơn hàng"` | `@L["Pos_OrderPanel_Title"]` | | 67 | `"món"` | `@L["Pos_CartItem_Unit"]` | | 89 | `"Nhập mã voucher..."` | `@L["Pos_Voucher_Placeholder"]` | | 97 | `"Giảm giá"` | `@L["Pos_Discount_Label"]` | | 107 | `"Tổng cộng"` | `@L["Pos_Total_Label"]` | | 117 | `"Đang tạo đơn..."` | `@L["Pos_CreatingOrder"]` | | 122 | `"Thanh toán"` | `@L["Pos_Checkout_Button"]` | Also found in layouts: - `AdminLayout.razor` (line ~160): `"Có lỗi xảy ra"`, `"Vui lòng thử lại"`, `"Tải lại"` - `StaffLayout.razor` (line 148): Same error boundary text - `PosLayout.razor` (lines 29, 65, 115): `"GoodGo POS"`, `"Menu"`, `"Đơn hàng"` --- ### 6. Hardcoded Color Values Instead of CSS Variables **Files:** `Pages/Pos/Cafe/CafeDesktop.razor`, `Pages/Auth/LoginAdmin.razor`, multiple admin pages **Impact:** Theme overrides are impossible. Colors are not consistent with the design token system. **Examples:** ```razor style="background:rgba(139,92,246,0.1);color:#8B5CF6;" style="background:rgba(239,68,68,0.12);color:#EF4444;" style="background-color:rgba(139,92,246,0.125);" class="status-purple" class="status-danger" ``` **Hardcoded colors to replace:** | Value | Should Be | |-------|-----------| | `#16A34A` | `var(--color-success)` | | `#EF4444` | `var(--color-danger)` | | `#8B5CF6` | `var(--color-purple)` | | `rgba(139,92,246,0.1)` | `var(--color-purple-subtle)` | | `rgba(239,68,68,0.12)` | `var(--color-danger-subtle)` | --- ## Warnings Issues that create significant technical debt or UX inconsistency. ### 7. 2,316 Inline Style Attributes Inline styles are scattered across all pages — especially POS desktop views, admin shop pages, and dashboard. This makes CSS maintenance impossible and prevents design system enforcement. **Top offending patterns:** ```razor style="display:flex;flex-direction:column;gap:24px;" style="padding:6px 12px;border-radius:8px;border:none;" style="position:absolute;left:@{X}px;top:@{Y}px;" ``` **Strategy:** Create CSS utility classes and component classes. Move inline styles to scoped `.razor.css` files. --- ### 8. Inconsistent Spacing Scale The design uses 10+ different spacing values without a defined scale: - Gaps: 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 48px - Padding: 6, 8, 10, 12, 16, 20, 24px - Border radius: 6, 8, 10, 12, 14, 20, 24px **Recommended scale:** ```css /* Spacing: 4-point scale */ --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 20px; --space-6: 24px; --space-8: 32px; --space-12: 48px; /* Border radius: 3 values */ --radius-sm: 8px; --radius-md: 12px; --radius-lg: 16px; ``` --- ### 9. Missing Contrast Ratio for Secondary Text — WCAG 2.1 §1.4.3 **File:** `wwwroot/css/admin.css` ```css /* Current — MAY fail WCAG AAA */ --admin-text-secondary: #ADADB0; /* ratio ~5.08:1 on #1A1A1D — FAILS AAA (7:1) */ --admin-text-tertiary: #8B8B90; /* ratio ~4.13:1 on #1A1A1D — FAILS AA (4.5:1) */ ``` `--admin-text-tertiary` likely **fails WCAG AA** for normal text. Needs contrast validation. --- ### 10. Cart Items Use `
` Instead of Semantic List **File:** `Pages/Pos/Cafe/CafeDesktop.razor` Cart items rendered as generic `
` elements. Should be `
    /
  • ` structure for screen readers to announce list count and items. --- ### 11. No `.razor.css` Scoped Stylesheets Per Component All 8 reusable components (`AuthButton`, `AuthInput`, `OtpInput`, etc.) have zero scoped CSS files. Styles are defined globally in `auth.css`. This creates unintended style leakage and makes component refactoring dangerous. --- ### 12. OTP Input Missing ARIA Group Label **File:** `Components/Auth/OtpInput.razor` (lines 12–19) The 6-digit OTP input is a group of individual `` elements but lacks `role="group"` and `aria-label="One-time password"`. Screen readers will announce 6 separate unlabeled inputs. --- ### 13. No Focus Trap in Modal Overlays **Files:** `Layout/PosLayout.razor`, admin dialog pages When mobile overlays or modals open, focus is not trapped within them. Users pressing Tab will cycle through background content, violating WCAG 2.1 §2.1.2. --- ## Improvements Recommendations that would improve UX quality and developer experience. ### A. Create Component-Scoped CSS Files For each component in `Components/`, create a matching `.razor.css` file: ``` Components/Auth/AuthButton.razor.css Components/Auth/AuthInput.razor.css Components/Pos/ResponsiveOrderPanel.razor.css ``` ### B. Add Password Strength Indicator **File:** `Pages/Auth/Register.razor` Registration form has no visual password strength feedback. Add a 4-step strength bar (weak → fair → good → strong) using the existing `PasswordStrengthCalculator` pattern from Swift app. ### C. Standardize Icon Sizes to 3 Tiers Currently uses: 12, 14, 16, 18, 20, 24, 28, 32px. Reduce to: ```css --icon-sm: 16px; /* Inline, label */ --icon-md: 20px; /* Button, nav */ --icon-lg: 24px; /* Header, feature */ ``` ### D. Add `aria-expanded` to Expandable Sections **File:** `Pages/Admin/Shop/ShopRecipes.razor` Accordion-style expand/collapse sections lack `aria-expanded` and `aria-controls`. Screen readers cannot determine collapsed state. ### E. Add `aria-busy` to Async Loading States Async data-fetch loading spinners don't set `aria-busy="true"` on the container, so screen readers don't know content is loading. ### F. Introduce Design Token Documentation Create a living style guide page at `/admin/design-system` (dev only) that shows all color tokens, spacing, typography, and component variants. Reference: MudBlazor Theme Manager pattern. ### G. Validate Table Semantics Admin tables (staff management, inventory, orders) should verify `` on all headers. MudBlazor's `MudTable` typically handles this, but custom HTML tables may not. --- ## Action Items Prioritized next steps. | # | Priority | Effort | Item | Files | |---|----------|--------|------|-------| | 1 | 🔴 Critical | Small | Add `:focus-visible` styles globally | `wwwroot/css/app.css` | | 2 | 🔴 Critical | Large | Replace clickable `
    ` with `