Designing Multi Role Service Marketplace Apps
Markdown--- name: designing-multi-role-service-marketplace-apps description: Defines features, UI flows, and technical architecture for two-sided Android marketplace apps connecting foreign residents with local service providers. Use when designing product requirements, screen flows, database structure, or reviewing/revising existing Android UI/UX for service-request, chat, booking, or payment features in Kotlin/Jetpack Compose apps with a Go backend. ---
When given a feature request or existing screen to work on, produce output in this order:
- Role — which user role does this serve (resident, provider, admin)?
- User need — what problem is being solved?
- Screen/flow breakdown — states (empty, loading, error, success)
- Data model — fields needed, request/response shape
- Backend logic — Go API endpoint(s), auth, DB interaction
- Android implementation — Jetpack Compose component structure, Material 3 usage
Example prompt handling:
"Design the service request screen" → Output: user role (resident), screen states, request fields (service type, description, location, urgency, photos), Go REST endpoint (
POST /requests), Compose screen with form validation, and provider-side "new request" notification logic.
Progress:
- Step 1: Identify user role(s) affected (resident / provider / admin)
- Step 2: List key needs for that role in this feature
- Step 3: Break feature into screens and states (default, empty, loading, error, success)
- Step 4: Define UI actions and resulting data changes
- Step 5: Specify data model (fields, types, relationships)
- Step 6: Specify Go backend logic (endpoint, auth requirement, DB tables touched)
- Step 7: Specify Android/Compose implementation notes (components, navigation, state handling)
- Step 8: Note multilingual/voice search or Stripe payment touchpoints if relevant
- Step 9: Validate against Material Design standards (spacing, hierarchy, accessibility)
Core Roles & Needs (default reference)
| Role | Core Needs |
|---|---|
| Foreign Resident | Search services (text/voice, multilingual), view provider profiles, submit requests, chat, track status, pay securely |
| Service Provider | Receive/manage requests, client list, chat, update service status, receive payments |
| Administrator | Verify providers, moderate content, monitor disputes, view platform metrics |
Standard Screen States (apply to every feature)
- Empty state (no data yet — show guidance, not a blank screen)
- Loading state (skeleton loaders preferred over spinners for lists)
- Error state (retry action, human-readable message)
- Success/content state
- Offline state (cached data + banner, since users may have unstable connectivity)
Example 1 — New feature request Input: "Add a feature for residents to book a recurring cleaning service." Output:
- Role: Foreign Resident
- Need: Schedule repeat service without resubmitting requests
- Screens: Service detail → Recurrence picker (weekly/biweekly/monthly) → Confirm & pay → Booking list
- Data model:
Booking{id, userId, providerId, serviceType, recurrenceRule, nextDate, status, stripePaymentIntentId} - Backend:
POST /bookings(auth required), cron job to generate next occurrence,GET /bookings/upcoming - Compose:
RecurrenceSelectorcomposable usingSegmentedButton,BookingConfirmationSheetas modal bottom sheet - Payment: Stripe subscription-like off-session charge per occurrence, with retry/refund flow on failure
Example 2 — Reviewing existing UI (per the real example pattern) Input: Existing "Provider Profile" screen with photo, rating, service list, and a single "Contact" button. Process: Check Material 3 compliance, hierarchy, accessibility (touch target sizes, contrast), state coverage, navigation clarity. Output:
- Problem: No loading/error state defined; rating not accessible to screen readers; single "Contact" button ambiguous (chat vs. request)
- Fix: Split into two clear CTAs — "Chat" (secondary/outlined button) and "Request Service" (primary filled button); add
contentDescriptionfor rating stars; add skeleton loader for profile load - Layout: Use
CardwithColumn— photo (top, 16:9), name/rating row, service chips (FlowRow), sticky bottom action bar with the two CTAs - Implementation-ready note: Use
ScaffoldwithbottomBarfor persistent CTAs on scroll
Example 3 — Voice search integration Input: "Resident wants to search for 'plumber' by speaking in Spanish." Output:
- Flow: Mic icon in search bar → record audio → send to OpenAI for transcription + translation → populate search field → run search query
- Backend: Go endpoint
POST /search/voiceproxies audio to OpenAI, returns normalized query + detected language - Compose:
SearchBarwith animated mic icon state (idle/listening/processing), fallback to text if transcription fails - Edge case: Low-confidence transcription → show "Did you mean...?" confirmation instead of auto-searching
- Always design for three concurrent states per screen minimum: loading, error, success — never assume happy path only.
- Default to Jetpack Compose + Material 3 components (
Scaffold,ModalBottomSheet,SegmentedButton,FlowRow) over custom views. - Keep language simple and iconography universal — users are non-native speakers navigating unfamiliar services.
- Every payment-related flow must define: pending, succeeded, failed, and refunded states explicitly, mapped to Stripe webhook events.
- Chat and request status should use real-time updates (WebSocket or polling fallback) — don't rely on manual refresh.
- Every backend endpoint spec should note: auth requirement, role permission, and rate-limiting need (esp. voice search due to OpenAI cost).
- When revising existing UI, always separate problems from fixes from implementation notes — don't blend critique with solutions.
- Accessibility is not optional: minimum 48dp touch targets, content descriptions, sufficient contrast (WCAG AA).
- Don't design screens without empty/error states — these are the most common gaps in early UI drafts.
- Don't conflate "chat" and "service request" into one action — they are distinct user intents.
- Don't hardcode language strings — multilingual support must be baked into the data model (e.g., store
serviceTypeas key, not display string). - Don't design payment flows without accounting for failed/retried charges — this breaks provider trust.
- Don't default to spinners for list loading — use skeleton loaders for perceived performance.
- Don't skip role-based permission checks in backend specs — provider and resident data access must be strictly separated.
- Don't propose UI changes without checking current Material Design version compliance — flag deprecated components (e.g., old
BottomNavigationvsNavigationBar).