# Deployment

Развёртывание 1C MCP Gateway: local dev, Docker, systemd, Kubernetes.

## Prerequisites

- Node.js 22+ (build) или готовый Docker image.
- Persistent volume для `ONEC_MCP_DATA_DIR`.
- TLS reverse proxy для production HTTP (nginx, traefik).
- Секреты: MCP tokens, 1C credentials — env/vault, not in image.

## Пошаговая настройка

### 1. Local development

```bash
cd /var/www/mwi.yatsuk.pro
npm ci
npm run typecheck && npm run build

# stdio MCP (Cursor)
npm run dev:gateway

# HTTP + Web Console
ONEC_MCP_HTTP_TOKEN="dev-only" npm run dev:http
# → http://127.0.0.1:3000
```

### 2. Production build

```bash
npm ci
npm run build
npm prune --omit=dev   # optional after build
# Entrypoints:
#   node dist/apps/gateway/src/server.js  — stdio
#   node dist/apps/gateway/src/http.js    — HTTP (prod default)
```

### 2b. mwi.yatsuk.pro (automated)

```bash
sudo bash deploy/prod/bootstrap-secrets.sh   # once: /etc/onec-mcp-gateway/env + secrets.txt
sudo bash deploy/prod/deploy.sh            # build, test, systemd, nginx, logrotate, backup timer
```

Secrets: `/etc/onec-mcp-gateway/secrets.txt` (store offline). Web Console → API key from that file.
MCP HTTP: `Authorization: Bearer <ONEC_MCP_HTTP_TOKEN>`, endpoint `https://mwi.yatsuk.pro/mcp`.

Daily backup: `onec-mcp-gateway-backup.timer` → `POST /api/system/backups`.

Env template: `deploy/prod/env.example`. Nginx: `deploy/nginx/mwi.yatsuk.pro.conf` + `deploy/nginx/conf.d/rate-limit.conf`.

### 3. Docker Compose

`docker-compose.yml` в корне repo:

```bash
docker compose up -d --build
docker compose ps
curl -s http://127.0.0.1:3000/healthz
```

Env defaults:

```yaml
ONEC_MCP_DATA_DIR: /data
ONEC_MCP_HTTP_HOST: 0.0.0.0
ONEC_MCP_HTTP_PORT: "3000"
ONEC_MCP_ACTOR: web-console
ONEC_OTEL_ENABLED: "1"
```

Volume `gateway-data` → `/data`. **Set** `ONEC_MCP_HTTP_TOKEN` via secrets manager, not compose file in prod.

### 4. systemd

Unit: `deploy/systemd/onec-mcp-gateway.service`

```bash
sudo useradd -r -s /usr/sbin/nologin onec-mcp || true
sudo mkdir -p /opt/onec-mcp-gateway /var/lib/onec-mcp-gateway
sudo cp -r dist package.json node_modules /opt/onec-mcp-gateway/
sudo cp deploy/systemd/onec-mcp-gateway.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now onec-mcp-gateway
```

Service env:

```
ONEC_MCP_DATA_DIR=/var/lib/onec-mcp-gateway
ONEC_MCP_HTTP_HOST=127.0.0.1
ONEC_MCP_HTTP_PORT=3000
```

Bind localhost — expose via nginx TLS only.

### 5. Kubernetes

Manifest: `deploy/k8s/deployment.yaml`

- Image: build from `Dockerfile`
- PVC 5Gi for `/data`
- Probes: `/healthz`, `/readyz`
- Service ClusterIP → Ingress

```bash
kubectl apply -f deploy/k8s/
kubectl rollout status deployment/onec-mcp-gateway
```

### 6. Post-deploy

1. Create backup: `POST /api/system/backups`
2. Issue MCP tokens: Web Console or `POST /api/mcp-tokens`
3. Configure profiles (OData/EDT)
4. Verify [CI_READONLY_ENDPOINT.md](./CI_READONLY_ENDPOINT.md) if CI used

## Copy-ready production env

See `deploy/prod/env.example`. After `bootstrap-secrets.sh`:

```bash
# /etc/onec-mcp-gateway/env
ONEC_PRODUCTION=1
ONEC_PUBLIC_BASE_URL=https://mwi.yatsuk.pro
ONEC_MCP_DATA_DIR=/var/www/mwi.yatsuk.pro/.data
ONEC_MCP_HTTP_HOST=127.0.0.1
ONEC_MCP_HTTP_PORT=3000
ONEC_MCP_ACTOR=web-console
ONEC_AUTH_COOKIE_SECURE=1
ONEC_OTEL_ENABLED=1
ONEC_CONSOLE_API_KEY=<generated>
ONEC_MCP_HTTP_TOKEN=<generated>
# Optional OIDC — see env.example
```

nginx snippet:

```nginx
location /mcp {
  proxy_pass http://127.0.0.1:3000;
  proxy_http_version 1.1;
  proxy_set_header Authorization $http_authorization;
  proxy_set_header X-MCP-Client-ID $http_x_mcp_client_id;
}
```

## Проверка tools/list

From allowed client after deploy:

```bash
curl -s -X POST https://gateway.example.com/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-MCP-Client-ID: cursor" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | jq '.result.tools | length'
```

Expect non-zero count; production token → no write tools.

## Первый тестовый prompt

```
Подключись к новому deployed endpoint. list_profiles, check_profile_health,
подтверди версию storage schema через resource или API /api/system/storage-meta.
```

## Типовые ошибки

| Issue | Fix |
|-------|-----|
| Container restart loop | Check `/data` mount writable |
| healthz OK but /mcp 404 | Path routing, trailing slash |
| Empty `.data` after redeploy | PVC not attached |
| Playwright missing in slim image | Use project Dockerfile (includes deps) |
| Wrong Node version | Node 22 in CI/CD image |

## Security warning

- Do not expose `:3000` publicly without TLS + auth.
- `ONEC_MCP_HTTP_HOST=0.0.0.0` in Docker — pair with network policy.
- Separate volumes for prod vs staging `ONEC_MCP_DATA_DIR`.
- Run `npm audit`; pin base image digest.
- Backup before every upgrade ([PRODUCTION_STORAGE.md](./PRODUCTION_STORAGE.md)).

## Related docs

- [PRODUCTION_STORAGE.md](./PRODUCTION_STORAGE.md) — data dir, migrations
- [RUNBOOK.md](./RUNBOOK.md) — incidents
- [MCP_CONNECTION.md](./MCP_CONNECTION.md) — HTTP tokens
- [SECURITY_MODEL.md](./SECURITY_MODEL.md) — hardening
