This project is a Go backend API for web and mobile clients in a handyman marketplace model.
- REST API with versioning (
/api/v1) - Persona-based auth:
userandhandyman - Handyman registration includes
categoryandwork_notes - Admin approval required for handyman login
- Location-aware matching using latitude/longitude
- Fixed booking radius (
BOOKING_RADIUS_MILES, default25) - Nearby handyman filtering by category (
/handymen/nearby?category=...) - Booking creation only if handyman is in allowed radius
- Booking lifecycle with transitions:
- Handyman:
requested -> acceptedorrequested -> rejected - User:
accepted -> completed
- Handyman:
- PostgreSQL persistence
- CORS support for mobile/web apps
- Swagger UI at
/swagger
go mod tidy
go run ./cmd/serverSet PostgreSQL connection before running:
export DATABASE_URL="postgres://postgres:<YOUR_DB_PASSWORD>@db.eurheehmvgvywbhzgaei.supabase.co:5432/postgres?sslmode=require"If your password has special characters (like @), URL-encode it.
Server runs on http://localhost:8080 by default.
Swagger UI runs at http://localhost:8080/swagger.
Build and run locally:
docker build -t handyman-api:latest .
docker run --rm -p 8080:8080 --env-file .env handyman-api:latestFiles are under k8s/.
Before deploy:
- Update image in
k8s/app-deployment.yaml:your-dockerhub-user/handyman-api:latest
- Update sensitive values in
k8s/secret.yaml.
Deploy:
kubectl apply -k k8sCheck status:
kubectl get pods -n handyman-app
kubectl get svc -n handyman-app
kubectl get ingress -n handyman-app- Register as user (auto-approved + token returned)
curl -X POST http://localhost:8080/api/v1/auth/register/user \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"secret123","base_location":"Phoenix, AZ","latitude":33.4484,"longitude":-112.0740}'- Register as handyman (pending approval)
curl -X POST http://localhost:8080/api/v1/auth/register/handyman \
-H "Content-Type: application/json" \
-d '{"email":"pro@example.com","password":"secret123","base_location":"Tempe, AZ","latitude":33.4255,"longitude":-111.9400,"category":"Plumbing","work_notes":"8 years residential plumbing, leak repairs, water heater installations."}'- Admin reviews pending handymen
curl -X GET http://localhost:8080/api/v1/admin/handymen/pending \
-H "X-Admin-Secret: change-me-admin"- Admin approves a handyman
curl -X PATCH http://localhost:8080/api/v1/admin/handymen/<handyman_user_id>/approve \
-H "X-Admin-Secret: change-me-admin"- User lists nearby approved handymen (within fixed radius)
curl -X GET http://localhost:8080/api/v1/handymen/nearby \
-H "Authorization: Bearer <user_token>"Optional category filter:
curl -X GET "http://localhost:8080/api/v1/handymen/nearby?category=Plumbing" \
-H "Authorization: Bearer <user_token>"- User creates booking
curl -X POST http://localhost:8080/api/v1/bookings \
-H "Authorization: Bearer <user_token>" \
-H "Content-Type: application/json" \
-d '{"handyman_id":"<approved_handyman_id>"}'- User or handyman lists their bookings
curl -X GET http://localhost:8080/api/v1/bookings \
-H "Authorization: Bearer <token>"- Handyman accepts or rejects a booking
curl -X PATCH http://localhost:8080/api/v1/bookings/<booking_id>/status \
-H "Authorization: Bearer <handyman_token>" \
-H "Content-Type: application/json" \
-d '{"status":"accepted"}'- User marks an accepted booking as completed
curl -X PATCH http://localhost:8080/api/v1/bookings/<booking_id>/status \
-H "Authorization: Bearer <user_token>" \
-H "Content-Type: application/json" \
-d '{"status":"completed"}'