# UI Consistency Audit — Epic 15A1

## Scope and method

Read-only source audit of the authenticated Agent and Admin portals, Admin Website Settings/CMS, shared navigation, and the migrated dashboard, leads, registration, premium-lead, support, billing, wallet, membership, coupon, and CMS surfaces. The audit compares page markup with the current shared primitives: `PageHeader`, `SectionHeader`, `Card`, `KpiCard`, `DataTable`, `FormField`, `Input`, `Select`, `Textarea`, `Button`, `StatusBadge`, `Alert`, `EmptyState`, and `Pagination`.

No visual changes, Vue changes, CSS changes, route changes, or business-logic changes were made during this audit.

## Overall assessment

**Initial consistency score: 72 / 100.** The current Design System is applied consistently on the recently migrated operational and CMS workflows. The remaining score is chiefly constrained by legacy operational pages that sit inside the new shell but retain old card, table, form, color, and heading patterns.

Estimated findings: **34 distinct consistency issues**. Category totals are observations and overlap where one page has related issues.

| Category | Estimated observations | Assessment |
| --- | ---: | --- |
| Buttons | 6 | Legacy pages use custom indigo/emerald/red buttons and do not consistently protect processing state. |
| Forms | 7 | Several legacy forms lack `FormField`, input descriptions, connected errors, or a common action row. |
| Cards | 6 | Legacy white/shadow cards bypass Card padding, border, and semantic surface variants. |
| Tables | 7 | Multiple operational tables bypass `DataTable`; density, headers, actions, and empty states vary. |
| Navigation | 1 | Shared shell/navigation is strong; an inactive legacy navigation branch remains in the layout source. |
| Typography | 5 | Legacy slot headers and raw `text-*` typography do not follow the semantic heading scale. |
| Spacing | 5 | `p-4/p-6`, `gap-2`, and raw spacing coexist with the token rhythm. |
| Responsive | 4 | Legacy filter rows and tables lack the migrated responsive/container conventions. |
| Accessibility | 8 | Most shared primitives are sound; legacy pages contain unlabelled controls, non-semantic status text, and inconsistent focus styles. |

## Current strengths

- Shared Admin and Agent sidebar, mobile drawer, Topbar, collapsed navigation, overlay dismissal, and focus styling use the tokenized navigation primitives.
- Current Agent Dashboard, Membership, Billing, E-Wallet, Credits, Partner, Premium Leads, and Support pages broadly establish PageHeader/Card/KpiCard/StatusBadge patterns.
- Current Admin Dashboard, Registrations, Leads, Premium Lead Approvals, Support, Coupons, and Website Settings/CMS pages broadly use semantic headers, tables, forms, cards, confirmations, and feedback.
- CMS is especially coherent: workspace, editor, preview/publish, revision history/rollback, and Theme editor share spacing tokens, typed statuses, accessible form fields, and controlled feedback.
- Shared `Button`, `FormField`, `DataTable`, `StatusBadge`, `Alert`, `Modal`, `ConfirmDialog`, and navigation components supply consistent focus, loading, responsive, and keyboard foundations for future migrations.

## Findings

### Critical

No Critical UI-consistency issue was identified. Shared primitives are present for all high-risk interactions; remaining issues are migration and presentation consistency rather than a broken authorization or destructive-action boundary.

### High

| ID | Location | Description | Recommended fix | Priority |
| --- | --- | --- | --- | --- |
| H1 | `resources/js/Pages/Admin/LeadCredits/Index.vue` | **Resolved in Epic 15A2.** The monitor now uses PageHeader, KpiCard, Card, FormField, Button, DataTable, StatusBadge, EmptyState, and Pagination, with no change to its existing read model. | Keep future changes within the shared primitives and preserve the existing server-side filters/order/query ceiling. | Resolved |
| H2 | `resources/js/Pages/Admin/Agents/Index.vue`, `Show.vue` | **Resolved in Epic 15A3.** Listing/detail now use shared tables, cards, fields, buttons, status presentation, pagination, and a scoped confirmation for existing Partner removal and Lead Credit adjustments. | Keep future Agent administration UI within the shared primitives and preserve the existing action/permission boundaries. | Resolved |
| H3 | `resources/js/Pages/Admin/PartnerWithdrawals/Index.vue`, `Show.vue` | **Resolved in Epic 15A4.** Listing/detail now use shared filters, tables, cards, field/error presentation, status badges, alerts, loading, and lifecycle-specific confirmations. | Keep future financial workflow UI within the shared primitives and preserve the existing server transition boundaries. | Resolved |
| H4 | `resources/js/Pages/Admin/Payments/Index.vue`, `resources/js/Pages/Billing/Show.vue` | **Resolved in Epic 15A5.** Admin listing/detail now use shared filters, tables, cards, status hierarchy, alerts, empty/pagination presentation, and safe payment-attempt context. | Keep future payment UI presentation within the shared primitives and preserve the existing provider/fulfilment authority boundaries. | Resolved |

### Medium

| ID | Location | Description | Recommended fix | Priority |
| --- | --- | --- | --- | --- |
| M1 | `resources/js/Pages/Admin/RoundRobin/Index.vue` | Raw `h1/h2`, white cards, and unstructured table rows bypass typography, Card, DataTable, and responsive table conventions. Long agent/reason rows can be difficult to scan on small screens. | Introduce PageHeader, Card, StatusBadge, DataTable, and an overflow table container while retaining the existing monitor data. | P1 |
| M2 | `resources/js/Pages/Admin/Settings/Onboarding.vue` | Legacy form uses raw labels, inputs, textarea, red error text, card, and indigo button. Labels and errors are not consistently wired through shared form primitives. | Adopt PageHeader, Card, FormField, Input, Textarea, Button, and Alert. | P1 |
| M3 | `resources/js/Pages/Admin/PartnerReceiptSettings/Edit.vue` | Legacy receipt form exposes raw field keys as labels, includes direct `logo_path` editing, and bypasses shared field/error/action presentation. | Perform a separately scoped receipt-settings migration; retain current fields and route behavior. | P1 |
| M4 | `resources/js/Pages/Agent/Notifications/Index.vue` | Notifications page uses hardcoded slate/indigo colors, direct `h1`, raw card/list styling, raw button/link actions, and a custom empty state. | Migrate to PageHeader, Card, EmptyState, Button/Link treatment, and semantic unread state. | P1 |
| M5 | `resources/js/Pages/Agent/PaymentReturn.vue` | Payment-return state is a single unbranded raw message on a slate background, with no PageHeader, Card, loading/status context, or return action hierarchy. | Define the return-state UI boundary and migrate it with shared status/empty/loading primitives without changing provider behavior. | P1 |
| M6 | `resources/js/Pages/Admin/WebsiteSettings/Index.vue` | Workspace uses a shared live-site action but does not surface the existing Theme editor as a visible context action. Theme is route-accessible but discoverability differs from the other CMS surfaces. | Add a future scoped workspace action after confirming intended role/route visibility; do not alter theme behavior. | P1 |
| M7 | `resources/js/Pages/Admin/Registrations/Show.vue`, `resources/js/Pages/Admin/Support/Show.vue`, `resources/js/Pages/Agent/Support/Show.vue` | Core forms are shared, but primary and destructive actions can appear in visually similar card regions with limited separation between review/support content and irreversible actions. | During a future polish pass, standardize action-rail spacing and place destructive actions in an explicit danger area without changing action eligibility. | P2 |
| M8 | `resources/js/Pages/Admin/WebsiteSettings/EditSection.vue`, `EditTheme.vue` | Native upload inputs are necessarily custom but their file-button styling is duplicated across CMS editor/theme editor rather than encapsulated. | Consider a future, small shared file-input presentation primitive; preserve each upload contract. | P2 |
| M9 | `resources/js/Pages/Admin/WebsiteSettings/Revisions.vue` | Revision content-summary table is intentionally rich; on narrow screens the minimum-width columns require horizontal scrolling and may make action discovery slow. | In a future responsive polish pass, evaluate a mobile stacked revision-card presentation while preserving newest-first order and actions. | P2 |
| M10 | `resources/js/Pages/Admin/Coupons/Form.vue`, `resources/js/Pages/Agent/Membership/Index.vue` | Coupon entry and validation presentation are generally consistent, but discount/coupon helper messaging is distributed across field descriptions and surrounding cards. | Consolidate non-business helper hierarchy during a form-polish phase; retain server validation as source of truth. | P2 |
| M11 | `resources/js/Pages/Admin/Dashboard.vue`, `resources/js/Pages/Agent/Dashboard.vue` | KPI grids are consistent, but supporting operational quick-action sections use page-local link arrangements rather than a documented shared quick-action pattern. | Document or introduce a lightweight shared action-list pattern only after auditing remaining dashboard/action groups. | P2 |

### Low

| ID | Location | Description | Recommended fix | Priority |
| --- | --- | --- | --- | --- |
| L1 | `resources/js/Layouts/AuthenticatedLayout.vue` | The disabled legacy navigation branch (`v-if="false"`) remains in source with gray/indigo/red utility patterns, inflating searches and obscuring the active Design System shell. | Remove or archive the dead branch in a dedicated cleanup phase after confirming no rollback dependency. | P3 |
| L2 | `resources/js/Components/DangerButton.vue`, `PrimaryButton.vue`, `SecondaryButton.vue`, `TextInput.vue`, `InputLabel.vue`, `InputError.vue`, `NavLink.vue`, `ResponsiveNavLink.vue` | Legacy component set remains alongside the current semantic primitives, creating a future risk of accidental mixed usage. | Audit call sites and deprecate/remove only in a dedicated compatibility cleanup. | P3 |
| L3 | `resources/js/Layouts/GuestLayout.vue`, `resources/js/Pages/Auth/VerifyEmail.vue` | Auth/guest views still use legacy gray/indigo utilities and legacy form primitives. They are outside the principal portal migration scope but remain token-inconsistent. | Schedule a separate Auth/Guest UI migration. | P3 |
| L4 | `resources/js/Pages/Public/OperatorCmsPage.vue`, `Quotation.vue`, `OperatorPage.vue`, `QuotationThanks.vue`, `Welcome.vue` | Public pages intentionally retain public-theme and/or starter-template styling; broad token scans flag hardcoded slate/amber/gray values. | Keep outside this portal-only consistency pass; audit Public branding separately. | P3 |
| L5 | `resources/js/Pages/Admin/WebsiteSettings/Revisions.vue` | The status labels render stored lowercase values (`published`, `draft`, `archived`) while other pages favour title case. | Normalize display casing through a local presentation helper during a later CMS polish pass; do not rename stored status values. | P3 |
| L6 | `resources/js/Pages/Agent/PremiumLeads/Index.vue` | Lead cards provide strong mobile presentation but deviate from the DataTable pattern used by Admin lists; this is a valid responsive choice yet should be documented as intentional. | Add an Agent-card-list guidance note to the Design System if the pattern recurs. | P3 |

## Cross-cutting audit notes

### Buttons and action hierarchy

The shared `Button` is used consistently on migrated pages. The main inconsistency is concentrated in legacy Admin pages, which use raw `bg-indigo-*`, `bg-emerald-*`, `bg-red-*`, and `bg-slate-*` actions. These lack shared variants, loading states, or uniform focus rings. Restore/publish/retry/destructive actions on migrated surfaces correctly use ConfirmDialog/Button and have clear state boundaries.

### Typography and spacing

Migrated pages consistently use `text-h1`, `text-h3`, `text-body`, `text-body-sm`, `text-caption`, `text-overline`, and `space-*` tokens. Legacy pages use direct `text-xl`, `text-2xl`, `text-sm`, raw `p-4/p-5/p-6`, and raw `gap-2/gap-3`, giving the Admin portal visibly mixed header and density rhythms.

### Cards, tables, and empty states

`Card` and `DataTable` standardize borders, surfaces, row density, table headers, and horizontal overflow on migrated pages. The legacy monitor, agent, payment, withdrawal, and receipt/onboarding pages retain raw `bg-white`, shadow, and table markup. Several also omit an explicit empty state or use a raw text row. These should be migrated by workflow rather than globally replaced.

### Forms and alerts

Migrated forms reliably use FormField labels, helper text, connected errors, and loading buttons. Legacy forms generally use native inputs inside plain labels and direct red error text, which weakens error association and consistency. Shared Alert severity usage is broadly sound: info for context, warning for requires-attention/non-live context, danger for failures/destructive context, and success for confirmed completion.

### Status badges and color semantics

New workflows use StatusBadge with text-bearing semantic mappings. Legacy monitor/payment/withdrawal pages render status as plain text or hardcoded colors, which makes status scanability and non-color meaning inconsistent. The theme preview swatches are correctly paired with textual hex values.

### Navigation, responsive behavior, and accessibility

The active sidebar, mobile drawer, and Topbar meet the shared token, focus, Escape, overlay, collapsed-label, and body-scroll expectations. The main responsive risks are legacy filter rows and tables, which do not consistently use responsive grids, labelled fields, DataTable overflow containers, or touch-friendly actions. Shared components provide visible focus; raw legacy links/buttons may not. No broad double-scroll issue was found in the active shell, but wide legacy tables need per-page responsive migration.

## Recommended implementation order

1. **P0 financial/operational legacy pages:** Lead Credits, Agents & Partners, Partner Withdrawals, Payments/Billing detail.
2. **P1 monitor/settings and Agent utility pages:** Round Robin, Onboarding, Partner Receipt Settings, Notifications, Payment Return, then confirm CMS Theme-editor discoverability.
3. **P2 shared polish:** upload-input presentation, dashboard quick-action guidance, action-rail spacing, revision mobile presentation, coupon-helper hierarchy.
4. **P3 cleanup/out-of-scope:** disabled legacy shell branch, legacy components, Auth/Guest, and separately scoped Public UI audit.

## Audit boundary

This document is an inventory and migration recommendation only. It does not authorize the fixes above, does not change any feature-frozen business behavior, and does not alter routes, theme/CMS lifecycle, Public rendering, or security boundaries.

## Epic 15A6 final cross-portal sweep

**Measured score: 86 / 100.** The 14-point increase reflects the resolution of every High finding plus M4–M6 and L5. The remaining gap is deliberate: three legacy Admin workflows need separately bounded migrations, and the other items are accepted lower-risk polish or separate-scope work. This is not a target score; it is a source-audited snapshot after the final safe sweep.

| Finding status | IDs | Evidence / boundary |
| --- | --- | --- |
| Resolved | H1, H2, H3, H4 | Lead Credit Monitor, Agents & Partners, Partner Withdrawals, and Payments/Billing already use the shared system without business changes. |
| Resolved | M4 | Agent Notifications now uses PageHeader, Card, EmptyState, semantic unread state, tokenized links, and a guarded shared Button for the existing read action. |
| Resolved | M5 | Payment Return and Agent order detail now use semantic surfaces, status, typography, Card, and responsive spacing without adding workflow actions. |
| Resolved | M6 | Website Settings now exposes the already-authorized Theme editor route in the existing PageHeader action area. |
| Resolved | L5 | Revision status display is title-cased through a local presentation helper; stored values are unchanged. |
| Deferred | M1, M2, M3 | Round Robin, Onboarding settings, and Partner Receipt Settings remain fully legacy Admin workflows. They require their own workflow-scoped migrations and were not silently redesigned. |
| Accepted | M7 | Existing action rails are usable; a reusable danger-area pattern needs separate interaction review. |
| Accepted | M8 | Two native file inputs have distinct upload contracts; a shared primitive is not justified yet. |
| Accepted | M9 | DataTable horizontal scrolling is the documented response for this rich comparison table; no mobile-card rewrite is warranted here. |
| Accepted | M10, M11 | Coupon helper placement and dashboard quick actions are readable page-local patterns; defer component creation until a recurring need is demonstrated. |
| Deferred | L1, L2 | Disabled shell code and legacy component retirement require a dedicated compatibility audit. |
| Deferred | L3, L4 | Auth/Guest and Public pages are outside this authenticated portal sweep. |
| Accepted | L6 | Agent Premium Lead cards are an intentional responsive alternative for context-rich records; the Design System now documents the decision boundary. |

### Remaining evidence-based category counts

| Category | Remaining observations |
| --- | ---: |
| Buttons | 3 |
| Forms | 3 |
| Cards | 3 |
| Tables | 3 |
| Navigation | 1 |
| Typography | 3 |
| Spacing | 3 |
| Responsive | 2 |
| Accessibility | 3 |

### Revised implementation order

1. Separately scope the three deferred Admin migrations: Round Robin, Onboarding settings, and Partner Receipt Settings.
2. Revisit accepted P2 polish only with fresh user evidence: action rails, native uploads, helper hierarchy, and quick-action reuse.
3. Schedule independent compatibility, Auth/Guest, and Public UI audits for the deferred P3 work.

Epic 15A6 changed presentation only. It did not alter business behavior, routes, permissions, payment-provider behavior, CMS lifecycle, Public rendering, or security boundaries.
