Three root causes addressed:
1. nginx routing gap — bare GET /api (no trailing slash) fell through
`location /api/` to the Vite dev proxy, which forwarded it to the
backend as an unmatched path. Added `location = /api` exact-match
block before the prefix block to catch it and proxy directly to
the backend health handler.
2. AppController root handler — added @Get() (maps to GET /api with
global prefix) so bare /api requests return a clean 200 instead of
a 404 that registers as a phantom NR transaction.
3. New Relic transaction naming — NestJS's setGlobalPrefix('api')
causes NR's Express instrumentation to bucket ALL requests into the
generic "Expressjs/GET/api$" segment, making per-endpoint APM data
completely useless. The new NewRelicTransactionInterceptor calls
newrelic.setTransactionName() with "METHOD /route/pattern" for
every request (after routing, so req.route is populated with the
matched template). Gracefully no-ops in dev where NR is not loaded.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
57 lines
2.0 KiB
Plaintext
57 lines
2.0 KiB
Plaintext
upstream backend {
|
|
server backend:3000;
|
|
}
|
|
|
|
upstream frontend {
|
|
server frontend:5173;
|
|
}
|
|
|
|
server {
|
|
listen 80;
|
|
server_name localhost;
|
|
|
|
# Exact match for bare /api (no trailing slash).
|
|
# nginx's `location /api/` below requires a trailing slash, so a request for
|
|
# GET /api would fall through to the Vite proxy, which then forwards it to
|
|
# the backend — arriving as an unmatched path that New Relic registers as
|
|
# the phantom "Expressjs/GET/api$" transaction bucket.
|
|
# This exact-match block catches it first and proxies it directly to the
|
|
# backend, where AppController's @Get() handler returns a clean 200.
|
|
location = /api {
|
|
proxy_pass http://backend;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
}
|
|
|
|
# API requests -> NestJS backend
|
|
location /api/ {
|
|
proxy_pass http://backend;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection 'upgrade';
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_cache_bypass $http_upgrade;
|
|
}
|
|
|
|
# AI endpoints now return immediately (async processing in background)
|
|
# No special timeout needed — kept for documentation purposes
|
|
|
|
# Everything else -> Vite dev server (frontend)
|
|
location / {
|
|
proxy_pass http://frontend;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection 'upgrade';
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_cache_bypass $http_upgrade;
|
|
}
|
|
}
|