Skip to main content
Glama
README.md
# GoHireHumans

The trusted marketplace where businesses, AI agents, and individuals hire verified human professionals on demand.

## For AI agents (MCP server)

GoHireHumans ships a Model Context Protocol (MCP) server so AI agents can find human help for small, scoped tasks that AI and software can't reliably finish alone. It is a Python stdio server with no third-party dependencies.

**Install and run** (uv, Python 3.9+):

```bash
uvx --from 'git+https://github.com/profilesearch/GohireHumans#subdirectory=backend/mcp-package' gohirehumans-mcp
```

**MCP client config** (Claude Desktop, Cursor and other stdio clients):

```json
{
  "mcpServers": {
    "gohirehumans": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/profilesearch/GohireHumans#subdirectory=backend/mcp-package", "gohirehumans-mcp"]
    }
  }
}
```

**Browse and search, no key needed:**
- `search_services`, `get_service_details`: find services by task, category and price
- `search_workers`, `get_recommended`: compare providers by skill, rating and price, or rank listings for a task description
- `browse_jobs`, `get_categories`: see open jobs and service categories
- `get_pricing_info`, `get_platform_info`: fees and how the platform works

**Account actions, need `GOHIREHUMANS_API_KEY` or `GOHIREHUMANS_AUTH_TOKEN`:**
- `create_job`: post a job
- `hire_worker`: hire a worker for a task
- `get_job_status`: track an order
- `release_payment`: approve completed work so the worker's listed payout is released
- `submit_review`: rate a completed order

Hiring and payment actions require the account owner's authorization. Workers receive the listed payout; employers pay a 1% platform fee plus a fixed 3% processing charge where checkout is configured. GoHireHumans is not an escrow provider.

Package docs and authentication steps: [`backend/mcp-package/README.md`](backend/mcp-package/README.md). API docs: https://www.gohirehumans.com/api-docs.html. The MCP server is MIT-licensed ([`backend/mcp-package/LICENSE`](backend/mcp-package/LICENSE)); the rest of this repository is proprietary (see [`LICENSE`](LICENSE)).

---

## Deployment guide

How the GoHireHumans site and API are built and deployed.

## Architecture

```
┌─────────────────────────┐          ┌──────────────────────────┐
│    Vercel (Frontend)     │  ─────▶  │  Railway (Backend API)    │
│                         │   API    │                          │
│  index.html             │  calls   │  Flask + Gunicorn        │
│  style.css              │          │  SQLite database         │
│  base.css               │          │  Python 3.12             │
│  config.js              │          │                          │
└─────────────────────────┘          └──────────────────────────┘
```

- **Frontend**: Static SPA (HTML/CSS/JS) hosted on Vercel
- **Backend**: Python Flask API hosted on Railway (Docker)
- **Database**: SQLite (file-based, included in container volume)

---

## Quick Start (Local Development)

### 1. Start the Backend

```bash
cd backend
pip install -r requirements.txt
python server.py
```

The API will be running at `http://localhost:8080`. Test it:

```bash
curl http://localhost:8080/health
# → {"status": "ok", "service": "gohirehumans-api"}
```

### 2. Seed Demo Data

Seeding is disabled unless `SEED_SECRET` is configured. Use it only for local/demo setup and unset it in production after controlled setup.

```bash
curl -X POST http://localhost:8080/seed \
  -H 'Content-Type: application/json' \
  -d '{"secret":"YOUR_SEED_SECRET"}'
```

This creates local/demo marketplace records. Do not publish or rely on demo credentials for production.

### 3. Serve the Frontend

```bash
cd frontend
# Any static file server works:
python -m http.server 3000
```

Open `http://localhost:3000` in your browser.

---

## Deploy to Railway (Backend)

### Step 1: Create a Railway Project

1. Go to [railway.app](https://railway.app) and sign in
2. Click **"New Project"** → **"Deploy from GitHub Repo"**
3. Connect your GitHub account and select your repo (or use "Deploy from Local" with the Railway CLI)

### Step 2: Configure the Service

1. In your Railway project, click on the service
2. Go to **Settings** → **Build & Deploy**
3. Set **Root Directory** to `backend`
4. Railway will auto-detect the Dockerfile

### Step 3: Add Environment Variables

In the Railway dashboard, go to **Variables** and add:

| Variable | Value |
|----------|-------|
| `PORT` | `8080` (Railway usually sets this automatically) |
| `FLASK_DEBUG` | `false` |
| `DATABASE_PATH` | Optional local override. Production prefers `/data/gohirehumans.db`. |

### Step 4: Add a Persistent Volume (Important!)

SQLite needs persistent storage:

1. In Railway, click **"+ New"** → **"Volume"**
2. Mount path: `/data`
3. Do not point production SQLite under `/app`; `/app` is ephemeral.

### Step 5: Deploy

Railway deploys automatically on push. Your backend URL will look like:
```
https://gohirehumans-api-production-xxxx.up.railway.app
```

### Step 6: Optional Controlled Seed

Only seed a controlled staging/demo environment. Production auto-seeding is disabled by default.

```bash
curl -X POST https://YOUR-RAILWAY-URL/seed \
  -H 'Content-Type: application/json' \
  -d '{"secret":"YOUR_SEED_SECRET"}'
```

---

## Deploy to Vercel (Frontend)

### Step 1: Update API URL

Edit `frontend/config.js` and set your Railway backend URL:

```javascript
window.GOHIREHUMANS_API_URL = "https://your-railway-backend-url.up.railway.app";
```

### Step 2: Deploy to Vercel

**Option A: Vercel CLI**

```bash
cd frontend
npx vercel --prod
```

**Option B: GitHub Integration**

1. Go to [vercel.com](https://vercel.com) and sign in
2. Click **"Add New Project"** → import your repo
3. Set **Root Directory** to `frontend`
4. Framework Preset: **Other**
5. Click **Deploy**

### Step 3: Custom Domain

1. In Vercel dashboard → **Settings** → **Domains**
2. Add `gohirehumans.com`
3. Follow the DNS configuration instructions

---

## Deploy with Railway CLI (Alternative)

```bash
# Install Railway CLI
npm install -g @railway/cli

# Login
railway login

# Initialize project
cd backend
railway init

# Deploy
railway up

# Get your URL
railway domain
```

---

## Project Structure

```
GohireHumans/
├── backend/
│   ├── server.py          # Flask server (production wrapper)
│   ├── api_core.py        # Core API logic (~14,000 lines, single route dispatcher)
│   ├── mcp_server.py      # MCP server for AI agents (mirrored in mcp-package/)
│   ├── test_*.py          # unittest suites (run with discover -s backend)
│   ├── requirements.txt   # Python dependencies
│   ├── Dockerfile         # Container config for Railway
│   ├── railway.toml       # Railway deployment config
│   ├── Procfile           # Process file (Heroku/Railway)
│   ├── start.sh           # Container entrypoint (execs gunicorn)
│   ├── .dockerignore      # Keeps tests/tools/local DBs out of the image
│   └── .env.example       # Environment variable template
│
├── frontend/
│   ├── index.html         # Single Page Application (hash routes under /#/)
│   ├── style.css          # Shared stylesheet: tokens, reset, components, public shell, page layouts
│   ├── app.css            # Signed-in app surfaces (loaded by index.html only)
│   ├── base.css           # Reset mirror for the SPA
│   ├── mobile-hardening.css # Phone-width guards (no-op above 768px)
│   ├── partials/          # Canonical public nav and footer (synced into every static page)
│   ├── *.html, blog/, hire/, use-cases/, ai-human-qa/, categories/, vs/, tools/, earn/, examples/
│   │                      # Static marketing, SEO, docs, and tool pages
│   ├── analytics-bootstrap.js # Fail-closed GA loader (production origins only)
│   ├── config.js          # API URL configuration ← EDIT THIS
│   ├── sitemap.xml, feed.xml, atom.xml, robots.txt, llms.txt, .well-known/
│   ├── performance-budgets.json # Byte budgets enforced in CI
│   ├── tests/             # Playwright browser regression suites
│   └── vercel.json        # Vercel redirects and security headers
│
├── docs/
│   ├── design-system/     # design-system.md (tokens, components, page patterns) and public-shell.md
│   ├── ops/               # Operating playbooks and internal working docs (not deployed)
│   └── plans/             # Historical sprint plans
│
├── scripts/
│   ├── sync_public_shell.py   # Sync the nav/footer partials into every static page (--check in CI)
│   ├── check_public_shell.py  # Guard: every public page has the canonical shell, skip link, main, bootstrap
│   ├── performance_budget.py  # Enforce performance-budgets.json
│   ├── generate_feeds.py      # Rebuild feed.xml and atom.xml from blog page metadata
│   └── generate-marketplace-pulse.py
│
├── .github/workflows/ci.yml # Backend tests, static checks, Playwright suites
├── .gitignore
└── README.md              # This file
```

---

## API Endpoints

| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/health` | Health check |
| `POST` | `/auth/register` | Register new user |
| `POST` | `/auth/login` | Login |
| `GET` | `/profile` | Get current user profile |
| `GET` | `/services` | List service listings |
| `POST` | `/services` | Create a service listing |
| `GET` | `/jobs` | List jobs |
| `GET` | `/me/services` | The caller's own services in every status (auth required; `page`, `per_page`, `status`, `include_removed`) |
| `GET` | `/me/jobs` | The caller's own jobs in every status, with `application_count` (auth required) |
| `POST` | `/jobs` | Create a job |
| `POST` | `/jobs/{id}/apply` | Apply to a job; payout-ready account and non-empty `cover_message` required, optional http(s) `portfolio_url`; incomplete payout setup returns 403 `payout_setup_required` |
| `GET` | `/jobs/{id}/applications` | Job-owner/admin-only JSON list; session or read-scoped API key. Each application includes `worker_payout_ready` (boolean synced hint), `suggested_rank` (1–3 or null), and `suggestion_reasons` (up to three fixed-copy strings, empty when not suggested). Only eligible, payout-ready pending/shortlisted applicants on open/reviewing fixed-price jobs with hiring enabled are suggested; no padding, no numeric score. Hiring still re-checks Stripe live; the buyer chooses. |
| `DELETE` | `/jobs/{id}/apply` | Withdraw your own pending application before a hire; one reapply allowed per job |
| `POST` | `/jobs/{id}/hire` | Hire an applicant |
| `GET` | `/services/{id}/quote` | Preview an authenticated, itemized service charge without creating an order |
| `POST` | `/services/{id}/order` | Order a listed service; optionally bind the request to a quote |
| `POST` | `/orders/{id}/approve` | Approve submitted work and release payment |
| `POST` | `/orders/{id}/review` | Leave a review |
| `POST` | `/seed` | Secret-gated local/demo seeding |
| `GET` | `/admin/dashboard` | Admin statistics |

---

## Content Safety

GoHireHumans includes built-in content safety filters that block:
- 80+ prohibited keywords and phrases
- Inappropriate service categories
- Dark web / illegal content patterns

All task titles and descriptions are automatically screened.

---

## Troubleshooting

### CORS Errors
The backend uses the `ALLOWED_ORIGINS` env var and does not allow wildcard credentials by default. If you see CORS errors:
1. Make sure the backend is running and accessible
2. Check that `config.js` has the correct backend URL
3. Ensure there's no trailing slash on the URL

### Database Reset
To start fresh locally, delete your local SQLite file and optionally run secret-gated `/seed` again. Do not delete production `/data/gohirehumans.db` without a verified backup and restore plan.

### Railway Volume Issues
If data disappears between deploys, make sure you've attached a persistent volume at `/data`. The app stores production SQLite at `/data/gohirehumans.db`.

---

## Frontend checks

The static checks CI runs, in order:

```bash
python3 scripts/check_public_shell.py
python3 scripts/sync_public_shell.py --check
python3 scripts/performance_budget.py
python3 backend/security_static_checks.py
python3 -m unittest discover -s backend -p 'test_deep_audit_regressions.py'
```

Browser suites (Playwright, desktop and Pixel 5 projects):

```bash
cd frontend && npm ci && npx playwright install chromium && npm run test:browser
```

Set `PW_PORT=<port>` if 4173 is taken on your machine; the config and specs honor it. After changing `frontend/partials/`, run `python3 scripts/sync_public_shell.py` (without `--check`) to propagate the shell, and update the JS-rendered nav and footer in `index.html` by hand. After adding a blog post, run `python3 scripts/generate_feeds.py`.

The visual system is documented in `docs/design-system/design-system.md`; static pages build on its classes instead of page-local styles.

---

## Tech Stack

- **Frontend**: Vanilla JS SPA plus static HTML pages, Newsreader and Instrument Sans (Google Fonts), CSS custom properties, one shared stylesheet
- **Backend**: Python 3.12, Flask, Gunicorn, SQLite
- **Hosting**: Vercel (frontend) + Railway (backend)
- **Security**: PBKDF2-HMAC password hashing, session tokens, rate limiting, content safety filters
- **Domain**: gohirehumans.com

TDQS

A4.4/5.0

Scored across 13 tools

Disambiguation4/5

Most tools are distinct, and the descriptions actively cross-reference each other (e.g. search_services vs search_workers vs get_recommended, get_platform_info vs get_pricing_info vs get_categories). The only real overlap is that search_services and get_recommended both return listing IDs, which could occasionally be confused, but the guidance on when to use each is clear.

Naming Consistency5/5

Every tool follows a snake_case verb_noun pattern (get_pricing_info, search_services, create_job, hire_worker, release_payment, submit_review). No mixing of conventions or vague verbs.

Tool Count5/5

13 tools is well within the ideal 3-15 range and each covers a distinct step of the search-hire-pay-review or job-posting workflow. No redundant or filler tools.

Completeness3/5

The hire/pay/review lifecycle is well covered, but the job-post side has a notable gap: create_job exists with no edit or close/delete counterpart (explicitly unsupported), leaving a dead end for managing a posted job. Order cancellation and provider messaging are also absent, though some of these are platform limitations.

Maintenance

ActivityNo data
ResponsivenessNo issues