Inspiration
Freelance software work runs on trust, and both sides can get burned. Clients pay up front and sometimes get nothing. Freelancers deliver the work and then chase the payment. Escrow-style services exist, but "is it done?" is usually decided by opinion. We wanted a system where that question is answered by the code itself, with the client still having the final say.
What it does
MilestonePay is milestone-based payments for software projects.
- Plan: A client describes a project and a budget. An AI planner (Claude) drafts the milestones, budget split, due dates and acceptance criteria, and the client edits them.
- Fund: The client authorizes the full budget through PayPal Sandbox. The money is held, not sent.
- Deliver: The freelancer submits a GitHub repo for a milestone. The app checks it against the criteria: required files exist, CI passes, a PR is merged. Anything subjective goes to the client for review.
- Pay: Nothing is paid automatically. The client approves, and only then is the milestone captured and paid out to the freelancer's PayPal. Late work gets a pre-agreed per-day penalty.
- Discover: Clients can search freelancer profiles by skill or by resume keywords, with OCR for scanned resumes. Profiles never show money.
- Visualize: Charts show the plan, the progress and the captured payments for each project.
Everything runs on PayPal Sandbox, so no real money moves.
How we built it
- Frontend: React 19, TypeScript, Vite and Tailwind.
- Backend: Supabase (Postgres) with row-level security on every table. All state changes go through
SECURITY DEFINERfunctions, so the database enforces the rules and not just the UI. - Edge Functions (Deno): one handles PayPal Orders v2 (authorize, capture, payouts, void), one handles server-side GitHub checks, and one calls the Claude API with structured outputs for the milestone plans.
- Resume search:
pdf.jsfor text PDFs, Tesseract OCR for scanned ones, and Mammoth for Word files. The extracted text goes into a searchable column. - Fallbacks: a built-in topic-aware planner takes over if the AI is unavailable, and a local-storage backend lets the app run without Supabase.
- Testing: end-to-end browser tests and a local Postgres that mirrors the schema.
Challenges we ran into
- PayPal Sandbox quirks: merchant and buyer accounts are easy to mix up, and accounts in unsupported countries throw generic errors. Authorizations also expire after 29 days, so we limited due dates to 28 days.
- Keeping secrets safe: the PayPal secret and the API keys live only in Supabase secrets, never in the browser.
- Trusting AI output: we validate the plan in code, forcing percentages to total exactly 100%, keeping file paths safe and capping the timeline, and we treat the project brief as data, not instructions.
- Fair deadlines: we designed a late-penalty rule that is calculated, shown to both sides and capped, instead of an all-or-nothing deadline.
- Dates and charts: timezone shifts moved chart dates by a day until we switched to local-date handling.
Accomplishments that we're proud of
- A complete loop that works end to end: sign up, plan, fund, submit, verify, approve and pay.
- The money rules are enforced in the database, so a client or freelancer can't skip a step by calling the API directly.
- Charts that are accessible, with values on hover and keyboard focus, a table view and status written as text.
- Real automated checks against real GitHub repositories.
- An app that stays usable with no AI key, no Supabase, or no PayPal configured.
What we learned
- Payment flows are mostly about edge cases, such as expiry, retries, partial failures and idempotency, and the happy path is the easy part.
- Putting business rules in the database makes the whole system easier to trust and test.
- AI works best as a draft the user can edit, wrapped in validation, and not as the final decision-maker.
- A good sandbox demo needs the right test accounts as much as it needs good code.
What's next for MilestonePay
- Live payments: a production PayPal review and a switch from Sandbox to Live.
- More checks: test coverage, code-quality scans, and deployed-URL checks.
- Disputes: a mediation flow for disagreements, plus partial approvals.
- Email notifications and verification.
- More payment options such as cards and bank transfer.
- A reputation system with verified delivery history for freelancers.
Built With
- claude
- css
- github-api
- html
- paypal
- plpgsql
- postgresql
- react
- sql
- supabase
- tailwindcss
- typescript