# adpilot-gateway — Setup Guide

## Stack

- **Runtime**: Node.js 20
- **Framework**: Express 5
- **Database**: MongoDB (Mongoose)
- **Cache / Rate-limit store**: Redis
- **Auth**: JWT (internal) — Auth0-compatible for production (TW-115)
- **Process manager**: PM2 (production)

**Business Metrics MCP (TW-296):** Google SSO login-once → Lucos JWT for ChatGPT Secure MCP Tunnel — see [docs/MCP-SECURE-TUNNEL-OIDC.md](./docs/MCP-SECURE-TUNNEL-OIDC.md). Staging smoke: `scripts/verify-mcp-tunnel-auth.sh`.

**Engineering code tools (TW-306 / TW-307 / TW-308):** `POST /api/v1/tools/code_search`, `/get_file`, `/get_file_lines` adapt the existing RAG `/api/v1/search` path under engineering tool RBAC (separate from Business Metrics credentials/policies). MCP clients call these via execute-on-gateway from `business-mcp.lucos.com`. See [docs/ENGINEERING-CODE-TOOLS.md](./docs/ENGINEERING-CODE-TOOLS.md).

---

## Local Development

### 1. Prerequisites

- Node.js 20+
- MongoDB running on `localhost:27017`
- Redis running on `localhost:6379`

### 2. Install dependencies

```bash
npm install
```

### 3. Configure environment

```bash
cp .env.example .env
```

Update `.env` with your values. Minimum required:

```env
MONGODB_URI=mongodb://localhost:27017/lucos
JWT_SECRET=<any long random string>
CORS_ORIGINS=http://localhost:5173
```

### 4. Start the server

```bash
npm run dev       # nodemon (auto-reload)
npm start         # production
```

Server starts on `PORT` (default `3007`).

---

## Docker Compose

```bash
docker compose up --build
```

Gateway exposes port `8080`. Upstream services (`rag-query-service`, `repo-sync`) are commented out in `docker-compose.yml` until their images are published — uncomment when available.

---

## API Endpoints

### Gateway

| Method | Path | Auth | Description |
|--------|------|------|-------------|
| GET | `/healthz` | No | Health check |

### Auth (`/api/v1/auth`)

| Method | Path | Auth | Description |
|--------|------|------|-------------|
| POST | `/authenticate` | No | Email or Google sign-in / sign-up |
| POST | `/refresh` | No | Exchange refresh token for new JWT |
| POST | `/forgot-password` | No | Request password reset |
| POST | `/reset-password` | No | Reset password with token |
| GET | `/me` | Yes | Get current user profile |
| POST | `/logout` | Yes | Logout |
| DELETE | `/delete-account` | Yes | Delete account |

### Proxy routes (`/api/v1`) — upstream required

| Method | Path | Role | Upstream |
|--------|------|------|----------|
| POST | `/search` | authenticated | `rag-service:6005` → `POST /api/v1/search/` |
| POST | `/query` | authenticated | `rag-service:6005` → `POST /api/v1/query/` (SSE streaming) |
| GET | `/models` | authenticated | `rag-service:6005` → `GET /api/v1/models/` |
| GET | `/repos` | authenticated | `rag-service:6005` → `GET /api/v1/repos/` |
| GET | `/repos/:id/status` | authenticated | `repo-sync:6001` |
| POST | `/admin/repos/:id/sync` | owner | `repo-sync:6001` |

### Lucos indexing routes (`/api/v1`) — lucos-cloud-client required

| Method | Path | Role | Upstream |
|--------|------|------|----------|
| POST | `/indexing/chunks` | authenticated | `lucos-cloud-client:6006` → `POST /api/v1/indexing/chunks` |
| GET | `/indexing/status` | authenticated | `lucos-cloud-client:6006` → `GET /api/v1/indexing/status` |
| POST | `/retrieval/search` | authenticated | `lucos-cloud-client:6006` → `POST /api/v1/retrieval/search` |

### Billing, Payments, Chat, Appearance, Plan-usage

All protected routes — see `src/routes/` for full details.

---

## Curl Examples

```bash
# Health check
curl http://localhost:3007/healthz

# Sign up
curl -X POST http://localhost:3007/api/v1/auth/authenticate \
  -H "Content-Type: application/json" \
  -d '{"authType":"email","action":"sign-up","email":"you@example.com","password":"secret123"}'

# Query RAG (streaming) — requires upstream
curl -X POST http://localhost:3007/api/v1/query \
  -H "Authorization: Bearer <token>" \
  -H "Accept: text/event-stream" \
  -H "Content-Type: application/json" \
  -d '{"question":"What does this repo do?"}'
```

---

## Environment Variables Reference

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `PORT` | No | `3007` | Server port |
| `MONGODB_URI` | Yes | — | MongoDB connection string |
| `REDIS_URL` | No | `redis://localhost:6379` | Redis (rate limiting) |
| `JWT_SECRET` | Yes | — | JWT signing secret |
| `JWT_ACCESS_EXPIRES_IN` | No | `1h` | Lucos access JWT TTL (MCP + login) |
| `AUTH_PROVIDER` | No | `internal` | `internal` or `auth0` |
| `GOOGLE_MCP_CALLBACK_URL` | No* | — | TW-296 MCP OAuth Google callback (*required for ChatGPT MCP connect) |
| `MCP_KEY_ALLOWLIST_ENABLED` | No | `false` (all `@admedia.com`) | `true` = only `MCP_KEY_ALLOWED_EMAILS` can create/list/revoke MCP keys. `false`/unset = all `@admedia.com`. |
| `MCP_KEY_ALLOWED_EMAILS` | No | — | CSV of emails used when `MCP_KEY_ALLOWLIST_ENABLED=true`. |
| `MCP_OAUTH_CLIENT_ID` | No* | — | TW-296 ChatGPT OAuth client id(s), CSV |
| `MCP_OAUTH_ALLOWED_REDIRECT_URIS` | No* | — | TW-296 exact redirect URI allowlist, CSV |
| `MCP_OAUTH_ISSUER` | No | request host | OAuth discovery issuer URL |
| `CORS_ORIGINS` | No | — | Comma-separated allowed origins |
| `RAG_QUERY_SERVICE_URL` | No | — | RAG service base URL |
| `REPO_SYNC_URL` | No | — | Repo-sync service base URL |
| `LUCOS_CLOUD_CLIENT_URL` | No | — | Lucos cloud client base URL (TW-177) |
| `RATE_LIMIT_GENERAL_MAX` | No | `100` | Requests/min for general routes |
| `RATE_LIMIT_QUERY_MAX` | No | `20` | Requests/min for /query |
