Marketplace · Case study
Seek My Service: A two-sided services marketplace with a credit-based vendor economy
Service marketplace case study: NestJS API with 80+ endpoints, React admin, Next.js public site, Stripe vendor credits and SMS, email and in-app alerts.

- Client
- Seek My Service connects people who need local services with verified vendors who bid on their requests.
- Team
- 3 full-stack engineers, 1 QA engineer, 1 designer
- Timeline
- Ongoing since December 2023
- Services
- Web development, Enterprise software, UI/UX design
- 80+
- RESTful API endpoints
- 28
- Admin dashboard routes
- 15+
- Database entities
- 5
- User roles with granular permissions
In short
Seek My Service asked for a two-sided marketplace where clients post service requests by category, zip code, budget and dates, and verified vendors are notified and submit proposals. We built the whole platform: a NestJS API with more than 80 endpoints and role-based access, a 28-route React admin dashboard, and a Next.js public site with real-time vendor availability. Vendors buy credits through Stripe to bid. The engagement has run since December 2023.
Where they started.
- Match service requests to the right vendors by geography and category, in real time, before the client finishes the form
- Give vendors a fair, monetised way to compete for work without spamming clients
- Run five distinct roles, from client to super admin, with granular permissions and an audit trail
- Notify vendors through the channel they prefer: SMS, email or in-app
- Keep three separately deployed applications consistent on one data model
The approach.
- Built a decoupled three-tier system: a NestJS 10 and TypeORM API on MySQL, a React 18 admin dashboard and a Next.js 14 public website
- Implemented a request engine with debounced availability lookups that cross-reference vendor subscription areas and categories against the client's zip code
- Designed a credit economy where vendors subscribe to service areas priced by population data, buy credits through Stripe, and spend daily credits to submit proposals
- Enforced role-based access control across Admin, Client, Vendor, Sub-Admin and Logistic Sub-Admin with route-level permission guards
- Added multi-channel notifications through Twilio SMS, SendGrid email and in-app messages, honouring each vendor's preference
- Delivered an analytics dashboard with KPI cards, proposal trend charts, payment history, CSV export and a discount-code engine
What shipped.
- Production API with 80+ RESTful endpoints, JWT authentication, RBAC, validation and migrations with seeders
- 28-route admin dashboard with real-time analytics and full entity management
- SEO-friendly Next.js public website with hybrid server and client rendering
- Credit monetisation with Stripe payments, fixed and percentage discount codes and daily allocations
- Email and phone verification, password recovery and activity logging
- Multi-channel notification system with vendor preference management
- Swagger API documentation and Jest test coverage
How the engagement ran.
Context
Seek My Service is a marketplace for local services such as plumbing, electrical work and handyman jobs. A client describes what they need, where and when, with a budget. Verified vendors who cover that area and category are told about it and can propose. The platform has to be fair to vendors, fast for clients and fully manageable by the operator, all from a standing start.
We built the product end to end as a three-tier system and have continued to develop it in iterative sprints since December 2023.
The platform has three surfaces with three audiences. Clients use the public website to describe a job and see, before they submit, how many vendors cover their area. Vendors work in the admin portal to manage subscriptions, buy credits and respond to requests. The operator uses the same portal, with elevated permissions, to run categories, areas, pricing, payments and support. Keeping all three on one API and one data model is what makes the marketplace consistent as it grows.
What we built
- A service request engine with a multi-field form, debounced real-time vendor availability and confirmation before submission
- Location-based vendor discovery keyed on zip codes and service categories
- A proposal lifecycle covering submission, acceptance, withdrawal and status changes with notifications to all parties
- A vendor subscription and credit system with daily allocations, Stripe purchases and discount codes
- An admin control plane with analytics, user management, area and category configuration, payments and audit logs
- Multi-channel notifications through Twilio, SendGrid and in-app messaging
- Email and phone verification with six-digit codes, password recovery and activity logging
Architecture and stack
| Layer | Technology | Why |
|---|---|---|
| API | NestJS 10 modular monolith, TypeORM, MySQL 8 | Feature modules with dependency injection can be extracted into services later; the repository pattern keeps business logic clean |
| Security | Passport.js JWT, custom permission guards and decorators, bcrypt | Five roles with permission keys such as MANAGE_USERS and MANAGE_PAYMENTS enforced per route |
| Admin dashboard | React 18, React Router 6, Redux Toolkit with redux-persist, TanStack Query, Ant Design | Sixteen Redux slices for client state; five-minute stale-time caching for server state |
| Public website | Next.js 14 App Router, Tailwind CSS, Formik | Server-rendered content for search engines with client-side hydration for forms and modals |
| Payments | Stripe SDK on the API and Stripe React SDK in the dashboard | Multi-step credit purchase with billing details, discount codes and confirmation |
| Messaging | Twilio SMS, SendGrid email, Nodemailer fallback | Verification codes and vendor alerts on the channel each vendor chooses |
| Operations | NestJS Schedule and cron, Swagger, Jest, ESLint, Prettier | Scheduled jobs, documented endpoints and tested code |
How we worked
The data model was designed around the marketplace's economics. Users, client requests, proposals, vendor subscriptions, areas, zip codes, transactions, discount codes, notifications, roles and permissions are separate entities with explicit relationships, including many-to-many mappings for role permissions and area zip codes. That gave the admin team levers to tune pricing and access without code changes.
Delivery ran in agile sprints. The API shipped first with migrations and seeders for repeatable environments, the admin dashboard followed so the operator could configure categories and areas, and the public site launched on top of a working marketplace.
Two details show the level of care. Vendor availability on the public form is checked with a 500-millisecond debounce so the client sees a live count without flooding the API, and every administrative action is written to an activity log with the endpoint, user and payload, which gives the operator an audit trail and a way to answer disputes. Both were built in the first sprints rather than added later.
Scale and complexity
| Measure | Figure from the documentation |
|---|---|
| API endpoints | 80+ across 15 controller modules |
| Database entities | 15+ with many-to-many role and area mappings |
| Admin dashboard routes | 28 |
| Redux slices | 16 |
| Roles | 5: Admin, Client, Vendor, Sub-Admin, Logistic Sub-Admin |
| Permission keys | 10+ |
| Notification channels | 3: SMS, email, in-app |
What this means for your project
Marketplaces fail on liquidity and trust: clients need vendors to respond, and vendors need a fair price for attention. The credit model, geographic matching and preference-based notifications here are reusable answers to those problems, and the admin control plane is what lets an operator run the business day to day.
If you are planning a two-sided platform, this is the shape we would propose: an API with strict roles, an operator dashboard from day one, and a public site built for search engines. Innovation Insight can start from this blueprint rather than from zero.
What changed.
- The platform runs in production with an engagement that has continued since December 2023
- Vendors and clients transact through a complete request, proposal and acceptance lifecycle with notifications to every party
- Administrators manage users, areas, categories, payments and discount codes from one control plane with an audit trail
- The client reports that the work elevated their platform and allowed them to offer an exceptional user experience
Questions about this project.
How does a marketplace decide which vendors see a request?
Vendors subscribe to service categories and geographic areas made up of zip codes. When a client enters a zip code and category, the API cross-references both against active vendor subscriptions and shows availability immediately. Matching vendors are then notified by SMS, email or in-app message.
How is the platform monetised?
Vendors buy credits through Stripe and spend them from a daily allocation each time they submit a proposal. Area credit values are set from population data, and admins can adjust credits, apply discount codes or pause subscriptions from the dashboard.
Can the admin dashboard and public site share one login?
Yes. The public site delegates authentication to the admin portal, which returns the token and user data after sign-in. Both applications then call the same API with the same JWT.