A multi-role service marketplace, built end to end.
A multi-role service marketplace connecting clients with local service providers. Clients discover and book services, providers manage availability and fulfillment, and administrators operate the platform through a dedicated back office. I built the system end to end: the data model, the API, and the three product surfaces they feed.
Public site













Admin dashboard








Problem
- Service discovery and booking in local markets happen across phone calls, direct messages, and social posts, with no shared record of availability, pricing, or history.
- Different users need different things from the same product: customers want fast booking, providers need reliable scheduling, and operators need visibility and control.
- Payment, notification, and location concerns overlap the booking lifecycle, so every flow has to be designed against one authoritative order state.
Solution
I built AWNUP as a multi-role application on a single Next.js codebase over a Hono API on PostgreSQL. The client experience covers discovery, booking, payments, and notifications; the provider surface handles availability, requests, and fulfillment; and the admin surface operates categories, users, orders, and configuration. The same order state drives every surface, so a booking made on mobile is the same booking a provider confirms in their app and an operator sees in the back office.
Architecture
- Client surface: service discovery with maps and location, provider profiles, a guided booking flow, payments, web-push and in-app notifications.
- Provider surface: availability management, incoming requests, fulfillment, and earnings.
- Admin surface: service categories, users, orders, payouts, and platform configuration.
- API layer: Hono services with Zod-schema contracts, running on PostgreSQL through Prisma.
- Delivery: the client experience ships as a PWA and inside a mobile WebView, so one frontend feeds web and wrapped native.
Key engineering challenges
- The booking lifecycle is a state machine: requested, confirmed, in progress, completed, and canceled, with legal transitions enforced in the API, not just in the UI.
- One session carries three permission sets, and every API route checks role boundaries server-side.
- Payments and orders are separate but must reconcile: order state and payment state evolve independently and resolve to one consistent result.
- A single event, a new booking request or a confirmation, must reach the right user on web, push, and WebView exactly once, without duplicating delivery logic.
Technical decisions
- One Next.js application with route groups and role-gated layouts instead of three separate applications, so shared UI, types, and configuration stay in one place.
- Hono for the API layer: typed, fast, and small, with Zod schemas shared between server and client as the contract.
- PostgreSQL as the source of truth with Prisma migrations, so the schema evolves with the product instead of around it.
- PWA-first for the client experience, because service booking is a mobile, low-connectivity activity.
Outcomes
- Three product experiences, one codebase, one schema, and one order state across web, PWA, and WebView.
- Role boundaries enforced where they belong: on the server.
- Booking, payment, and notification flows that resolve through a single authoritative order lifecycle.