Kong Route and Service Mapping Guide
This guide documents the practical process used in this repository to:
Purpose
This guide documents the practical process used in this repository to:
- add and update Kong services
- add and update Kong routes
- apply rewrites and plugins
- map legacy Ocelot paths to Kong paths
- validate behavior after changes
It reflects the current stack under:
runtime/stacks/infrastructure/gateway/kong-bootstrap-ocelot.shruntime/stacks/infrastructure/gateway/ocelot-to-kong-mapping.md
Architecture Overview
Request flow
- Client sends request to
api.perspective-v.com. - Kong matches a route by host + path + method + regex priority.
- Kong applies route/global plugins (rewrite, rate limit, auth, CORS).
- Kong forwards to an internal upstream service on Docker network (for example
graph:5138,identity:62258).
Core concepts in this repo
- Service: upstream target (
host,port,protocol, optional path). - Route: public entry (
hosts,paths,methods,regex_priority). - Rewrite plugin: maps incoming path to upstream path.
- JWT plugin: attached only to protected routes.
- Global CORS plugin: controls browser cross-origin behavior.
Source of Truth Files
Bootstrap automation
runtime/stacks/infrastructure/gateway/kong-bootstrap-ocelot.sh
This script is idempotent and performs upserts for:
- services
- routes
- route plugins (rewrite/rate-limit/jwt)
- global plugins (cors/correlation-id)
- JWT consumer credential
Human-readable mapping
runtime/stacks/infrastructure/gateway/ocelot-to-kong-mapping.md
This file describes Ocelot-to-Kong parity and compatibility routes.
How Services Are Added
Service upsert function:
upsert_service(name, protocol, host, port, path)
Current examples:
identity-svc -> identity:62258graph-svc -> graph:5138pv-web-svc -> perspective-v.com:443sms-svc -> schoolmanagement.perspective-v.com:443syassociates-svc -> service.syassociates.pk:443
Add a new service
- Choose a unique service name ending in
-svc. - Point to internal Docker host when possible.
- Add one
upsert_serviceline in the services section. - Keep tag
ocelot-migrationfor audit consistency.
How Routes Are Added
Route upsert function:
upsert_route(name, service_name, regex_priority, path_pattern, methods...)
Route matching controls:
hosts[]fixed toKONG_PROXY_HOST(defaultapi.perspective-v.com)paths[]regex-style pathmethods[]explicit methodsregex_prioritycontrols conflict resolution
Priority rules used here
- More specific public compatibility routes use higher priority.
- Catch-all protected routes use lower priority.
- This prevents accidental fallthrough to JWT-protected routes.
Rewrite Strategy Used Here
Rewrite plugin function:
upsert_rewrite_plugin(route_name, rewritten_uri)
Typical patterns:
- capture groups from regex path:
/api/v$(uri_captures.version)/$(uri_captures.endpoint)
- fixed remap:
/swagger/1.0/swagger.json
Public vs Protected Routing Model
Protected
Protected routes receive JWT plugin (key_claim_name=iss, verify exp):
- identity-protected
- pv-web-protected
- graph-protected
- sms-protected
- syassociates-private
Public
Public routes do not receive JWT plugin:
- auth/login-like endpoints
- docs/swagger compatibility
- graph compatibility endpoints such as
/graph/docs,/graph/resume, and gopher public API paths
Graph Mapping Model (Important)
The graph service in this repo follows this split:
- UI paths are passthrough at plain paths (for example
/resume,/gopher/*) - public docs paths are under
/graph/docs - API paths are under
/graph/v1/*(identity-style) and/graph/*compatibility paths
Kong mapping aligns with this:
/graph/docs and /graph/docs/* -> /docs*(public docs passthrough)/graph/v1/* -> /api/v1/*(JWT-protected versioned API)/resume -> /resume(UI passthrough)/gopher/* -> /gopher*(UI passthrough)/graph/gopher/* -> /graph/gopher/*(API paths)/graph/resumepublic API route supportsPOST,OPTIONS
OPTIONS is required for browser CORS preflight.
CORS Configuration Model
Global CORS is managed by upsert_global_cors_plugin.
Origins
Configured by KONG_CORS_ALLOWED_ORIGINS.
Current required origins include:
https://console.perspective-v.comhttps://hassan.taj.contacthttps://hassantaj.github.io
Headers
Configured by KONG_CORS_ALLOWED_HEADERS.
Current required headers include:
AuthorizationContent-TypeAppCode,appcode,APPCODEapollographql-client-nameapollographql-client-version
Methods
Configured by KONG_CORS_ALLOWED_METHODS with OPTIONS included.
Step-by-Step: Add a New Route in This Repo
- Add or identify the upstream service in the services section.
- Add
upsert_route(...)with:- unique route name
- correct service
- correct regex path
- methods including
OPTIONSif browser-facing - proper
regex_priority
- Add
upsert_rewrite_plugin(...)mapping inbound path to upstream path. - Add rate limit plugin via
upsert_rate_limit_plugin(route, second_limit). - If protected, add
upsert_jwt_route_plugin(route). - Update mapping doc table in
ocelot-to-kong-mapping.md. - Run bootstrap apply.
- Validate with curl and browser preflight checks.
Applying Changes Safely
Recommended apply commands
From runtime/stacks/infrastructure/gateway:
bash -n kong-bootstrap-ocelot.shThen apply with current live JWT secret loaded (or provided securely):
KONG_JWT_HMAC_SECRET="<current-secret>" ./kong-bootstrap-ocelot.shIf env values are used:
set -a
source /home/repo/contabo-server-setup/runtime/environments/vps/infrastructure/gateway/.env
set +a
KONG_JWT_HMAC_SECRET="<current-secret>" ./kong-bootstrap-ocelot.shValidation Patterns
Route behavior
- UI endpoints should return expected upstream behavior (not route-miss 404).
- Public API endpoints should not fall through to protected JWT route.
/graph/docsmust stay public and/graph/v1/*must stay JWT-protected.
CORS preflight
Example:
curl -ksS -D - -o /dev/null -X OPTIONS 'https://api.perspective-v.com/graph/resume' \
-H 'Origin: https://console.perspective-v.com' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: apollographql-client-name,content-type'Expect:
HTTP/2 200access-control-allow-originmatches request originaccess-control-allow-headersincludes Apollo headersaccess-control-allow-methodsincludesOPTIONS
Common Failure Modes and Fixes
1) Browser CORS blocked on graph route
Causes:
- origin not in global CORS origins
- required request header missing in allowed headers
- route does not include
OPTIONS
Fix:
- update
KONG_CORS_ALLOWED_ORIGINS - update
KONG_CORS_ALLOWED_HEADERS - ensure route methods include
OPTIONS - reapply bootstrap (or patch route/plugin live)
2) Public route returns 401 JWT error
Cause:
- request falls through to protected catch-all route.
Fix:
- add explicit public route
- raise regex priority above protected route
3) Public route returns 404 route miss
Cause:
- route absent, wrong path regex, wrong host, or wrong rewrite.
Fix:
- verify route inventory in Kong Admin
- verify host/path regex and rewrite target
How This Repo Mapped Ocelot to Kong
- Enumerated Ocelot upstream/downstream entries.
- Created Kong service per backend target.
- Created Kong route per Ocelot upstream template.
- Applied request-transformer rewrites to downstream templates.
- Attached JWT only where Ocelot required bearer auth.
- Added second-based rate limits to approximate Ocelot period limits.
- Added compatibility routes to preserve existing client URLs.
- Added explicit graph/gopher public routes with higher priority.
- Added CORS allow-headers and origins required by browser/Apollo clients.
Operational Notes
- Keep all route/plugin entities tagged
ocelot-migration. - Prefer script-driven idempotent updates over ad-hoc manual mutations.
- If emergency live patch is used, back-port the same change into bootstrap and mapping docs immediately.
Quick Checklist Before Closing a Kong Change
- service exists and points to correct upstream
- route exists with correct host/path/methods
-
OPTIONSincluded for browser-facing API routes - rewrite plugin maps to correct upstream URI
- protected/public auth behavior verified
- CORS origin/header/method preflight verified
- mapping doc updated
- state docs updated (
accepted-suggestions,requirements,already-implemented,next-steps)