Skip to content

UX Phase D — Professional-Side Surfaces Polish

UX Phase D — Professional-Side Surfaces Polish

Section titled “UX Phase D — Professional-Side Surfaces Polish”

Date: 2026-04-20 Status: Draft Scope: Full pro-side polish to Airbnb/Linear-tier — dashboard, calendar, requests, earnings, credentials (self + admin), onboarding wizard (7 steps + welcome + complete) Phase mapping: Phase D (stretch) of UX overhaul — follows Phase A (hero) + Phase C (consumer tabs) + Phase B (SOS live) Related specs:

  • plans/ideony-ux-overhaul-plan.md (master)
  • plans/specs/2026-04-19-ux-phase-a-design.md (consumer hero flow)
  • plans/specs/2026-04-19-pro-onboarding-design.md (onboarding logic + gating)
  • plans/specs/2026-04-19-pro-credentials-design.md (credential pipeline + trust score)
  • .impeccable.md (brand/bans)

Phase D brings every professional-facing screen up to the same Airbnb-warm + Linear-precise bar established in consumer flows (Phase A/C). Pros currently get a functional surface with inconsistent typography (mixed StyleSheet + NativeWind, two sibling header styles), no motion language differentiation from consumer, underpowered empty/error states, and a dashboard that reads as a metrics dump rather than an operator’s cockpit. Phase D rebuilds these surfaces around a pro-specific motion language (calmer, denser, data-forward), consistent Gambarino/Switzer treatment, first-class trust-tier visuals, and a real earnings surface with chart + payout transparency.

  • Retention: pros switch apps faster than consumers (they work daily in them). A dashboard that respects their time keeps them open between jobs instead of flipping to WhatsApp.
  • Trust: Italian tradespeople are skeptical of “tech bro” tools. Warm, grounded typography + Italian editorial density signals “built for you, not Silicon Valley.”
  • Activation: current completion rate of 7-step onboarding is the single biggest pro-funnel leak. Each polish point on onboarding directly converts signups to active pros who can accept bookings.
  • Commercial upside: pros with polished dashboards recommend the platform to peers — referral channel Ideony cannot buy.
  • Operational accuracy: a calendar that feels trustworthy → pros keep availability up-to-date → fewer missed jobs → fewer consumer complaints.

Screen Catalog — Current State + Gap List

Section titled “Screen Catalog — Current State + Gap List”

Scale 1–5 (1 = raw/functional, 5 = Airbnb-tier polished). Reference: .impeccable.md.

(professional)/dashboard.tsx — Current: 3/5

Section titled “(professional)/dashboard.tsx — Current: 3/5”

Strengths: FadeInDown stagger on stat cards; online toggle with haptics (Light on press, Success/Warning on result); avatar with online indicator; shadows.sm from design tokens. Gaps:

  • Stat grid reads as “big number + small label hero metric” template — hard-ban per impeccable. Must redesign as a cockpit strip or activity timeline.
  • Title uses Switzer Bold at 22 for name but no Gambarino headline — loses Italian editorial voice for a primary surface.
  • “Quick actions” section = two identical primary-subtle tiles, feels placeholder.
  • No trust-tier surface anywhere — pros can’t see their standing at a glance.
  • Empty state for “today bookings” = generic grey pill. No illustration, no forward motion.
  • No dark mode awareness (bg-neutral-50 hardcoded).
  • StyleSheet remnants: none — NativeWind ✓. Target: 5/5 — operator-cockpit layout with Gambarino day-greeting, activity ribbon, trust tier card, calendar-slice preview, jobs-queue peek, earnings ticker.

(professional)/requests.tsx — Current: 3/5

Section titled “(professional)/requests.tsx — Current: 3/5”

Strengths: FadeInDown staggered cards; accept/decline with confirmation Alert + Warning/Success haptics; skeleton loaders; error retry state; refresh control. Gaps:

  • Uses inline Alert.alert for accept/decline — feels native-OS, not on-brand. Replace with in-screen bottom sheet confirmation with job preview + price reminder.
  • Count badge bg-accent-500 w/ raw numeral alongside the Switzer-Bold title — composition reads as decoration, not info.
  • Card layout: category · description · address · €price · buttons — no time-since-received, no urgency ranking, no distance indicator. Pros need “how fresh is this?” at a glance.
  • Mixes className + style={{ fontFamily }} — sign NativeWind font stack not wired into tailwind config as utilities.
  • No dark mode. Target: 5/5 — freshness-ranked cards with countdown-to-stale pill, distance chip, consumer trust signals (prior-customer flag), swipe-to-accept gesture option.

(professional)/calendar.tsx — Current: 2.5/5

Section titled “(professional)/calendar.tsx — Current: 2.5/5”

Strengths: react-native-calendars themed with Sole tokens; marked dates distinguish recurring (primary) vs specific (accent); AvailabilityEditor modal for slot edits. Gaps:

  • Hardcoded bg-[#FAF6EE] hex instead of colors.background or bg-background token utility — token leak.
  • react-native-calendars is a heavy, non-Reanimated library with limited theming — check if it fights NativeWind/dark mode. Flagged as candidate for swap.
  • Title is Switzer-Bold 28 — should be Gambarino per hero-screen convention.
  • Two empty states layered (one in the non-id branch, one under the calendar) — confusing UX.
  • No haptic on day-select.
  • No week/month toggle, no “today” quick-jump, no booked-slot preview on tap. Target: 4.5/5 — custom Reanimated calendar OR tightly-themed alt library, Gambarino month header, animated day selection, booking preview drawer.

(professional)/earnings.tsx — Current: 2/5 (worst offender)

Section titled “(professional)/earnings.tsx — Current: 2/5 (worst offender)”

Strengths: Memoized totals; skeleton list; refresh control; EmptyState component; animated list items. Gaps:

  • Uses StyleSheet.create entirely — Phase A convention breach (should be NativeWind like other tabs).
  • Summary card is bg: colors.primary (solid terracotta) with color: "#FFFFFF"pure white banned per impeccable.
  • “big number + small label” summary card = the exact hero-metric template banned.
  • No chart, no payout schedule, no pending/cleared split, no category breakdown. For a pro this is the single-most-consulted screen after dashboard.
  • Single-row transaction list with no grouping (by month, by category).
  • No skeleton alignment with final layout (skeleton list vs final grouped list visual mismatch).
  • No privacy toggle (sensitive amounts in public situations).
  • No dark mode. Target: 5/5 — full earnings studio with monthly-trend chart, payout timeline, pending/cleared split, category breakdown, exportable CSV, privacy-blur gesture.

(professional)/credentials.tsx — Current: 3.5/5

Section titled “(professional)/credentials.tsx — Current: 3.5/5”

Strengths: Trust tier badge surface; upload progress banner with cancel; FAB pattern; FadeInDown stagger; Gambarino title; proper Switzer stack; i18n throughout. Gaps:

  • bg hardcoded via colors.background inline style — not via Tailwind bg-background utility, inconsistent with dashboard NativeWind approach.
  • FAB uses #FAF6EE hex inline for button text — token leak.
  • No animation on trust score change when a credential gets approved mid-session.
  • Upload progress banner position competes with tab bar — needs safe-area awareness.
  • No visual ladder from BASIC → VERIFIED → ELITE showing what’s needed next.
  • Rate-limit feedback is missing (“you’ve used 8/10 uploads today”). Target: 5/5 — ladder progression card, animated trust-score counter on approval event, tier-up celebration moment.

Strengths: Gambarino header; FadeInDown list; refresh control; review sheet; proper role-gating via hook. Gaps:

  • Pure StyleSheet inline — no NativeWind.
  • Queue row is a flat list — no filters (by type, by age, by pro trust tier).
  • No keyboard shortcuts (J/K next/prev, A approve, R reject) even though admin is power user.
  • No batch actions.
  • No SLA indicator (“24-48h target, this one: 37h in queue — red flag”).
  • Approve/Reject live inside a sheet — no side-by-side doc + metadata.
  • Pro context missing — who submitted, their current trust tier, their completion history. Target: 5/5 — filter chips, SLA-colored rows, keyboard-first interactions, pro-context sidebar, batch tools.

Strengths: Progress bar, step counter, back affordance, consistent safe-area, slide-right Stack animation. Gaps: Progress bar is static fill — no spring/interpolation when step advances. No skip-to-step affordance for resume users. Header background = colors.background but with a hard border-b — slightly abrupt; consider subtle surface-elevated shelf.

onboarding/index.tsx (welcome) — Current: 4/5

Section titled “onboarding/index.tsx (welcome) — Current: 4/5”

Strengths: Gambarino 32 title, duotone Briefcase icon, bullet-list highlights card, resume vs start branching. Gaps: Welcome hero has no imagery / illustration — a photograph or custom illustration per impeccable imagery strategy would elevate. No “how long this takes” badge (“~15 min”).

Strengths: Clean form layout, chips for languages, bio + years + languages validation inline. Gaps: No character counter on bio (1000 limit invisible). No autosave — if pro backs out mid-typing, input lost. No “show me an example bio” tooltip. Error surface is a plain red text line — should be inline w/ the field.

Strengths: Debounced Mapbox autocomplete, radius stepper with +/- buttons, loading spinner in input. Gaps: No map preview — pros select a city + radius but never see their service area on a map. Critical gap: the core UI affordance promised by the spec. Radius stepper is five-step increments — feels coarse vs a slider with snap.

Strengths: Clear card-within-screen, benefits list, external-browser handoff with refetchStatus on return, ArrowSquareOut icon signals external. Gaps: No “you’ll be back in ~2 min” reassurance. No security badge (“Stripe, livello PCI-DSS”) though it’s mentioned in subtitle. No handling for “partial return” (user bounced without completing on Stripe side — needs explicit resume CTA).

onboarding/identity.tsx — Current: 3.5/5

Section titled “onboarding/identity.tsx — Current: 3.5/5”

Strengths: IdentificationCard duotone, secondary-subtle skip notice, verify + skip dual CTA. Gaps: The actual Stripe Identity sheet is not wiredstartIdentity just advances the flow. Phase D must finish the wire-up to @stripe/stripe-react-native Identity sheet. Skip CTA is too prominent — moves pro to BASIC tier without warning about search-ranking consequence.

onboarding/credentials.tsx — Current: 3.5/5

Section titled “onboarding/credentials.tsx — Current: 3.5/5”

Strengths: Reuses CredentialCard; AddCredentialSheet integration; smart CTA text (skip vs next). Gaps: No trust-score preview (“adding P_IVA raises you from 20 → 50”). Empty state is a grey dashed box — should illustrate the payoff (illustration of badges).

Strengths: Category chips (8), model toggle (3), min/max price inputs with € prefix, description. Gaps: Only one category can be priced in this screen — pro is routed to portfolio after a single submit. Pros offering multiple categories need a list view w/ add-another affordance. Price field shows 25/80 placeholder but no unit hint (”€/h” vs ”€ fixed”). Model toggle is 3 equal pills — fixed-vs-hourly are the two main choices and should be visually dominant, quote-on-request secondary.

Strengths: 3-column grid, delete affordance, permission handling, empty dashed box w/ ImageSquare, MIN_TO_PUBLISH gate, MAX_IMAGES cap. Gaps: No reorder (drag-to-reorder — pros have a hero image, matters). No caption entry (spec’s PortfolioImage.caption unused in UI). No category tagging per image. Count indicator (“2 of 10”) is Switzer-Regular tertiary — should be more prominent + color-shift when approaching min (3 to publish).

onboarding/complete.tsx — Current: 4.5/5

Section titled “onboarding/complete.tsx — Current: 4.5/5”

Strengths: CheckCircle duotone, Gambarino celebration copy, Sparkle accent, trust card with score + tier, next-step bullets, go-live CTA. Gaps: No confetti or Lottie moment of delight (spec’s “one moment of delight per flow” unfulfilled here — this is the natural spot). Trust score is static — should count up from 0 to actual value with easing.

SurfaceCurrentTarget
dashboard35
requests35
calendar2.54.5
earnings25
credentials (pro)3.55
credentials (admin)35
onboarding/_layout44.5
onboarding/index44.5
onboarding/profile44.5
onboarding/area45
onboarding/stripe44.5
onboarding/identity3.55
onboarding/credentials3.54.5
onboarding/pricing3.54.5
onboarding/portfolio44.5
onboarding/complete4.55

J1 — Morning check-in: Dashboard → Earnings → Availability

Section titled “J1 — Morning check-in: Dashboard → Earnings → Availability”

Pro opens app, sees last-24h activity + today’s bookings + pending payout + calendar slice. Taps earnings tile → full earnings studio. Back → taps calendar → adjusts this afternoon’s availability. Total: 3 taps, <10 seconds, zero friction.

Welcome → Profile → Area → Stripe (external) → Identity (Stripe sheet) → Credentials (skippable) → Pricing → Portfolio → Complete w/ confetti. Each step has an “autosave on blur” safety net + visible progress + correct resume behavior.

Push notification arrives → deep-link to requests tab → top card has freshness badge + distance + fixed/hourly price → swipe-right to accept → confirmation sheet with job details + consumer name + address → confirm → card animates out + success haptic + booking ribbon appears on dashboard.

J4 — Credential upload → approval → trust-tier-up

Section titled “J4 — Credential upload → approval → trust-tier-up”

Credentials screen → Add → picker → upload progress (with cancel) → Pending state with “Review in 24-48h” → push arrives on approval → opens to credentials screen → score counts up + tier badge transitions with haptic Success + brief Sparkle animation → if crossed a tier threshold, modal “You’re now VERIFIED. Your rank in search improves immediately.”

Different from consumer? — Yes. Consumer motion is romantic (staggered reveals, parallax hero photos, warm fades). Pro motion is operational:

AxisConsumerPro
Entry400ms spring stagger250ms ease-out, lighter delay (40ms vs 80ms)
HeroParallax photo on scrollStatic cockpit — content density over scenic reveal
FeedbackWarm (heart flutter, scale bounce)Tactile (short haptic, quick color flash, no scale)
Empty statesIllustrated, generous whitespaceSmaller illustration, denser instruction
SuccessConfetti, full-screen celebrationCheckmark pulse + ribbon banner, stays on-task
ScrollElastic/bouncyDamped, precise

Implementation: share @/lib/motion/pro.ts with pro-specific presets — proEnter, proStagger, proSuccessPulse, proTap. Consumer keeps existing Reanimated defaults.

SurfaceStateCopy (IT)IllustrationAction
DashboardNo bookings today”Oggi nessun appuntamento. Buona occasione per aggiornare il profilo.”Calendar + sun illustrationCTA: Update profile
RequestsNo pending requests”Nessuna richiesta al momento. Ti avviseremo appena arriva.”Mailbox illustrationCTA: Check availability
RequestsNetwork error”Connessione interrotta. Riprova.”Disconnected iconRetry button
CalendarNo availability set”Imposta la tua disponibilità per iniziare a ricevere richieste.”Week-grid illustrationCTA: Add first slot
CalendarAll week booked”Settimana piena. Buon lavoro!” (positive framing)Checkmark streakCTA: View next week
EarningsNo history”I tuoi guadagni appariranno qui dopo il primo lavoro.”Empty wallet illustrationCTA: Complete onboarding if not done
EarningsThis-month zero but history exists”Ancora nessun guadagno questo mese.” + trendline of prior monthsSmall sparkline
CredentialsNone uploaded”Carica la tua prima certificazione per salire di livello.”Badge stack illustrationCTA: Add credential
CredentialsPending review”In revisione · Ti avviseremo in 24-48h.” + estimated completion chipPending badge spinner
CredentialsRejected”Documento non approvato. Vedi motivo →“Warning badgeCTA: View reason + re-upload
Admin queueEmpty”Coda vuota. Niente da revisionare.”Empty inbox
Onboarding resumePartial progress”Hai completato 4 di 7 passi. Riprendi da dove eri.”Stepper illustrationCTA: Resume

All empty-state illustrations: hybrid imagery strategy → source Humaaans-customized for pro characters + custom Italian-palette vector drops, OR defer to illustrator engagement (open decision — see Phase A plan).

  • BASIC (0–30): subtle surface — bg: colors.surface, border: colors.border, icon: User duotone olive. NO prominent badge in results. “In costruzione” sub-label permitted.
  • VERIFIED (31–70): solid olive pill bg: #6E7F3C + cream #FAF6EE text + ShieldCheck weight=“fill” icon. The Sole trust color anchored.
  • ELITE (71+): solid terracotta pill bg: #B35F3B + cream text + Star weight=“fill” icon (gold strokeWidth 0.5). No gradient — composition relies on icon + texture, not color-gradient text or multi-stop fill (bans respected).
  • Dashboard: small tier badge in header area next to name + avatar — always visible, low prominence.
  • Credentials tab: large tier badge w/ score — heroic placement.
  • Pro profile (consumer side): tier badge in header (already designed in Phase A).
  • Results cards (consumer side): tier badge in corner (already designed in Phase A).
  • Onboarding complete: tier badge in trust card — already present, polish moment of delight.

On server notification that trust score crossed a tier boundary (WebSocket or push-then-open):

  1. Haptic: Haptics.notificationAsync(Success).
  2. Score counter animates from old to new (Reanimated, 800ms ease-out).
  3. Badge swaps via crossfade (200ms) + pulse scale 1.0 → 1.08 → 1.0 (400ms spring).
  4. One-time modal: “Sei ora VERIFICATO. La tua posizione nei risultati migliora subito.”
  5. Analytics event pro.tier_up with old + new tier.

Ladder card on credentials screen always visible — shows score progress + next tier threshold + which credential type would advance fastest (using trust-score formula from credentials spec). This is the self-service growth loop.

Chart library choice: victory-native v41 (Skia-backed, Reanimated-compatible, tree-shakeable) vs react-native-gifted-charts vs react-native-svg-charts.

Recommendation: victory-native — Skia-backed renderer is a step-change for mobile perf + looks-right on iOS + Android + Web. Handles Reanimated gesture-driven interactions natively. Accepts custom palette (Sole). Tree-shakeable. ~250KB gzipped for what we need (bar + line).

Fallback: react-native-gifted-charts if victory-native has Expo Web issues — pure-JS, slightly less polished but universally compatible.

Layout:

┌─────────────────────────────────────────┐
│ Guadagni [privacy 👁] │ header
├─────────────────────────────────────────┤
│ │
│ €2.347,50 │ Gambarino 42, terracotta
│ Questo mese │ Switzer-Regular 14 secondary
│ │
│ ↗ +18% vs mese scorso │ Switzer-Medium 13 success
│ │
│ [sparkline: 30 days, interactive] │ Skia chart
│ │
├─────────────────────────────────────────┤
│ Prossimo pagamento │
│ ┌─────────────────────────────────────┐ │
│ │ €1.230,00 → venerdì 24 │ │ payout card
│ │ Saldo Stripe │ │
│ └─────────────────────────────────────┘ │
├─────────────────────────────────────────┤
│ Per categoria │
│ Idraulica ████████████ €1.450 │ horizontal bar
│ Elettrica ██████ € 650 │
│ Caldaie ██ € 247 │
├─────────────────────────────────────────┤
│ Storico [csv export] │
│ [grouped transactions by month] │
└─────────────────────────────────────────┘

Privacy toggle: eye icon top-right. On tap: numbers replace with dots (•••• €) in all amount surfaces for 30s session (resettable). For quick public-space checks.

Payout timing UX: read Stripe::Payout API via BE proxy (new route GET /professionals/me/payouts/next). Show:

  • Amount ready to pay out
  • Expected arrival date (from Stripe payout schedule, typically T+2 for EU)
  • “On hold” amount separately (disputed, in-process refunds)
  • Stripe-deep-link “Vedi dettagli su Stripe” for authoritative view

Privacy considerations:

  • Amounts never in push notification body (only generic “Nuovo pagamento in arrivo”).
  • Privacy toggle must not persist across sessions (always visible fresh on app open).
  • Screenshots: flag FLAG_SECURE on Android for the earnings screen (prevents screenshot in some contexts + suppresses from recent-apps preview).
  • iOS equivalent: hide content when app backgrounds via existing ExpoSecureStore pattern, or manual AppState listener + overlay.

CSV export: server-side generation (GET /professionals/me/earnings/export.csv date-range param) — leverages existing booking records. Share via system share sheet.

Each milestone ships as a standalone PR, 1–3 days each, dependency-ordered.

M-D1: Token unification + pro-motion library (2 days)

Section titled “M-D1: Token unification + pro-motion library (2 days)”
  • Replace remaining StyleSheet usage in earnings.tsx with NativeWind + design tokens
  • Replace hex-literal backgrounds with token utilities (bg-[#FAF6EE]bg-background)
  • Wire Switzer/Gambarino into tailwind.config.js as font utilities (no more inline fontFamily style)
  • Create @/lib/motion/pro.ts with proEnter, proStagger, proSuccessPulse, proTap presets
  • Depends on:
  • Risk: low
  • Unblocks: all downstream pro milestones
  • Replace stat grid with activity ribbon + earnings ticker + trust tier card + today preview + upcoming-week strip
  • Gambarino day-greeting headline (“Buongiorno, Marco”)
  • Integrate pro-motion library for entry staggers
  • Dark mode awareness
  • Depends on: M-D1
  • Risk: medium — cockpit density requires iteration
  • Install victory-native + Skia
  • Implement layout above (sparkline, category bars, payout card, transaction history)
  • Privacy toggle
  • CSV export endpoint + client integration
  • New BE route GET /professionals/me/payouts/next
  • Depends on: M-D1
  • Risk: medium — chart lib integration + Skia Expo Web compat
  • Freshness pill (time-since-received, red after 30min pending)
  • Distance chip
  • Swipe-to-accept gesture (react-native-gesture-handler)
  • In-screen bottom sheet confirmation replacing native Alert
  • Pro-motion entry
  • Depends on: M-D1
  • Risk: low
  • Evaluate: keep react-native-calendars themed deeper OR swap for Reanimated custom calendar
  • Gambarino month header
  • Haptic on day-select
  • Booking-preview drawer on day tap (shows that day’s bookings + availability slots)
  • Single coherent empty state
  • Depends on: M-D1
  • Risk: medium — calendar library decision has scope impact

M-D6: Credentials screen + tier ladder (2 days)

Section titled “M-D6: Credentials screen + tier ladder (2 days)”
  • Ladder progression card (BASIC → VERIFIED → ELITE with next-step hint)
  • Animated trust score counter
  • Tier-up celebration moment (haptic + crossfade + scale pulse + modal)
  • Rate-limit feedback surface
  • Safe-area-aware upload progress banner
  • Depends on: M-D1, trust-tier-up WebSocket or push event (BE work)
  • Risk: medium — requires BE event wiring
  • Filter chips (type, age, pro-tier)
  • SLA-colored rows (green <24h, yellow 24–48h, red >48h)
  • Keyboard shortcuts (J/K/A/R)
  • Pro-context sidebar (pro completion history + current tier + prior approvals/rejections)
  • Side-by-side doc + metadata layout (tablet-optimized, collapses on phone)
  • Batch approve/reject
  • Depends on: M-D1
  • Risk: low

M-D8: Onboarding wizard polish — part 1 (1.5 days)

Section titled “M-D8: Onboarding wizard polish — part 1 (1.5 days)”
  • Welcome screen: add imagery + “~15 min” badge
  • Profile screen: bio character counter, autosave, error-inline
  • Area screen: Mapbox map preview with radius circle (critical missing UI)
  • Complete screen: Lottie confetti + score count-up
  • Depends on: M-D1
  • Risk: low (mostly additive)

M-D9: Onboarding wizard polish — part 2 (2 days)

Section titled “M-D9: Onboarding wizard polish — part 2 (2 days)”
  • Identity screen: finish Stripe Identity sheet wiring + consequence warning on skip
  • Credentials screen: trust-score preview + illustrated empty state
  • Pricing screen: multi-category list + dominant fixed-vs-hourly toggle + unit hints
  • Portfolio screen: drag-to-reorder + caption entry + category tagging
  • Progress bar spring animation on step advance
  • Depends on: M-D1, M-D8
  • Risk: medium — Stripe Identity wire-up has external-dependency surface

M-D10: Pro-specific empty/error component pack (1 day)

Section titled “M-D10: Pro-specific empty/error component pack (1 day)”
  • Canonical ProEmptyState + ProErrorState components wrapping EmptyState with pro motion + illustration slot
  • Port illustrations (sourced from decision in Phase A illustration pack question)
  • Replace every pro-surface empty/error with these components
  • Depends on: M-D1, Phase A illustration decision (blocker if still open)
  • Risk: blocked if illustration source not decided

M-D11: Accessibility + dark mode pass (1.5 days)

Section titled “M-D11: Accessibility + dark mode pass (1.5 days)”
  • Every pro screen: dark variants via NativeWind class modifiers
  • Every interactive element: accessibilityLabel + accessibilityRole + accessibilityState
  • Focus-visible rings on web
  • Screen-reader labels on chart surfaces (earnings)
  • Depends on: M-D1 through M-D9
  • Risk: low

M-D12: Preview system coverage + visual regression snapshot (1 day)

Section titled “M-D12: Preview system coverage + visual regression snapshot (1 day)”
  • Add every pro route + state permutation to Playwright tour (persona=pro)
  • Seed fixtures for: empty earnings, full earnings, all tier states, pending credentials, rejected credentials, partial onboarding at each step
  • Establish baseline snapshots on first main-merge
  • Depends on: M-D1 through M-D11
  • Risk: low

Total estimated: 22 days (≈4.5 weeks), but many can parallelize post M-D1 across agents/worktrees.

Genuine unknowns. No speculation.

  1. react-native-calendars swap? Keep themed or replace with custom Reanimated calendar? Swap cost vs theming-limit risk unclear. Spike: 4hrs to check dark-mode + token compatibility.
  2. victory-native vs react-native-gifted-charts for earnings chart — needs Expo Web compatibility test. If victory-native Skia fails on web, fallback.
  3. Illustration pack decision (inherited from master plan) — blocks M-D10. Escalate: decide this before Phase D starts or M-D10 becomes blocked.
  4. Trust tier-up delivery mechanism — WebSocket via existing Socket.IO gateway, or push notification only? WebSocket is snappier but adds screen-specific socket subscription cost. Decide before M-D6.
  5. Batch actions in admin queue — needed for MVP 0 or Phase D+? Low admin volume means maybe post-MVP. Confirm with admin user volume projection.
  6. CSV export location — server-side generated endpoint (heavier BE work) vs client-side generation from cached bookings (simpler, but may be slow for >1000 records). Recommend server-side.
  7. Earnings screenshot prevention — iOS lacks direct FLAG_SECURE equivalent. Manual overlay on AppState change is a workaround but UX-fragile. Accept the limitation or invest in native module? Recommend accept.

All pro surfaces inherit the brand hard bans from .impeccable.md:

  • No side-stripe borders >1px
  • No gradient text
  • No glassmorphism
  • No pure black/white (always tint to Sole palette — replace #FFFFFF in earnings summary with cream #FAF6EE)
  • No big-number-hero metric decoration
  • No reflex-default fonts
  • No side-stripe accents

Current Phase D audit already flagged violations:

  • earnings.tsx: #FFFFFF text on terracotta → replace with cream
  • dashboard.tsx stat grid: big-number-hero template → redesign as cockpit ribbon
  • calendar.tsx: hardcoded #FAF6EE hex → use colors.background token
  • Every pro screen uses NativeWind + design tokens (zero StyleSheet.create, zero hex literals)
  • Every pro screen uses Gambarino for headlines + Switzer for body (font utilities in Tailwind config)
  • Every pro surface has branded empty + error states (not generic grey boxes)
  • Dashboard redesigned away from big-number hero template (impeccable compliance)
  • Earnings screen includes chart + payout timeline + privacy toggle + CSV export
  • Trust tier has 3 distinct visual treatments + tier-up celebration moment
  • Onboarding completes in <15 min for 80% of new pros (instrument + measure)
  • Admin queue has keyboard shortcuts + filters + SLA coloring
  • Every pro screen dark-mode compatible
  • Every pro route covered in Playwright tour + visual regression baselines
  • Phase D Lost Pixel diff < 5% on post-merge runs (change intentional, not chaotic)
  • 2026-04-20 — Spec created. Inventoried 16 pro-side surfaces, scored current polish (average 3.4/5), drafted 12 milestones totaling ~22 days, identified 7 open decisions. Trust tier visual treatment locked (3 tiers, no gradient, icon+color anchored). Earnings spec includes victory-native chart library choice + privacy toggle + CSV export. Pro motion language documented as distinct-from-consumer (operational vs romantic).