# Agent Portal Shell Migration — Epic 13A1

## Scope

This migration replaces only the authenticated non-admin shell. Existing Agent page components, their content, business logic, routes, notification data, onboarding flow, and form/table markup are unchanged. Admin users remain on the legacy authenticated navigation shell pending a separate Admin migration.

## Shell architecture

At `lg` and above, the Agent portal uses the shared sticky `Sidebar` with local-only collapsed state, the shared `Topbar`, a flexible full-width main content area, and the existing page-header/default slots. Below `lg`, `Topbar` opens `MobileSidebar`; the drawer supplies overlay close, Escape close, explicit close control, body-scroll lock, and close-after-navigation through `SidebarNavItem`'s `navigate` event.

The existing onboarding modal remains mounted in `AuthenticatedLayout`, above the new shell, without a behavior change. The existing notification bell/list and account `Dropdown` are repositioned into Topbar slots; unread count, read actions, notification navigation, Profile, and Logout remain the same capabilities.

## Navigation information architecture

| Group | Items |
| --- | --- |
| Main | Dashboard |
| Sales | Premium Leads, Affiliate |
| Account | Membership, E-Wallet, Lead Credits, Billing |
| Support | Support |
| Partner | Partner — only when the current authenticated user has `is_partner` |
| Settings | Profile |

Notifications remains directly available in the topbar and links to the existing notifications index. Billing and Affiliate were included because active Agent routes/pages exist. No navigation badges were invented.

## Partner confidentiality

The shell reads only the already-authorized `auth.user.is_partner` capability flag to conditionally render the Partner navigation item. It does not query, expose, or pass partner rates, balances, hierarchy, or financial data into global navigation state. Server-side Partner route middleware remains the authorization boundary.

## Responsive and accessibility behavior

- Desktop sidebar is expanded by default and can collapse locally; collapsed items keep accessible text and a native title hint.
- Mobile/tablet shows one topbar trigger and no duplicated legacy menu; drawer navigation closes after an item is selected.
- Sidebar and drawer navigation areas scroll independently for long menus.
- Active state is mapped in the Agent shell from existing route patterns, including nested Support, Partner, Premium Leads, Profile, and billing routes.
- Collapse, menu, notification, and account controls retain keyboard access and visible focus treatment.
- Main content has no global narrow maximum width; existing page-level containers remain authoritative.

## Deferred work

No Agent dashboard/content redesign, individual Agent page migration, Admin shell migration, public landing-page work, notification redesign, page-header replacement, or business/route change is included in Epic 13A1.

## Dashboard Mission Control — Epic 13B1

The Agent Dashboard now uses a Mission Control hierarchy: PageHeader, account-readiness strip, three KPI cards, next-best-action/quick-action cards, and a compact account overview. It reuses `PageHeader`, `Card`, `KpiCard`, `SectionHeader`, `StatusBadge`, and `Button`, with a responsive one/two/three-column layout that collapses cleanly to a single column on mobile.

The dashboard read model remains unchanged: membership, lead-credit balance, lead eligibility, and the existing authenticated user/operator context. It deliberately does not display E-Wallet, partner financial data, activity feeds, recent leads, support counts, or analytics because those are not current dashboard props. Quick actions reuse only existing Premium Leads, Lead Credits, Membership, and Support routes. Premium Leads, Membership, Wallet, Support, Partner, Admin, and public pages remain deferred for their own migrations.

## Premium Leads workspace — Epic 13B2

The Premium Leads index remains a horizontal Kanban workspace with the existing drag-and-drop and inline status-update workflow. Its server-provided columns preserve the exact nine labels: NEW, CONTACTED, QUOTATION GIVEN, FOLLOW UP, POTENTIAL, CLOSED, NOT PROCEED, WRONG NO., and SPAM. The local presentation mapping is NEW/QUOTATION GIVEN → info; CONTACTED/NOT PROCEED → neutral; FOLLOW UP/WRONG NO. → warning; POTENTIAL/CLOSED → success; SPAM → danger. This is display-only and does not alter pipeline rules.

The page reuses `PageHeader`, `Card`, `Input`, `Select`, `Button`, `Alert`, `StatusBadge`, and `EmptyState`. Filters, board widths, route-backed lead detail links, timestamps, repeat-submission context, and inline server-validated status updates remain. The board intentionally scrolls horizontally on smaller displays rather than compressing nine workflow stages. Lead detail, notes, reminders, Membership, Wallet, Support, Partner, Admin, and public pages remain deferred.

## Premium Lead detail — Epic 13B2.1

The Premium Lead detail now uses a responsive information hierarchy: a `PageHeader` with a Premium Leads back link and current status context; read-only prospect/quotation details; a compact desktop side rail for status, contact, and assigned-operator context; then notes and activity history. It is a single-column mobile layout and becomes a two-third/one-third reading layout from `lg` without fixed widths.

The same display-only pipeline mapping as the board is used: NEW/QUOTATION GIVEN → info; CONTACTED/NOT PROCEED → neutral; FOLLOW UP/WRONG NO. → warning; POTENTIAL/CLOSED → success; SPAM → danger. Pipeline states, status updates, assignments, and event data remain server-owned; this detail page adds no client-side status mutation.

Notes preserve the existing submit route, validation feedback, loading protection, and newest-first order. A small `note_url` read-model field is now supplied because the already-existing note form posts to that URL; it is derived from the existing route and does not change note authorization or business behavior. The activity timeline preserves the existing latest-50 ordering and renders status transitions with the same badge mapping. The existing detail response provides no reminders, so no reminders UI has been invented.

## Membership and billing — Epic 13B3

Membership is now a buyer-facing account workspace built from a status summary, pricing/payment card, and compact E-Wallet balance context. It uses only the existing safe membership, price, buyer-pricing, coupon-availability, and balance props. Status remains display-only: active → success, pending → info, expired → danger, and inactive/unknown → neutral. The page derives a lapsed active record as “Expired” only for readable presentation; it does not update membership state.

The pricing hierarchy shows base membership price, then only an applicable special referral or coupon discount, and then the buyer-facing amount to pay. A zero payable amount clearly offers the existing completion action without payment-provider detail. Coupon input preserves the current validation endpoint, apply/remove behavior, invalid feedback, renewal availability, and referred first-paid restriction. The unavailable-coupon message stays neutral and does not disclose referrer, partner, affiliate, or commission information. CHIP and E-Wallet remain the only payment actions, with their existing requests and processing protection.

Billing retains the existing paginated mixed Membership/Lead Credit order history. It now uses a horizontally-scrollable `DataTable`, semantic payment-status badges, route-backed order links, `Pagination`, and an `EmptyState`; it presents only the already-safe date, product label, charged amount, method, and status fields. It deliberately omits provider identifiers, payment-attempt metadata, raw references, discounts not already present in the list read model, and all Partner/commission information. Membership is a single-column reading flow on mobile and uses a balanced content/summary grid at `lg`; Billing remains scrollable rather than compressing its table on small screens.

## E-Wallet and Lead Credits — Epic 13B4

E-Wallet now presents a compact available-balance KPI, a short existing-use boundary (Membership and Lead Credit purchases only; no cash withdrawal), and a paginated transaction history. Its read model provides only description, signed amount, and timestamp, so the history marks each row explicitly as Credit or Debit with a signed amount while omitting wallet IDs, ledger IDs, balance-before/after fields, references, metadata, and all Partner Wallet data.

Lead Credits follows the same balance/history rhythm as E-Wallet and Billing. It keeps the existing active-membership `canPurchase` capability as the sole purchase gate, presents current packages unchanged, and retains the existing CHIP/E-Wallet checkout actions with per-package processing feedback. The paginated credit history maps existing stored types to readable labels (Credit purchase, Credit adjustment, Lead assignment), preserves the already-user-facing balance-after amount, and omits IDs, references, metadata, and balance-before fields. No packages, payment methods, transfer/top-up/withdrawal capability, or credit logic were added.

Both views are mobile-first, with KPI/context cards stacking on narrow screens and their `DataTable` histories retaining horizontal scrolling when needed. They share Membership/Billing’s PageHeader, Card, spacing, amount typography, empty states, and semantic feedback so the financial/account family remains consistent.

## Agent Support — Epic 13B5

Agent Support is now a three-view workspace: a paginated ticket index with a clear Create Ticket action, a labelled create form, and a chronological ticket conversation. The index uses the existing owner-scoped pagination and renders backend-provided category labels alongside local display-only status mapping: open → info, in review/waiting for you → warning, resolved → success, and closed → neutral. Stored category and status values remain unchanged.

The create form preserves exactly the existing categories—General, Membership, Lead Credit, Billing, Balance Inquiry, Technical Issue, Bug Report, and Feature Request—and its Category, Subject, and Message fields retain server validation with adjacent inline errors. Balance Inquiry remains an ordinary Support category; no refund-specific UI or workflow was added.

Ticket detail keeps messages oldest first and distinguishes the visible sender labels “You” and “Support” without exposing an admin identity. Closed tickets show a clear state and no reply composer. Resolved tickets retain the existing reply composer: replying continues the existing server workflow that moves the ticket back to in review. The Agent page props are now curated to display-only ticket/message fields, with IDs retained only for the current ticket routes; no sender email, internal identity, or message metadata is exposed. Layouts stack into a single conversation flow on mobile, while desktop places ticket metadata in a compact side card. Admin Support, notifications, attachments, and live chat remain out of scope.

## Partner Portal — Epic 13B6

The confidential Partner portal now leads with available commission, reserved-for-withdrawal, total-earned, and direct-referral KPIs. It explicitly labels the Partner Commission Wallet as separate from the normal E-Wallet, then presents the existing wallet balance/reservation semantics, commission mix, referral link, safe current program rates, allocation controls, and buyer-facing pricing preview. It remains accessible only through the existing Partner route/middleware for current Partner accounts.

Allocation preserves the server-owned 100% invariant with clearly labelled Commission and Buyer Discount inputs: Partner Benefit Pool → Commission % + Buyer Discount % = 100%. The page retains only the existing current preview and safe rates; it does not expose hierarchy, other Partner identities, commission recipients, or new analytics.

Commission and withdrawal histories now use responsive `DataTable`/`Pagination` patterns with semantic status badges and empty states. Withdrawal requests retain their existing validation and reservation behavior. A paid withdrawal with an existing receipt exposes only its protected download URL and current payment reference; loading the receipt does not generate or modify it. Rejected requests show only their status. Admin notes, internal IDs, wallet details, and receipt internals remain hidden. The layout stacks on mobile and keeps tables horizontally scrollable where required.

## Affiliate and Profile — Epic 13B7

Affiliate now presents the existing affiliate code/link, direct-referral total, current legacy referral-commission total, and the existing paginated referral list using only safe referral name and joined date fields. It does not expose Partner rates, hierarchy, allocation, Partner Wallet, or Partner economics.

Profile now groups the existing profile-information, email-verification, password, and permanent account-deletion flows into shared-card sections. The Danger Zone uses the existing password-confirmed deletion route in an accessible modal; no account fields, authentication rules, preferences, or account capabilities were added. This completes migration of the current Agent Portal page surfaces; Admin and Public pages remain separate work.
