Files
Genarrative/deploy/pingora/nginx-route-parity.matrix.json
kdletters a7711d2dc3 引入Pingora独立网关正式化链路
新增 pingora-gateway 独立二进制 crate,覆盖路由、静态资源、压缩、接流保护、TLS 直连和访问日志能力。

新增 Nginx canary、realpath canary、direct preflight、direct live、direct enable 和 rollback 脚本。

新增 Pingora 切流证据包、命令证据、manifest 验真、根目录总审计和 release readiness 聚合门禁。

完善 API release、Jenkins、systemd、health patrol、生产部署和发布包自包含校验。

更新 Pingora 试点文档、Nginx README 与 Hermes 共享记忆。
2026-06-17 20:16:51 +08:00

376 lines
11 KiB
JSON

{
"version": 1,
"description": "Pingora shadow gateway routes that must stay aligned with the current Genarrative Nginx production/development templates before any public cutover.",
"routes": [
{
"id": "acme_challenge",
"samplePath": "/.well-known/acme-challenge/token",
"expect": {
"kind": "static",
"root": "acme",
"mode": "exact"
},
"nginx": {
"production": [
"location /.well-known/acme-challenge/",
"root /var/www/html;"
]
},
"docs": ["`/.well-known/acme-challenge/*`"]
},
{
"id": "shadow_probe",
"samplePath": "/__genarrative_pingora/healthz",
"expect": {
"kind": "shadow_probe"
},
"docs": ["`/__genarrative_pingora/healthz`"]
},
{
"id": "admin_redirect",
"samplePath": "/admin",
"expect": {
"kind": "redirect_permanent",
"location": "/admin/"
},
"nginx": {
"production": ["location = /admin", "return 301 /admin/;"],
"development": ["location = /admin", "return 301 /admin/;"]
},
"docs": ["`/admin`", "301 到 `/admin/`"]
},
{
"id": "admin_api_proxy",
"samplePath": "/admin/api/users",
"expect": {
"kind": "proxy",
"target": "api",
"bodyLimit": null,
"protectionClass": "admin_api"
},
"nginx": {
"production": [
"location ^~ /admin/api/",
"proxy_pass http://genarrative_api/admin/api/;",
"limit_conn genarrative_api_conn 64;",
"limit_req zone=genarrative_admin_rps burst=16 nodelay;"
],
"development": [
"location ^~ /admin/api/",
"proxy_pass http://genarrative_api/admin/api/;",
"limit_conn genarrative_api_conn 64;",
"limit_req zone=genarrative_admin_rps burst=16 nodelay;"
]
},
"docs": ["`/admin/api/*`"]
},
{
"id": "admin_assets",
"samplePath": "/admin/assets/index.js",
"expect": {
"kind": "static",
"root": "web",
"mode": "exact"
},
"nginx": {
"production": ["location ^~ /admin/assets/", "try_files $uri =404;"],
"development": ["location ^~ /admin/assets/", "try_files $uri =404;"]
},
"docs": ["`/admin/assets/*`"]
},
{
"id": "admin_spa_fallback",
"samplePath": "/admin/settings",
"expect": {
"kind": "static",
"root": "web",
"mode": "spa_fallback"
},
"nginx": {
"production": [
"location ^~ /admin/",
"try_files $uri $uri/ /admin/index.html;"
],
"development": [
"location ^~ /admin/",
"try_files $uri $uri/ /admin/index.html;"
]
},
"docs": ["`/admin/*`"]
},
{
"id": "web_assets",
"samplePath": "/assets/app.js",
"expect": {
"kind": "static",
"root": "web",
"mode": "exact"
},
"nginx": {
"production": ["location ^~ /assets/", "try_files $uri =404;"],
"development": ["location ^~ /assets/", "try_files $uri =404;"]
},
"docs": ["`/assets/*`"]
},
{
"id": "puzzle_gallery_list",
"samplePath": "/api/runtime/puzzle/gallery",
"expect": {
"kind": "proxy",
"target": "api",
"bodyLimit": null,
"protectionClass": "gallery_list"
},
"nginx": {
"production": [
"location = /api/runtime/puzzle/gallery",
"limit_conn genarrative_api_conn 320;",
"limit_req zone=genarrative_gallery_rps burst=4096 nodelay;",
"add_header X-Accel-Buffering no always;"
],
"development": [
"location = /api/runtime/puzzle/gallery",
"limit_conn genarrative_api_conn 320;",
"limit_req zone=genarrative_gallery_rps burst=4096 nodelay;",
"add_header X-Accel-Buffering no always;"
]
},
"docs": ["`/api/runtime/puzzle/gallery`"]
},
{
"id": "custom_world_gallery_list",
"samplePath": "/api/runtime/custom-world-gallery",
"expect": {
"kind": "proxy",
"target": "api",
"bodyLimit": null,
"protectionClass": "gallery_list"
},
"nginx": {
"production": [
"location = /api/runtime/custom-world-gallery",
"limit_conn genarrative_api_conn 320;",
"limit_req zone=genarrative_gallery_rps burst=4096 nodelay;",
"add_header X-Accel-Buffering no always;"
],
"development": [
"location = /api/runtime/custom-world-gallery",
"limit_conn genarrative_api_conn 320;",
"limit_req zone=genarrative_gallery_rps burst=4096 nodelay;",
"add_header X-Accel-Buffering no always;"
]
},
"docs": ["`/api/runtime/custom-world-gallery`"]
},
{
"id": "puzzle_gallery_detail",
"samplePath": "/api/runtime/puzzle/gallery/work-a",
"expect": {
"kind": "proxy",
"target": "api",
"bodyLimit": null,
"protectionClass": "gallery_detail"
},
"nginx": {
"production": [
"location ~ ^/api/runtime/puzzle/gallery/[^/]+$",
"limit_conn genarrative_api_conn 32;",
"limit_req zone=genarrative_api_rps burst=32 nodelay;",
"add_header X-Accel-Buffering no always;"
],
"development": [
"location ~ ^/api/runtime/puzzle/gallery/[^/]+$",
"limit_conn genarrative_api_conn 32;",
"limit_req zone=genarrative_api_rps burst=32 nodelay;",
"add_header X-Accel-Buffering no always;"
]
},
"docs": ["`/api/runtime/puzzle/gallery/{id}`"]
},
{
"id": "custom_world_gallery_detail",
"samplePath": "/api/runtime/custom-world-gallery/profile-a/owner-b",
"expect": {
"kind": "proxy",
"target": "api",
"bodyLimit": null,
"protectionClass": "gallery_detail"
},
"nginx": {
"production": [
"location ~ ^/api/runtime/custom-world-gallery/[^/]+/[^/]+$",
"limit_conn genarrative_api_conn 32;",
"limit_req zone=genarrative_api_rps burst=32 nodelay;",
"add_header X-Accel-Buffering no always;"
],
"development": [
"location ~ ^/api/runtime/custom-world-gallery/[^/]+/[^/]+$",
"limit_conn genarrative_api_conn 32;",
"limit_req zone=genarrative_api_rps burst=32 nodelay;",
"add_header X-Accel-Buffering no always;"
]
},
"docs": ["`/api/runtime/custom-world-gallery/{profile}/{owner}`"]
},
{
"id": "generic_api_proxy",
"samplePath": "/api/creation-entry/config",
"expect": {
"kind": "proxy",
"target": "api",
"bodyLimit": "default",
"protectionClass": "api"
},
"nginx": {
"production": [
"location ~ ^/api(?:/|$)",
"client_max_body_size 64m;",
"limit_conn genarrative_api_conn 64;",
"limit_req zone=genarrative_api_rps burst=64 nodelay;",
"add_header X-Accel-Buffering no always;"
],
"development": [
"location ~ ^/api(?:/|$)",
"client_max_body_size 64m;",
"limit_conn genarrative_api_conn 64;",
"limit_req zone=genarrative_api_rps burst=64 nodelay;",
"add_header X-Accel-Buffering no always;"
]
},
"docs": ["`/api`、`/api/*`"]
},
{
"id": "spacetime_subscribe",
"samplePath": "/v1/database/genarrative/subscribe",
"expect": {
"kind": "proxy",
"target": "spacetime",
"bodyLimit": null,
"protectionClass": "spacetime"
},
"nginx": {
"production": [
"location ~ ^/v1/database/[^/]+/subscribe$",
"proxy_pass http://127.0.0.1:3101;",
"proxy_set_header Upgrade $http_upgrade;",
"proxy_set_header Connection \"Upgrade\";",
"proxy_read_timeout 3600s;"
],
"development": [
"location ~ ^/v1/database/[^/]+/subscribe$",
"proxy_pass http://127.0.0.1:3101;",
"proxy_set_header Upgrade $http_upgrade;",
"proxy_set_header Connection \"Upgrade\";",
"proxy_read_timeout 3600s;"
]
},
"docs": ["`/v1/database/{db}/subscribe`"]
},
{
"id": "spacetime_identity",
"samplePath": "/v1/identity",
"expect": {
"kind": "proxy",
"target": "spacetime",
"bodyLimit": null,
"protectionClass": "spacetime"
},
"nginx": {
"production": [
"location ^~ /v1/identity",
"proxy_pass http://127.0.0.1:3101;",
"proxy_set_header Upgrade $http_upgrade;",
"proxy_set_header Connection \"Upgrade\";"
],
"development": [
"location ^~ /v1/identity",
"proxy_pass http://127.0.0.1:3101;",
"proxy_set_header Upgrade $http_upgrade;",
"proxy_set_header Connection \"Upgrade\";"
]
},
"docs": ["`/v1/identity*`"]
},
{
"id": "v1_forbidden",
"samplePath": "/v1/ping",
"expect": {
"kind": "not_found"
},
"nginx": {
"production": ["location ^~ /v1/", "return 404;"],
"development": ["location ^~ /v1/", "return 404;"]
},
"docs": ["`/v1/*`"]
},
{
"id": "healthz_forbidden",
"samplePath": "/healthz",
"expect": {
"kind": "not_found"
},
"nginx": {
"production": [
"location ~ ^/(generated-|healthz|readyz)",
"return 404;"
],
"development": [
"location ~ ^/(generated-|healthz|readyz)",
"return 404;"
]
},
"docs": ["`/healthz*`"]
},
{
"id": "readyz_forbidden",
"samplePath": "/readyz",
"expect": {
"kind": "not_found"
},
"nginx": {
"production": [
"location ~ ^/(generated-|healthz|readyz)",
"return 404;"
],
"development": [
"location ~ ^/(generated-|healthz|readyz)",
"return 404;"
]
},
"docs": ["`/readyz*`"]
},
{
"id": "generated_assets_forbidden",
"samplePath": "/generated-puzzle-assets/foo.webp",
"expect": {
"kind": "not_found"
},
"nginx": {
"production": [
"location ~ ^/(generated-|healthz|readyz)",
"return 404;"
],
"development": [
"location ~ ^/(generated-|healthz|readyz)",
"return 404;"
]
},
"docs": ["`/generated-*`"]
},
{
"id": "web_spa_fallback",
"samplePath": "/some/spa/path",
"expect": {
"kind": "static",
"root": "web",
"mode": "spa_fallback"
},
"nginx": {
"production": ["location /", "try_files $uri $uri/ /index.html;"],
"development": ["location /", "try_files $uri $uri/ /index.html;"]
},
"docs": ["其它路径", "失败回退 `/index.html`"]
}
]
}