MyManny — Product Catalog
MyManny — Product Catalog
Section titled “MyManny — Product Catalog”MyManny is a skilled-trades marketplace connecting Italian consumers with vetted professionals (plumbers, electricians, HVAC, locksmiths, and more). The product has two intended modes: a normal booking flow for planned jobs and an SOS emergency-dispatch flow. Product direction is not a claim that every described flow or payment is currently shipped.
This document catalogs MyManny product surfaces and their implementation states, linking to roadmap.md §Feature Matrix. Design direction and planned flows are distinguished from shipped behavior.
The catalog is Phase 1 of a three-phase product-doc strategy. Phase 2 (a Slidev/Marp cofounder + investor demo deck auto-generated from this catalog) and Phase 3 (a public Storybook component gallery for apps/mobile/components/) are deferred — see Future tiers below.
Status legend
Section titled “Status legend”stable— production-ready, hardening completebeta— feature-complete, hardening still in flightalpha— usable end to end, polish + edge cases pendingshipped (date)— landed in the most recent sprintstub— placeholder UI present, behaviour not wiredplanned— roadmap-only, no code yet
User identity, authentication, authorization. Backed by Clerk (@clerk/expo on mobile, @clerk/backend JWT verification on API). Italian-first identifier flow (email + social) feeding role-based access control across consumer / professional / admin surfaces.
Sign In
Section titled “Sign In”Status: stable · Platforms: iOS, Android, Web · ADR 0024 · ADR 0005
Single Clerk identifier-first flow that accepts email or any social provider in one prompt rather than branching upfront. Returning users land on the home screen with a session in under two seconds; first-timers are seamlessly forwarded into Sign Up without re-typing their identifier. Italian copy is the default surface, English mirrors it via react-i18next.
Sign Up
Section titled “Sign Up”Status: stable · Platforms: iOS, Android, Web · ADR 0005
Three-slide welcome tour leads into a social-first Sign Up (Google, Apple, Facebook) with email + OTP as the fallback. Clerk components are deeply themed to the Italian Sole palette so the auth surface feels native, not bolted-on. JIT (just-in-time) provisioning writes the Prisma User row on first authenticated call to /users/me.
2FA / MFA
Section titled “2FA / MFA”Status: alpha · Platforms: iOS, Android, Web
Clerk TOTP support is wired but currently dashboard-managed — users opt in via the Clerk-hosted account portal. App-level enrolment UI is tracked as roadmap task #140. All existing user MFA was audited and wiped 2026-04-21 to reset to a clean baseline before public launch.
Status: stable · Platforms: API · ADR 0024
Three roles — CONSUMER, PROFESSIONAL, ADMIN — gate every API surface via NestJS @Roles() metadata + RolesGuard. The role lives on the Prisma User row and is flipped atomically by the onboarding flow when a consumer becomes a professional.
JWT Verify
Section titled “JWT Verify”Status: stable · Platforms: API
Every request is authenticated by JwtAuthGuard, which delegates token verification to the IDENTITY_PROVIDER seam (ClerkIdentityProvider → @clerk/backend verifyToken() today) and attaches a typed AuthenticatedUser to the request. Controllers read identity exclusively via @CurrentUser() — never from request bodies — eliminating an entire class of impersonation bugs. Per-user cache (auth:user:<clerkId>, 60s TTL) keeps the verify path off the hot loop.
Clerk Webhooks
Section titled “Clerk Webhooks”Status: stable · Platforms: API
user.created, user.updated, and user.deleted events are signed by svix and verified with req.rawBody (NOT a re-stringified body — that breaks signature verification). Webhook handlers keep the Prisma User mirror consistent with the Clerk source of truth and bust the auth Redis cache on role changes.
Discovery
Section titled “Discovery”How consumers find professionals. Trade-category browsing, full-text search, PostGIS-backed proximity, and a map-first results view powered by Mapbox.
Category Search
Section titled “Category Search”Status: stable · Platforms: iOS, Android, Web
Browse-by-trade entry point on the home screen — plumber, electrician, HVAC, locksmith, and the long tail. Each tap fans out into a PostGIS ST_DWithin query against the consumer’s current location with a 30-second Redis result cache to keep the home grid snappy on repeat visits.
Text Search
Section titled “Text Search”Status: stable · Platforms: iOS, Android, Web
Free-text search bar covers professional names, trade keywords, and service descriptions. Postgres full-text index drives the query; Redis caches every search slug for 30 seconds to absorb double-taps and back-button repeats without re-hitting the database.
Results Screen
Section titled “Results Screen”Status: stable · Platforms: iOS, Android, Web · Spec · ADR 0028
Map-first list/map split that anchors discovery to geography — a 60/40 split with cards underneath the map, not behind a tab. Filters (trade, distance, trust tier, availability) and sort (proximity, rating, price) hang off the top bar. The map renders in the custom Italian Sole Mapbox Studio style so the surface feels brand-consistent rather than generic Google blue.
Pro Profile
Section titled “Pro Profile”Status: stable · Platforms: iOS, Android, Web · Spec
Detail page surfaces the data that builds trust before booking — trust tier badge (BASIC / VERIFIED / ELITE), credential summary, recent reviews with rating histogram, service area, base price band, onboarding-configured service line items, portfolio/avatar photo, and a prominent CTA to start a booking or send a chat message. When the consumer shares coordinates, the API returns the same haversine distance used by search; otherwise distance is null. Search cards expose the recorded average response minutes as a fast-responder signal — travel ETA is deliberately absent until SOS tracking has a real ETA source. Profile data is cached in Redis for five minutes to keep the page snappy on warm visits.
Mapbox Maps
Section titled “Mapbox Maps”Status: beta · Platforms: iOS, Android, Web · ADR 0008
Native maps via @rnmapbox/maps plus the Mapbox APIs (Geocoding, Directions, Matrix, Places). The custom Sole-palette style was authored in Mapbox Studio so the map matches the rest of the app rather than fighting it. The free tier (50K MAU + 100K API requests/month) carries us comfortably through MVP 0.
Booking
Section titled “Booking”Normal-mode booking direction is to select a published professional slot, pay without a second professional confirmation, and reserve that slot for ten minutes during checkout. This is approved product direction, not a claim that it has shipped; a slot reservation does not itself establish provider-side payment authorization or capture.
Create Booking
Section titled “Create Booking”Status: planned · Platforms: iOS, Android, Web
The 2026-09-30 design direction selects a published professional slot, reserves it for ten minutes during checkout, and completes payment without a second professional confirmation. Existing implementation and prototype do not establish this flow as shipped; the slot reservation does not guarantee provider-side payment authorization or capture.
Booking Lifecycle
Section titled “Booking Lifecycle”Status: planned · Platforms: iOS, Android, API
Current booking records move through workflow states including PENDING, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED, and NO_SHOW. Persisted state transitions do not establish payment authorization, capture, release, or payout.
Change Orders
Section titled “Change Orders”Status: stable · Platforms: iOS, Android, API
Change-order approval updates the booking total; it does not itself establish that a payment authorization or captured amount has been updated.
Booking History
Section titled “Booking History”Status: stable · Platforms: iOS, Android
Both consumer and professional get a chronological list of past and upcoming bookings with status, counterpart, address, and total. A displayed receipt or booking total does not independently prove Stripe payment authorization, capture, transfer, or payout.
Cancel Booking
Section titled “Cancel Booking”Status: stable · Platforms: iOS, Android
Consumer-initiated cancellation with a confirm sheet and reason capture. Current behavior updates the booking and escrowStatus workflow marker; the marker alone does not prove a Stripe refund has completed.
SOS is an emergency-dispatch product direction. The current dispatcher auto-assigns the first professional to accept. The approved 2026-09-30 consumer flow requires pro acceptance first, then consumer acceptance of the same bound total and payment; the new sequence is not established as shipped.
SOS Request
Section titled “SOS Request”Status: planned · Platforms: iOS, Android · Historical flow spec
The 2026-09-30 product direction is professional acceptance first, then consumer acceptance of the same bound total, then payment. The design export is a reference; existing dispatch behavior does not establish this full sequence as shipped.
Candidate Matching
Section titled “Candidate Matching”Status: stable · Platforms: API · Spec
Server-side ranker queries pros by PostGIS radius (ST_DWithin) intersected with current availability, SOS opt-in flag, trust tier, and accept-rate history. The output is a candidateQueue of up to 30 pros that drives sequential dispatch (AUTO) or top-10 push (PICK_LIST).
SOS Pricing
Section titled “SOS Pricing”Status: planned · Platforms: iOS, Android, API · Historical flow spec
The 2026-09-30 product direction binds the total when the professional accepts; the consumer must then accept that same total and pay before the job proceeds. Displayed example prices are not tariffs. The flow is not established as shipped. Release is eligible only after both parties record their required completion; absence of either completion does not trigger automatic release. See ADR 0006.
Accept / Decline
Section titled “Accept / Decline”Status: planned · Platforms: iOS, Android · Historical flow spec
The approved product sequence is professional acceptance, consumer acceptance of the same total, and payment. Existing accept/decline mechanics are not evidence that this complete sequence is implemented.
SOS Pick-List Mode
Section titled “SOS Pick-List Mode”Status: shipped (2026-04-23) · Platforms: iOS, Android, Web · ADR 0030 · Spec
The existing dispatch option broadcasts the request to the top 10 candidates, who may submit quotes; the consumer selects one. This dispatch selection flow predates the 2026-09-30 product direction and does not by itself implement the later pro-acceptance → consumer-acceptance-of-the-same-total → payment sequence.
Live Tracking
Section titled “Live Tracking”Status: beta · Platforms: iOS, Android · Spec
Consumer sees the pro’s position on a live map after acceptance. The pro’s useProLocationStream hook emits GPS at a 7-second cadence to a Socket.IO /tracking namespace; the consumer’s LiveTrackingMap subscribes and renders the marker with a status pill (Confermato → In arrivo → Arrivato → Completato). Tier 2 (full Directions API ETA + route polyline) is queued post-MVP 0.
Real-time messaging between consumer and professional during a booking. Socket.IO over the NestJS WebSocket gateway, message persistence in Postgres, history scrollback, and unread badges.
Real-time Chat
Section titled “Real-time Chat”Status: beta · Platforms: iOS, Android
Per-booking chat thread with message history, typing indicator, and unread counter. The Socket.IO gateway authenticates connections via the same Clerk JWT used by REST, so identity is consistent across both surfaces. Hardening still in flight: media attachments, read receipts, and push fallback when the socket is closed.
Reviews
Section titled “Reviews”Post-booking reviews that feed back into the trust tier engine. Unlocked only after COMPLETED status, with a duplicate-submission guard at the database level.
Create Review
Section titled “Create Review”Status: stable · Platforms: iOS, Android
5-star rating + optional text review. The CTA only unlocks after the booking transitions to COMPLETED, and a @@unique([bookingId, authorId]) Prisma constraint prevents accidental duplicate submissions on flaky networks. Submissions update the pro’s aggregate rating cache in Redis for fast profile reads.
Display Reviews
Section titled “Display Reviews”Status: stable · Platforms: iOS, Android, Web
Pro profile shows aggregate rating, a 5-star breakdown histogram, and the recent reviews list (newest first, paginated “load more”). Author identity is composed BE-side from Clerk — first name + last-name initial plus avatar — so no full name, email, or phone is ever exposed on the review surface. Italian + English copy is localised on the server so the review surface respects the consumer’s Accept-Language even when the original review was written in the other language.
Saved Addresses
Section titled “Saved Addresses”Consumers store the addresses they book at most so the booking form fills in with one tap instead of a full address search every time.
Address Book
Section titled “Address Book”Status: beta · Platforms: iOS, Android, API
Address rows (label, formatted address, coordinates, default flag) with full CRUD at /addresses. Default is exclusive — setting one clears the others in a transaction. Soft cap of 20 addresses per user; rows cascade-delete with the user so GDPR erasure needs no special case. The booking itself keeps its own serviceAddress string: the address book is a form-filling convenience, not a booking dependency.
Help Center
Section titled “Help Center”Real support resources, no invented content.
Support Screen
Section titled “Support Screen”Status: beta · Platforms: iOS, Android
/help aggregates only resources that exist: the support mailbox (support@mymanny.it, same address referenced by the Terms), the Terms of Service and Privacy Policy, and the running app version. FAQ editorial content is deliberately absent until product writes it — the screen ships no dead taps and no placeholder copy.
Payments
Section titled “Payments”Stripe Connect Express remains the selected integration. Payment readiness, capture, funds movement, and payout are not established by booking status or prototype screens; provider legal go/no-go and verified end-to-end payment behavior remain outstanding. See ADR 0006.
Stripe Connect
Section titled “Stripe Connect”Status: beta · Platforms: iOS, Android, API · ADR 0006
Pros connect their bank account via Stripe Connect Express onboarding — KYC and payout details handled by Stripe-hosted forms, never our UI. The StripeService wraps account creation, status polling, and capability requirements so the rest of the app sees a single typed surface.
Booking and SOS payment state
Section titled “Booking and SOS payment state”Status: planned · ADR 0006
Booking records expose application workflow markers such as escrowStatus; those markers alone do not prove that a PaymentIntent was created, authorized, captured, held, released, or refunded. The currently implemented Connect PaymentIntent shape and consumer-confirmation booking update do not demonstrate those external funds movements or a payout. No automatic release after 48 hours is implemented. For the approved SOS lifecycle, release is eligible only after both the professional and consumer complete; if either completion is missing, there is no automatic release. The provider-specific payment model and end-to-end flow require written provider/legal confirmation before use. These are payment design constraints, not shipped behavior.
Refunds
Section titled “Refunds”Status: planned · Platforms: API · ADR 0006
Application refund markers and webhook code do not by themselves establish an end-to-end Stripe refund path for the approved charge model. Reconcile and verify Stripe-side refund completion before presenting a refund as completed.
Stripe Webhooks
Section titled “Stripe Webhooks”Status: stable · Platforms: API
Raw-body signature verification (NOT JSON.stringify — that breaks signing), immediate ACK to Stripe, and async BullMQ job processing with two-layer idempotency: a StripeEventLog processedAt guard plus BullMQ jobId: stripe:{eventId} dedup. Admin endpoint GET /admin/stripe-events?status=stuck surfaces stalled events for ops triage. This infrastructure does not itself establish end-to-end booking payment, refund, or payout behavior.
Notifications
Section titled “Notifications”Multi-channel transactional notifications via Novu Cloud (EU region). Email through Resend, SMS through Twilio, push through Expo Push.
Multi-channel Notifications
Section titled “Multi-channel Notifications”Status: stable · Platforms: API · ADR 0007
Six Novu workflow templates cover the booking + SOS lifecycle — confirmation, reminder, cancellation, completion, refund, dispute. Channel preference is per-subscriber and per-event, so users can mute SMS without losing email or push for the same event class. Server stays vendor-agnostic by speaking only to Novu; channel providers swap underneath.
Push Notifications
Section titled “Push Notifications”Status: beta · Platforms: iOS, Android · ADR 0007
Expo Push Token registered on app start, posted to the API, and forwarded to Novu as the push channel for that subscriber. Tap-handling routes the user back into the relevant booking, dispatch, or chat thread via Expo Router deep links. Hardening pending: badge-count synchronisation across iOS + Android.
Pro Tools
Section titled “Pro Tools”The professional-side workspace — onboarding, dashboard, availability management, earnings, and a planned calendar view.
Consumer → Pro Funnel
Section titled “Consumer → Pro Funnel”Status: shipped (2026-04-23) · Platforms: iOS, Android, Web · Spec
A “Become a professional” Briefcase row on the consumer profile tab routes into the 8-step onboarding wizard. The OnboardingController accepts both CONSUMER and PROFESSIONAL roles per-method (rather than class-level), so consumers can start the wizard mid-session. The final step’s completeOnboarding runs in a $transaction that flips User.role to PROFESSIONAL and busts the auth:user:${clerkId} Redis cache so the next request sees the new role immediately.
Pro Dashboard
Section titled “Pro Dashboard”Status: stable · Platforms: iOS, Android
Single-screen view of what the pro needs to know on a working day — earnings to date, upcoming bookings, pending change-order approvals, and credential expiry warnings. Designed to feel like a tools-truck command-strip rather than a corporate dashboard.
Availability
Section titled “Availability”Status: stable · Platforms: iOS, Android, API
Weekly recurring schedule + one-off slot blocks. Stored as a normalised slot table so consumer-side booking can intersect with ST_DWithin proximity in a single Postgres query rather than an N+1 lookup.
Earnings
Section titled “Earnings”Status: stable · Platforms: iOS, Android
Payout history, pending balance, and per-booking breakdown. Reads from the local mirror of Stripe transfer events rather than calling Stripe live on every screen render — keeps the page fast and Stripe rate-limits comfortable.
Calendar
Section titled “Calendar”Status: stub · Platforms: iOS, Android
Visual calendar with blocked-slot management is a placeholder — the data model exists (the slot table from Availability) but the visual UI is roadmap Phase 1. Today, pros manage availability from the list view.
Credentials
Section titled “Credentials”Trust-building credential upload + admin review pipeline. P_IVA, insurance certificates, ALBO membership, F-Gas certifications, ID documents, training diplomas, manufacturer certs. Drives the BASIC / VERIFIED / ELITE trust tier badge.
Credential Upload
Section titled “Credential Upload”Status: stable · Platforms: iOS, Android, API · Spec
Pro picks a document type, the API mints a 600-second presigned R2 URL, the mobile client uploads directly to Cloudflare R2 (no API server in the data path). Throttled at 20 uploads/minute via @nestjs/throttler to absorb bursts without abuse. The presigned-URL pattern keeps the API server out of the way of multi-MB document uploads.
Credential Review
Section titled “Credential Review”Status: stable · Platforms: API · Spec
Admin queue at GET /admin/credentials lists PENDING credentials with the document, the pro, and a side-by-side approve/reject form. Approval triggers a trust-score recompute; rejection captures a reason that the pro sees on their credentials screen so they can re-upload a better scan.
Trust Score
Section titled “Trust Score”Status: stable · Platforms: API · Spec
Weighted score: P_IVA 30, insurance 25, ALBO 20, F-Gas 15, others 10/5. Tiers: BASIC 0–30, VERIFIED 31–70, ELITE 71+. Recomputed on every credential approval/rejection. The tier badge surfaces on the pro profile, results cards, and SOS quote cards — so consumers see trust before they see price.
LangGraph.js state machines fronting GPT-5.4 Mini (primary) and Gemini 2.5 Flash (fallback). LangSmith EU traces every run for offline review.
AI Job Estimation
Section titled “AI Job Estimation”Status: alpha · Platforms: API · ADR 0011
LangGraph state machine consumes the consumer’s job description (text + optional photo) and returns a structured estimate: trade category, estimated duration band, parts likely needed, and a price range. Wired into the SOS triage chat so the pro sees a structured summary, not a wall of free text.
AI Smart Scheduling
Section titled “AI Smart Scheduling”Status: alpha · Platforms: API · ADR 0011
LangGraph graph with tool nodes for availability lookup, distance matrix, and pro filtering. Suggests time-slot + pro pairings that maximise pro utilisation and minimise consumer wait. Currently dogfooded; consumer-facing rollout queued post-MVP 0.
The production-readiness underneath everything — health probes, internationalisation, and security headers.
Health Endpoint
Section titled “Health Endpoint”Status: stable · Platforms: API
/health exposes liveness + readiness payloads consumed by the smoke-prod GitHub Actions job (curl retry loop + Playwright authed flows post-deploy) and by Better Stack’s 1800s external monitor (deliberately not on the 180s cadence — /health runs SELECT 1, and polling it every 3 minutes would keep the Neon free-tier compute awake 24/7). Readiness covers Postgres + Redis + Stripe + Clerk so a partial outage is visible before user traffic hits.
i18n IT+EN
Section titled “i18n IT+EN”Status: stable · Platforms: iOS, Android, API · ADR 0023
Italian-first by default, English mirrors. Server: nestjs-i18n keyed on Accept-Language / x-lang header with a t(key, fallback, args?) helper that no-ops outside HTTP context (so unit tests don’t have to mock the full i18n module). Mobile: i18next + react-i18next + expo-localization for auto-detection.
Security Headers
Section titled “Security Headers”Status: stable · Platforms: API
@fastify/helmet ships every response with CSP, HSTS, X-Frame-Options, Referrer-Policy, and a permissions policy tuned for the mobile-API surface. CORS is locked to the canonical FE host; raw-body verification on Stripe + Clerk webhooks lives outside the global parser.
Future tiers
Section titled “Future tiers”This catalog is Phase 1 of a three-phase product-doc strategy.
- Phase 2 — Cofounder/investor demo deck. Slidev or Marp generation from this catalog, auto-rebuilt on roadmap commit. Hosted at
docs.ideony.is-a.dev/demo. Estimated effort: ~2 hours. Not yet scheduled. - Phase 3 — Storybook component gallery. Public showcase of
apps/mobile/components/w/ Sole tokens. Hosted atdocs.ideony.is-a.dev/storybook. Estimated effort: ~1 day. Not yet scheduled.
Capturing screenshots
Section titled “Capturing screenshots”This catalog references screenshots at docs/assets/product/<feature-slug>.png that are not yet captured. To populate them:
- Run the relevant Playwright spec:
pnpm --filter @mymanny/e2e exec playwright test e2e/web/demo/<spec>.spec.ts --update-snapshots - Move the captured PNG into
docs/assets/product/. - The catalog references the file relatively; add a fallback
<!-- SCREENSHOT MISSING -->HTML comment if the file does not yet exist.
Screenshots are NOT generated automatically yet. Phase 2 (demo deck) will introduce automated capture as part of the slide build. Until then, this is a manual one-time task.