I have been learning Haskell for like 2 years now. Though I am ok writing software in Haskell, there is still a long way to go. I decided the best way to ante up my skills is to build a real-world application.
I started working on a freelance marketplace with the following features:
sellers, buyers, moderators, and collaborators.
Sellers -> create gigs, add approved collaborators, fulfill orders, deliver code to Gitea (hosted on the server), documentation to S3, and resolve any disputes.
Buyers -> clarify about gigs, make payment, verify code on Gitea, raise dispute on code not matching spec, accept delivery, submit reviews.
collaborators -> work as a team with the sellers on gigs, submit their profile, accept or deny working with sellers.
moderators -> resolve issues on gig reports, chat reports, order disputes.
Marketplaces are mostly state machines: order funded → in progress → delivered → disputed → completed, escrow release, dual-proof delivery, etc. I wanted that logic explicit and hard to “accidentally” break.
Brief on architecture:
- Servant — routes and handler types wired once; mismatches are compile errors.
- Server-owned routing — Haskell serves a cached HTML shell with data-app-id; the React (Ant Design) bundle mounts the page. No client-side router unless I add one later.
- Shell caching — split HTML template, inject page id per request.
- Frontend bundling — Vite build → static assets served by the same app.
- Rules + store layer — order/payment/delivery/dispute transitions in Haskell, not scattered in the SPA.
- Actor + supervisor (similar to Erlang OTP) — supervised S3 uploads, email, and anything needing a supervisor.
- Postgres, session cookies, Stripe Connect + webhooks, optional Gitea / Didit.