# Provider portal state alerts design

Date: 2026-08-25
Status: Approved design
Projects: `api_mycode`, `web_mycode`

## Context

Submitting a provider profile for publication review and submitting evidence for provider verification are independent operations. The current portal does not make that distinction prominent enough. A provider can submit a profile, later see a rejection reason, and have no persistent visual signal outside the review form. Verification rejection reasons are stored by the API but are not included in the authenticated owner verification resource.

## Goals

- Make actionable profile and verification states visible throughout the provider portal.
- Distinguish publication review from optional document verification.
- Provide a direct route from each actionable alert to the relevant portal section.
- Keep messages synchronized with current API state without introducing notification persistence.
- Support Spanish and English with the existing portal locale behavior.
- Preserve API privacy boundaries and render all remote text safely.

## Non-goals

- A notification inbox, history, read/unread state, email, SMS, or push notifications.
- User-dismissible alerts whose dismissal is stored.
- Making document verification mandatory for publication.
- Exposing moderation or verification reasons on public provider endpoints.

## User experience

### Global presentation

The provider application shell will contain a state-alert region immediately below the sticky top bar and before the active page content. The region is present on Summary, Profile, Locations, Review, and Resolutions.

The Review navigation item will display an accessible coral badge containing the number of actionable conditions. On compact navigation the same badge appears on the Review icon. Informational states do not increase the badge count.

Alerts are not dismissible. They disappear automatically when a subsequent provider response no longer satisfies the condition. The highest-priority actionable alert is rendered first. If more than one actionable alert exists, each remains individually visible and the badge shows the total.

### Tone and priority

| Condition | Tone | Badge | Action |
|---|---|---:|---|
| Provider suspended | Coral, critical | Yes | Contact or review the stated MyCode instruction |
| Provider rejected | Coral, actionable | Yes | Open Profile/Review to correct the profile |
| Verification rejected | Coral, actionable | Yes | Open Review and focus Verifications |
| Provider pending review | Blue, informational | No | No required action; explain read-only state |
| Editable provider without verification evidence | Blue, informational | No | Open Review and focus Verifications |

Archived providers remain read-only using the existing state notice and do not receive an actionable counter. Published providers do not receive a success banner because publication is already represented by the status UI.

### Publication review versus verification

The Review page will prominently state:

> Sending the profile for review does not submit documents or request verification. To verify identity or business information, attach evidence in Verifications before sending the profile.

The Spanish equivalent will be provided in the locale catalog. The optional checklist entry will retain its optional semantics and will not block profile submission.

### Safe fallback messages

If an actionable state has no reason, the portal shows a translated generic explanation and the same direct action. Unknown states never create an actionable alert. Server-provided reasons are inserted with `textContent`; they are never interpreted as markup.

## Data and architecture

### API contract

`ServiceVerificationResource`, used for authenticated provider-owner responses, will add nullable `rejection_reason`. The value is only meaningful for rejected verifications.

Public provider resources continue to omit provider moderation reasons, verifications, evidence paths, metadata, and verification rejection reasons. `AdminServiceVerificationResource` remains unchanged because it already exposes the administrative review fields.

No migration or new endpoint is required.

### Web state derivation

The web portal will project `rejection_reason` in its verification contract as bounded plain text. A pure alert-derivation function accepts the projected provider resource and returns normalized alert descriptors:

- stable alert key;
- tone and priority;
- translated title/message keys;
- optional safe reason text;
- destination route and optional section anchor;
- whether the alert contributes to the navigation badge.

The derivation function contains no DOM access and no network calls. Rendering consumes descriptors and creates DOM nodes using safe text APIs.

The alert controller subscribes to `providerStore` so profile saves and review/verification state updates refresh the banner immediately. On pages that do not already load the provider, it reuses a shared current-provider loading promise to avoid duplicate `mine` requests.

### Navigation and anchors

- Provider rejection links to the Review screen, where the publication reason and requirements are visible.
- Verification rejection and missing optional evidence link to the Review screen with a stable Verifications anchor.
- Suspension links to the Review screen and does not imply that editing is available.

Focus is moved only after explicit user navigation. A URL fragment may select the target section, but it must not bypass the existing route or authorization logic.

## Localization

All fixed alert titles, fallback messages, CTA labels, badge labels, and the publication/verification distinction are defined in both `resources/lang/es/provider_portal.php` and `resources/lang/en/provider_portal.php`, or in the existing provider JavaScript translation catalog where dynamic rendering requires it.

Remote moderation reasons remain administrator-authored text and are shown exactly as safe plain text; they are not machine-translated.

## Accessibility

- The alert region uses an accessible label and `aria-live="polite"`.
- Critical/actionable alerts use `role="alert"`; informational notices use status semantics.
- The badge has a localized accessible name and is not communicated only through color.
- Links are keyboard reachable and use descriptive labels.
- Coral and blue variants must preserve readable contrast in desktop and mobile layouts.
- Motion is limited to a short entrance transition and disabled under `prefers-reduced-motion`.

## Security and privacy

- Only authenticated owner/admin resources may expose private rejection reasons.
- Public resource privacy tests explicitly assert that the new verification reason is absent.
- The web contract bounds reason length and rejects malformed verification payloads.
- Remote reasons are never assigned through `innerHTML`.
- No credentials, evidence contents, private paths, or moderation metadata are logged to the browser console.

## Tests

### API

- Owner verification resources include a nullable rejection reason.
- Rejected owner verification responses include the stored reason.
- Public provider and location resources do not expose it.
- Existing admin verification behavior remains unchanged.

### Web

- Pure derivation tests cover rejected, suspended, pending-review, published, archived, missing-verification, and rejected-verification states.
- Multiple actionable conditions are ordered deterministically and counted correctly.
- Informational conditions never increment the badge.
- Rendering tests cover links, safe fallback copy, `textContent` behavior, and accessibility attributes.
- English and Spanish pages contain the complete alert vocabulary and distinction notice.
- The Review checklist remains optional for verification and submission is not blocked by missing evidence.
- Responsive assertions cover the desktop label badge and compact icon badge.

The final verification gates are the focused API/web tests, complete test suites, and `php artisan architecture:audit --strict` in `web_mycode`.

## Version and rollout

This is a backward-compatible user-facing feature plus a private API resource addition. The web version dialog will be reviewed from the actual change set before commit. The expected change is a minor web version increment, subject to the repository's version hook decision. API and web commits are deployed independently, API first and web second, with health and route checks after each deployment.

## Acceptance criteria

- A rejected provider sees a persistent coral alert and Review badge on every provider portal screen.
- A rejected verification produces its own persistent alert with a direct Verifications action.
- Pending review and missing optional evidence are explained without an actionable badge.
- The Review page clearly says that profile review and document verification are separate submissions.
- Resolving the underlying state removes the corresponding alert without storing dismissal state.
- All UI is bilingual, accessible, responsive, and consistent with MyCode blue/coral styling.
- No new private value is exposed by public API resources.
