Files
Zimin A.N. c86ce8c8d5 fix(nginx): route /api/v1/ai/* к writer (был fall-through к read-api → 500)
После !234 ship'нул AiSchemaController на writer, frontend hit /api/v1/ai/info
получает 500 — generic /api/v1/ location route к read-api который не имеет
этих handlers. Тот же pattern fix что для /drafts/, /me/, /admin/ — explicit
location к writer перед generic /api/v1/ fallback.

Без этого AI feature unusable в staging (даже если backend healthy).
2026-05-16 19:51:04 +03:00

168 lines
7.6 KiB
Nginx Configuration File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
server {
listen 80;
server_name _;
# Resolver — coredns (10.233.0.3 на kubespray-кластерах). nodelocal-dns
# (169.254.25.10) при первом cold lookup отвечает SERVFAIL, поэтому
# обращаемся напрямую к ClusterDNS service.
resolver ${RESOLVER_IP} valid=30s ipv6=off;
# Real client IP behind ingress-nginx.
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
root /usr/share/nginx/html;
index index.html;
# /api/v1/dictionaries/* — все admin endpoints (schema, raw record, mutations) идут
# на writer. Read-api держит /api/v1/{name}/records/* (другой URL pattern, flatten i18n).
# Regex-location имеет приоритет над префиксом ниже.
location ~ ^/api/v1/dictionaries/ {
set $backend "ordinis-app.${ORDINIS_NAMESPACE}.svc.${CLUSTER_DOMAIN}";
proxy_pass http://$backend$request_uri;
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;
proxy_pass_request_headers on;
}
# /api/v1/version — VersionController в ordinis-rest-api → подключён ТОЛЬКО в
# writer (см. ordinis-app/pom.xml). Без явного правила generic /api/v1/ ниже
# роутит GET → read-api → 500 NoResourceFoundException → пустой traceId.
# Тот же класс баги что для /drafts/me ниже.
location = /api/v1/version {
set $backend "ordinis-app.${ORDINIS_NAMESPACE}.svc.${CLUSTER_DOMAIN}";
proxy_pass http://$backend$request_uri;
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;
proxy_pass_request_headers on;
}
# /api/v1/search — SearchController (global trigram-search across all dicts)
# тоже в ordinis-rest-api → только writer. Без route'а — 500 в Smart Search.
location ~ ^/api/v1/search(/|$|\?) {
set $backend "ordinis-app.${ORDINIS_NAMESPACE}.svc.${CLUSTER_DOMAIN}";
proxy_pass http://$backend$request_uri;
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;
proxy_pass_request_headers on;
}
# /api/v1/records/{dict}/{businessKey}/dependents — record-level lineage
# endpoint в LineageController (ordinis-rest-api → writer). Префикс /records/
# на root уровне отличается от /api/v1/{dict}/records/* read-api endpoint'а
# — нужно явное правило, иначе fallback на read-api → 500.
location ~ ^/api/v1/records/ {
set $backend "ordinis-app.${ORDINIS_NAMESPACE}.svc.${CLUSTER_DOMAIN}";
proxy_pass http://$backend$request_uri;
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;
proxy_pass_request_headers on;
}
# /api/v1/admin/* — audit + outbox admin endpoints на writer.
location ~ ^/api/v1/admin/ {
set $backend "ordinis-app.${ORDINIS_NAMESPACE}.svc.${CLUSTER_DOMAIN}";
proxy_pass http://$backend$request_uri;
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;
proxy_pass_request_headers on;
}
# /api/v1/drafts/* — Approval Workflow v2 endpoints (submit/approve/reject/withdraw)
# + GET /drafts/me (maker self-tracking) + GET /drafts/{id}. Все живут на writer —
# read-api не имеет DraftController. Без явного правила GET /drafts/me ловится
# generic /api/v1/ ниже → read-api → 500 NoResourceFoundException.
location ~ ^/api/v1/drafts(/|$) {
set $backend "ordinis-app.${ORDINIS_NAMESPACE}.svc.${CLUSTER_DOMAIN}";
proxy_pass http://$backend$request_uri;
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;
proxy_pass_request_headers on;
}
# /api/v1/me/* — current-user self-scope endpoints (notifications + future
# preferences). Все на writer (MeNotificationsController в ordinis-rest-api).
# Тот же шаблон что для /drafts: без явного правила GET → read-api → 500
# NoResourceFoundException → bell badge на каждой странице бомбит "Внутренняя
# ошибка сервера". Закрывает observed bug в v2.27.2 (TODO 7).
location ~ ^/api/v1/me(/|$) {
set $backend "ordinis-app.${ORDINIS_NAMESPACE}.svc.${CLUSTER_DOMAIN}";
proxy_pass http://$backend$request_uri;
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;
proxy_pass_request_headers on;
}
# /api/v1/ai/* — AI Schema Assist (LlmAdapter + AiSchemaController). Writer
# only — read-api не подключает ordinis-rest-api ai package. Без явного
# правила generic /api/v1/ ниже → read-api → 500 NoResourceFoundException.
# Conditional на ordinis.ai.enabled — если flag off, controller бесконечно
# не зарегистрирован, writer возвращает 404 чисто (frontend hides UI).
location ~ ^/api/v1/ai(/|$) {
set $backend "ordinis-app.${ORDINIS_NAMESPACE}.svc.${CLUSTER_DOMAIN}";
proxy_pass http://$backend$request_uri;
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;
proxy_pass_request_headers on;
}
# Swagger UI + OpenAPI spec на writer (там обвязаны контроллеры).
location ~ ^/(swagger-ui|v3/api-docs|swagger-resources|webjars/swagger-ui) {
set $backend "ordinis-app.${ORDINIS_NAMESPACE}.svc.${CLUSTER_DOMAIN}";
proxy_pass http://$backend$request_uri;
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;
proxy_pass_request_headers on;
}
# GET → read-api, мутирующие → writer.
# FQDN в proxy_pass нужен потому что nginx resolver не использует search list.
# Namespace и cluster-domain инжектятся через ENV (см. admin-ui Deployment).
location /api/v1/ {
set $backend "ordinis-read-api.${ORDINIS_NAMESPACE}.svc.${CLUSTER_DOMAIN}";
if ($request_method ~ ^(POST|PUT|PATCH|DELETE)$) {
set $backend "ordinis-app.${ORDINIS_NAMESPACE}.svc.${CLUSTER_DOMAIN}";
}
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;
proxy_pass_request_headers on;
}
# SPA history fallback.
location / {
try_files $uri $uri/ /index.html;
}
}