Skip to content

Commit cc0ba4c

Browse files
committed
docs(deploy): add safe public demo guide
1 parent d752540 commit cc0ba4c

5 files changed

Lines changed: 81 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818
- In-flight coalescing for identical cache misses so concurrent same-key searches share one upstream request per process.
1919
- Redocly-powered `npm run contract` check for the OpenAPI document, wired into CI.
2020
- Docker Compose smoke test against a fake GNews provider, wired into CI.
21+
- Deployment guide for safe public demos on Render, Fly.io, and Railway.
22+
- Docker healthcheck now honors the runtime `PORT` environment variable.
2123

2224
### Security
2325

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ COPY --chown=appuser:nodejs package.json ./
2020
USER appuser
2121
EXPOSE 3000
2222
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
23-
CMD node -e "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
23+
CMD node -e "const port=process.env.PORT||3000; fetch('http://127.0.0.1:'+port+'/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
2424
CMD ["node", "dist/server.js"]

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ Full diagram and component notes live in [docs/ARCHITECTURE.md](docs/ARCHITECTUR
2727

2828
**Automation:** [CI](.github/workflows/ci.yml) (Node **20**/**22**), [CodeQL](.github/workflows/codeql.yml), [Codecov](https://codecov.io) upload, [dependency review](.github/workflows/dependency-review.yml), [SBOM](.github/workflows/supply-chain.yml), [provenance attest](.github/workflows/provenance.yml), [releases on tags](.github/workflows/release.yml), and [Dependabot](.github/dependabot.yml) (npm, Docker, Actions). Details: [docs/CI.md](docs/CI.md). Operations: [docs/OPERATIONS.md](docs/OPERATIONS.md). Security: [SECURITY.md](SECURITY.md).
2929

30+
Deployment guide: [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) covers safe public-demo settings and Render/Fly/Railway Docker paths.
31+
3032
## Requirements
3133

3234
- **Node.js** 20 or newer ([`engines`](package.json)), or Docker 24+

docs/DEPLOYMENT.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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.

docs/OPERATIONS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ To smoke-test the production container without a live GNews key, boot the CI Com
9090
npm run smoke:docker
9191
```
9292

93+
For hosted Docker deployment notes and safe public-demo defaults, see [DEPLOYMENT.md](DEPLOYMENT.md).
94+
9395
## Local Benchmark
9496

9597
For reproducible cache/upstream performance checks without a live GNews key:

0 commit comments

Comments
 (0)