KB-5DE7

02 — Route / Handler Mapping

3 min read Revision 1
architecturerproute-mappingnuxtnginx2026-06-06

— 02 ROUTE / HANDLER MAPPING — why the production APIs fail

Deployment topology (discovered live):

  • nginx (incomex-nginx) terminates TLS for vps.incomexsaigoncorp.vn and proxies location / , /api/registry/ , /api/registries/ , /api/registries-pivot/ to upstream nuxt:3000. Directus paths proxy to directus_backend.
  • nuxt (incomex-nuxt, image nuxt-ssr-local:s174) runs Nitro on :3000, mem_limit 512m. Env: NUXT_DIRECTUS_INTERNAL_URL=http://directus:8055, NUXT_DIRECTUS_SERVICE_TOKEN=admin token, plus RP_PG_HOST/PORT/DATABASE/USER/PASSWORD (direct Postgres).
  • KEY: the container bind-mounts /opt/incomex/deploys/nuxt-output -> /app/.output. The served Nitro bundle lives on the host filesystem, not baked in the image. Editing an existing handler file there + restart applies it without an image rebuild. Adding a NEW route still needs a rebuild (route registration is compiled into nitro.mjs).
  • Compose: /opt/incomex/docker/docker-compose.yml (service "nuxt").

Two helper patterns coexist in handlers:

  • Directus REST via ofetch ($fetch to http://directus:8055/items/...). Used by matrix and pivot-query.
  • Postgres via rpQuery(sql) (exported from nitro.mjs as rpQuery as m; imported m as rpQuery). Used by registries-pivot/summary, registries-pivot/rows, counts, etc. These run SQL directly against the RP_PG pool.

Mapping of the 3 breaks:

route mounted handler chunk backend failure
/api/registry/pivot-query yes routes/api/registry/pivot-query.get.mjs directus-rest jsonb _neq filter -> Directus 400 -> 500
/api/registry/matrix yes routes/api/registry/matrix.get.mjs directus-rest 897K entity_labels pull -> 15s timeout -> 500
/api/registries/index NO none (string only in client chunk index-DCnbKlud.mjs = /knowledge/registries page) n/a route never mounted in s174 -> Nitro 404

Evidence that registries/index is a client/server drift: the Nitro route registration table lists /api/registries/system-issues and /api/registries/system-issues/detail (plural) but NOT /api/registries/index; the literal string /api/registries/index appears only in client.precomputed.mjs and the /knowledge/registries page chunk. So the page fetches a route the server build does not expose.

Why matrix is the outlier: every sibling RP data endpoint queries Postgres via rpQuery; matrix alone fans out 152 per-collection Directus REST calls plus the 897K-row entity_labels pull plus taxonomy and edges, all limit=-1, each $fetch capped at 15s, inside a 512 MB container. entity_labels (897,347 rows) is the killer; edges (2,199) and per-collection (managed/log = 152 collections, ~thousands of rows) are minor.

View created: v_rp_production_api_route_mapping_status (route -> handler chunk -> mounted -> backend -> live -> fix).

Back to Knowledge Hub knowledge/dev/reports/architecture/rp-production-api-operator-fix-ui-truth-smoke-2026-06-06/02-route-handler-mapping.md