7ea463ed08
保留 SpacetimeDB 历史表、迁移白名单与最小兼容读取定义 移除旧创作前后端、worker、业务过程及纯业务 crate 的编译依赖 恢复现役创作、项目、我的入口及桌面移动导航 收紧 Vite、TypeScript、ESLint、Vitest 与静态资源退役边界 补齐开发栈、网关、原生壳和文档退役约束
467 lines
11 KiB
JSON
467 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": "generic_api_proxy",
|
|
"samplePath": "/api/assets/history",
|
|
"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": "/project",
|
|
"expect": {
|
|
"kind": "static",
|
|
"root": "web",
|
|
"mode": "spa_fallback"
|
|
},
|
|
"nginx": {
|
|
"production": [
|
|
"# BEGIN GENARRATIVE MAIN SPA ROUTES",
|
|
"try_files $uri /index.html =404;"
|
|
],
|
|
"development": [
|
|
"# BEGIN GENARRATIVE MAIN SPA ROUTES",
|
|
"try_files $uri /index.html =404;"
|
|
]
|
|
},
|
|
"docs": [
|
|
"主站 SPA allowlist",
|
|
"失败回退 `/index.html`"
|
|
]
|
|
},
|
|
{
|
|
"id": "profile_spa_fallback",
|
|
"samplePath": "/profile",
|
|
"expect": {
|
|
"kind": "static",
|
|
"root": "web",
|
|
"mode": "spa_fallback"
|
|
},
|
|
"nginx": {
|
|
"production": [
|
|
"# BEGIN GENARRATIVE MAIN SPA ROUTES",
|
|
"try_files $uri /index.html =404;"
|
|
],
|
|
"development": [
|
|
"# BEGIN GENARRATIVE MAIN SPA ROUTES",
|
|
"try_files $uri /index.html =404;"
|
|
]
|
|
},
|
|
"docs": [
|
|
"主站 SPA allowlist",
|
|
"失败回退 `/index.html`"
|
|
]
|
|
},
|
|
{
|
|
"id": "web_spa_case_trailing_slash",
|
|
"samplePath": "/PROJECT/",
|
|
"expect": {
|
|
"kind": "static",
|
|
"root": "web",
|
|
"mode": "spa_fallback"
|
|
},
|
|
"nginx": {
|
|
"production": [
|
|
"location ~*",
|
|
"try_files $uri /index.html =404;"
|
|
],
|
|
"development": [
|
|
"location ~*",
|
|
"try_files $uri /index.html =404;"
|
|
]
|
|
},
|
|
"docs": [
|
|
"大小写不敏感",
|
|
"一个尾部斜杠"
|
|
]
|
|
},
|
|
{
|
|
"id": "web_unknown_path_exact",
|
|
"samplePath": "/some/spa/path",
|
|
"expect": {
|
|
"kind": "static",
|
|
"root": "web",
|
|
"mode": "exact"
|
|
},
|
|
"nginx": {
|
|
"production": [
|
|
"location /",
|
|
"try_files $uri $uri/ =404;"
|
|
],
|
|
"development": [
|
|
"location /",
|
|
"try_files $uri $uri/ =404;"
|
|
]
|
|
},
|
|
"docs": [
|
|
"其它 Web 路径",
|
|
"缺失时返回真实 404"
|
|
]
|
|
},
|
|
{
|
|
"id": "creation_unknown_path_exact",
|
|
"samplePath": "/creation/not-exist",
|
|
"expect": {
|
|
"kind": "static",
|
|
"root": "web",
|
|
"mode": "exact"
|
|
},
|
|
"nginx": {
|
|
"production": [
|
|
"try_files $uri $uri/ =404;"
|
|
],
|
|
"development": [
|
|
"try_files $uri $uri/ =404;"
|
|
]
|
|
},
|
|
"docs": [
|
|
"`/creation/not-exist`"
|
|
]
|
|
},
|
|
{
|
|
"id": "runtime_unknown_path_exact",
|
|
"samplePath": "/runtime/not-exist",
|
|
"expect": {
|
|
"kind": "static",
|
|
"root": "web",
|
|
"mode": "exact"
|
|
},
|
|
"nginx": {
|
|
"production": [
|
|
"try_files $uri $uri/ =404;"
|
|
],
|
|
"development": [
|
|
"try_files $uri $uri/ =404;"
|
|
]
|
|
},
|
|
"docs": [
|
|
"`/runtime/not-exist`"
|
|
]
|
|
},
|
|
{
|
|
"id": "puzzle_unknown_path_exact",
|
|
"samplePath": "/puzzle/not-exist",
|
|
"expect": {
|
|
"kind": "static",
|
|
"root": "web",
|
|
"mode": "exact"
|
|
},
|
|
"nginx": {
|
|
"production": [
|
|
"try_files $uri $uri/ =404;"
|
|
],
|
|
"development": [
|
|
"try_files $uri $uri/ =404;"
|
|
]
|
|
},
|
|
"docs": [
|
|
"`/puzzle/not-exist`"
|
|
]
|
|
}
|
|
]
|
|
}
|