|
| 1 | +# Deployment |
| 2 | + |
| 3 | +This service is safe to deploy as a small read-only portfolio demo, but it still spends GNews quota. For public links, prefer a low rate limit plus `CLIENT_API_KEYS` for `/api/*`; leave `/health`, `/ready`, `/openapi.yaml`, and `/metrics` available for inspection. |
| 4 | + |
| 5 | +## Production environment |
| 6 | + |
| 7 | +Set these variables on the hosting platform: |
| 8 | + |
| 9 | +| Variable | Suggested value | Notes | |
| 10 | +|----------|-----------------|-------| |
| 11 | +| `GNEWS_API_KEY` | platform secret | Required outside tests. | |
| 12 | +| `NODE_ENV` | `production` | Enables production behavior. | |
| 13 | +| `PORT` | platform-provided or `3000` | The app and Docker healthcheck both read this. | |
| 14 | +| `TRUST_PROXY` | `1` | Use behind managed load balancers/proxies. | |
| 15 | +| `RATE_LIMIT_MAX` | `60` | Keep demo quota burn low. | |
| 16 | +| `RATE_LIMIT_WINDOW_MS` | `60000` | One-minute demo window. | |
| 17 | +| `CLIENT_API_KEYS` | generated secret | Recommended for a public demo; protects `/api/*`. | |
| 18 | +| `REDIS_URL` | managed Redis URL | Optional. Use it if the platform makes Redis cheap/easy. | |
| 19 | + |
| 20 | +Do not set `GNEWS_BASE_URL` in production unless you intentionally point at a compatible mock/provider. It exists for deterministic local tests, benchmarks, and CI smoke tests. |
| 21 | + |
| 22 | +## Render |
| 23 | + |
| 24 | +1. Create a Web Service from the GitHub repository and choose Docker deployment. Render supports Dockerfile-based services and passes configured environment variables to the running service. |
| 25 | +2. Set the environment variables above. Use Render secrets for `GNEWS_API_KEY` and `CLIENT_API_KEYS`. |
| 26 | +3. Set the health check path to `/ready`. |
| 27 | +4. Deploy, then smoke test: |
| 28 | + |
| 29 | +```bash |
| 30 | +BASE_URL=https://your-render-service.onrender.com QUERY=postgres CLIENT_API_KEY=your-demo-key npm run smoke |
| 31 | +``` |
| 32 | + |
| 33 | +References: [Render Docker](https://render.com/docs/docker), [Render health checks](https://render.com/docs/health-checks). |
| 34 | + |
| 35 | +## Fly.io |
| 36 | + |
| 37 | +1. Run `fly launch` from the repository and let Fly detect the Dockerfile. |
| 38 | +2. Check the generated `fly.toml`; the internal service port should match `PORT` (use `3000` unless you change it). |
| 39 | +3. Set secrets: |
| 40 | + |
| 41 | +```bash |
| 42 | +fly secrets set GNEWS_API_KEY=... CLIENT_API_KEYS=... |
| 43 | +``` |
| 44 | + |
| 45 | +4. Deploy: |
| 46 | + |
| 47 | +```bash |
| 48 | +fly deploy |
| 49 | +``` |
| 50 | + |
| 51 | +References: [Fly Dockerfile deploys](https://fly.io/docs/languages-and-frameworks/dockerfile/), [Fly app configuration](https://fly.io/docs/reference/configuration/), [fly deploy](https://fly.io/docs/flyctl/deploy/). |
| 52 | + |
| 53 | +## Railway |
| 54 | + |
| 55 | +1. Create a service from the GitHub repository. Railway can build from a Dockerfile. |
| 56 | +2. Add the production variables in the Railway Variables UI. If Railway does not inject a `PORT` for the service, set `PORT=3000`. |
| 57 | +3. Deploy, open the generated domain, and smoke test: |
| 58 | + |
| 59 | +```bash |
| 60 | +BASE_URL=https://your-railway-domain.up.railway.app QUERY=postgres CLIENT_API_KEY=your-demo-key npm run smoke |
| 61 | +``` |
| 62 | + |
| 63 | +References: [Railway Dockerfiles](https://docs.railway.com/builds/dockerfiles), [Railway variables](https://docs.railway.com/variables). |
| 64 | + |
| 65 | +## Demo posture |
| 66 | + |
| 67 | +For a recruiter-facing public demo, the best default is: |
| 68 | + |
| 69 | +- Public: `/health`, `/ready`, `/openapi.yaml`, `/metrics`. |
| 70 | +- Protected with `CLIENT_API_KEYS`: `/api/articles`, `/api/articles/title/:title`, `/api/articles/source`. |
| 71 | +- Rate limited: `RATE_LIMIT_MAX=60` or lower until you know traffic is tiny. |
| 72 | +- Logs: `LOG_LEVEL=info`, with no API keys in logs or URLs. |
| 73 | + |
| 74 | +That gives people something real to inspect without turning your GNews quota into a public vending machine. |
0 commit comments