From c3408a498a989c06d458bec7370b71f2b119f1f9 Mon Sep 17 00:00:00 2001 From: Alireza Hassani Date: Tue, 11 Aug 2026 16:15:52 +0330 Subject: [PATCH] Route social crawlers on invoice URLs to Open Graph HTML. Bots hitting /invoices/:id on manage get API OG markup; browsers still load the SPA. Co-authored-by: Cursor --- apps/super-admin/public/og-invoice.png | Bin 0 -> 11859 bytes deploy/nginx-dashboards-ssl.conf | 26 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 apps/super-admin/public/og-invoice.png diff --git a/apps/super-admin/public/og-invoice.png b/apps/super-admin/public/og-invoice.png new file mode 100644 index 0000000000000000000000000000000000000000..9b7eaf115811a50ff1525215989153bf3046853c GIT binary patch literal 11859 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 J`K5th{ws4?{O|w( literal 0 HcmV?d00001 diff --git a/deploy/nginx-dashboards-ssl.conf b/deploy/nginx-dashboards-ssl.conf index ea82ddd..dde8bc3 100644 --- a/deploy/nginx-dashboards-ssl.conf +++ b/deploy/nginx-dashboards-ssl.conf @@ -1,4 +1,12 @@ # HTTPS dashboards (Certbot SANs on meshkee-dashboards) +# +# Link-preview bots (WhatsApp, etc.) hitting /invoices/:id get Open Graph HTML +# from the API; browsers still receive the SPA. + +map $http_user_agent $meshkee_link_preview_bot { + default 0; + ~*(whatsapp|facebookexternalhit|facebot|twitterbot|linkedinbot|slackbot|telegrambot|discordbot) 1; +} server { listen 443 ssl; @@ -7,6 +15,24 @@ server { ssl_certificate_key /etc/letsencrypt/live/meshkee-dashboards/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; + location ~ ^/invoices/(?[0-9]{6,32})$ { + if ($meshkee_link_preview_bot = 1) { + rewrite ^ /__internal/invoice-og/$invoice_public_id last; + } + root /var/www/meshkee/super-admin; + try_files /index.html =404; + } + + location ~ ^/__internal/invoice-og/([0-9]{6,32})$ { + internal; + proxy_pass https://api.meshkee.com/api/v1/public/invoices/$1/og; + proxy_ssl_server_name on; + proxy_set_header Host api.meshkee.com; + 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; + } + location / { root /var/www/meshkee/super-admin; try_files $uri $uri/ /index.html;