From 7d48c349deaf602dd5a3480fa3da19b40389e413 Mon Sep 17 00:00:00 2001 From: Frances-bot <263591795+Franc3s-bot@users.noreply.github.com> Date: Sat, 1 Aug 2026 09:51:30 +0000 Subject: [PATCH 1/5] Update external_data submodule to 0a53315 (xwing-data2-legacy -> Darker333 master) --- external_data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external_data b/external_data index 7c538039..0a533156 160000 --- a/external_data +++ b/external_data @@ -1 +1 @@ -Subproject commit 7c5380393e4a17940e09f781c19f40feb0ecb204 +Subproject commit 0a5331564401bcf4bb819d87467385ad82719d05 From adc225b747310a6569d585ad0aec0dcbad7f0c75 Mon Sep 17 00:00:00 2001 From: Frances-bot <263591795+Franc3s-bot@users.noreply.github.com> Date: Thu, 13 Aug 2026 14:52:12 +0000 Subject: [PATCH 2/5] fix(frontend): route preview /api proxy to PR-specific backend container The generic 'backend' docker hostname resolves to the old shared backend on the coolify network, so all preview deployments served stale data. Preview proxies now target 'backend-pr-' via COOLIFY_BRANCH/hostname. --- frontend/src/routes/api/[...path]/+server.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/frontend/src/routes/api/[...path]/+server.js b/frontend/src/routes/api/[...path]/+server.js index 31f2c69b..c6673859 100644 --- a/frontend/src/routes/api/[...path]/+server.js +++ b/frontend/src/routes/api/[...path]/+server.js @@ -4,13 +4,24 @@ function normalizeBackendApiBase(raw) { return trimmed.endsWith('/api') ? trimmed : `${trimmed}/api`; } +function previewBackendHost() { + // PR-specific backend containers are reachable as `backend-pr-` on the + // shared coolify network. The generic `backend` alias belongs to the old + // shared backend, so previews must target their own container. + const fromBranch = (process.env.COOLIFY_BRANCH || '').match(/^pull\/(\d+)$/); + if (fromBranch) { + return `backend-pr-${fromBranch[1]}`; + } + return null; +} + function resolvePreviewBackendApiBase(requestUrl) { try { const host = new URL(requestUrl).hostname; const match = host.match(/^(\d+)\.dev\.m3tacron\.com$/); if (match) { // Preview deployment - talk directly to local backend container via docker network - return 'http://backend:8888/api'; + return `http://backend-pr-${match[1]}:8888/api`; } } catch { // Fall through to the default proxy target. @@ -42,7 +53,8 @@ export async function GET({ params, url, fetch, request }) { const path = params.path || ''; // Preview deployments: always use internal Docker network to reach backend const isPreview = process.env.ENV_VAR_SOURCE === 'preview' || (process.env.COOLIFY_BRANCH || '').startsWith('pull/'); - const backendBase = isPreview ? 'http://backend:8888/api' : (resolveBackendApiBase() || resolvePreviewBackendApiBase(request.url)); + const previewHost = isPreview ? previewBackendHost() : null; + const backendBase = previewHost ? `http://${previewHost}:8888/api` : (resolveBackendApiBase() || resolvePreviewBackendApiBase(request.url)); const target = new URL(`${backendBase}/${path}`); for (const [key, value] of url.searchParams.entries()) { From a8a9b9b8d3a5693749966f4ebe8568f99e9134aa Mon Sep 17 00:00:00 2001 From: Frances-bot <263591795+Franc3s-bot@users.noreply.github.com> Date: Thu, 13 Aug 2026 15:58:05 +0000 Subject: [PATCH 3/5] fix(frontend): match COOLIFY_BRANCH 'pull/N/head' for preview backend host --- frontend/src/routes/api/[...path]/+server.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/routes/api/[...path]/+server.js b/frontend/src/routes/api/[...path]/+server.js index c6673859..0372303b 100644 --- a/frontend/src/routes/api/[...path]/+server.js +++ b/frontend/src/routes/api/[...path]/+server.js @@ -8,7 +8,8 @@ function previewBackendHost() { // PR-specific backend containers are reachable as `backend-pr-` on the // shared coolify network. The generic `backend` alias belongs to the old // shared backend, so previews must target their own container. - const fromBranch = (process.env.COOLIFY_BRANCH || '').match(/^pull\/(\d+)$/); + // COOLIFY_BRANCH is like `pull/131/head`. + const fromBranch = (process.env.COOLIFY_BRANCH || '').match(/^pull\/(\d+)/); if (fromBranch) { return `backend-pr-${fromBranch[1]}`; } From 8618ac27665efe295b9cc17f8fb636620af8b6a5 Mon Sep 17 00:00:00 2001 From: Frances-bot <263591795+Franc3s-bot@users.noreply.github.com> Date: Thu, 13 Aug 2026 16:26:17 +0000 Subject: [PATCH 4/5] fix(frontend): strip quotes from COOLIFY_BRANCH before matching PR number --- frontend/src/routes/api/[...path]/+server.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/routes/api/[...path]/+server.js b/frontend/src/routes/api/[...path]/+server.js index 0372303b..f14fd3cb 100644 --- a/frontend/src/routes/api/[...path]/+server.js +++ b/frontend/src/routes/api/[...path]/+server.js @@ -8,8 +8,10 @@ function previewBackendHost() { // PR-specific backend containers are reachable as `backend-pr-` on the // shared coolify network. The generic `backend` alias belongs to the old // shared backend, so previews must target their own container. - // COOLIFY_BRANCH is like `pull/131/head`. - const fromBranch = (process.env.COOLIFY_BRANCH || '').match(/^pull\/(\d+)/); + // COOLIFY_BRANCH is like `pull/131/head` but Coolify quotes the value + // (e.g. `"pull/131/head"`), so strip any surrounding quotes first. + const branch = String(process.env.COOLIFY_BRANCH || '').replace(/^"|"$/g, ''); + const fromBranch = branch.match(/^pull\/(\d+)/); if (fromBranch) { return `backend-pr-${fromBranch[1]}`; } From f33c62aeb805a00ae862c6ba3440ed2a55dd6bdb Mon Sep 17 00:00:00 2001 From: Frances-bot <263591795+Franc3s-bot@users.noreply.github.com> Date: Thu, 13 Aug 2026 16:37:07 +0000 Subject: [PATCH 5/5] docs(skill): add Coolify CLI usage + preview proxy gotchas to m3tacron skill --- .agents/skills/m3tacron/SKILL.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/.agents/skills/m3tacron/SKILL.md b/.agents/skills/m3tacron/SKILL.md index 7149bbd3..07c4a73a 100644 --- a/.agents/skills/m3tacron/SKILL.md +++ b/.agents/skills/m3tacron/SKILL.md @@ -1,6 +1,6 @@ --- name: m3tacron -description: SSH access and database connection info for the m3tacron project servers (m3tacron.com, dev.m3tacron.com). Load whenever you need to connect to the server or inspect the database. +description: SSH access, database connection info, and Coolify deployment info for the m3tacron project (m3tacron.com, dev.m3tacron.com). Load whenever you need to connect to the server, inspect the database, or trigger/manage Coolify preview deployments via the coolify CLI. --- ## SSH Access @@ -30,3 +30,29 @@ The `audit-bot` user has docker group access. Use `docker ps` to list containers ```bash docker exec psql -U postgres -c "SELECT COUNT(*) FROM tournament;" ``` + +## Coolify CLI (preview deployments) + +The `coolify` CLI is installed locally and configured with context `m3tacron` +(`https://coolify.m3tacron.com`, deploy-scoped API token in `~/.config/coolify/config.json`). + +### Trigger a PR preview redeploy +```bash +coolify deploy uuid d1237bghfe3rxgm7ahj00z8l --pull-request-id --force +``` +Application UUID `d1237bghfe3rxgm7ahj00z8l` = `francespo/m3tacron:main` (preview deployments are per-PR). + +### Prerequisites / gotchas (already configured) +- Coolify API must be enabled: `instance_settings.is_api_enabled = true` (was disabled → CLI returned 403 "API is disabled"). +- Token is a Laravel Sanctum personal access token created via tinker with abilities `["deploy","read","write"]`. + Coolify's custom `createToken` requires `session(['currentTeam' => $team])` to be set first (team_id is NOT NULL). + +### Preview proxy architecture (for debugging why a preview shows stale data) +- Each PR preview has its own backend container, reachable as `backend-pr-` on the shared coolify network. + The generic `backend` hostname belongs to the OLD shared backend — never use it for previews. +- Frontend proxy: `frontend/src/routes/api/[...path]/+server.js` resolves the backend via + `previewBackendHost()` reading `COOLIFY_BRANCH`. +- Gotcha: Coolify sets `COOLIFY_BRANCH` **with literal quotes** (e.g. `"pull/131/head"`) — strip quotes + before matching `/^pull\/(\d+)/`. Also the value has a `/head` suffix. +- Verify data freshness: `GET /api/pilot/ricolie` returns `cost` (old=4 on 20-pt scale, new=11 on 50-pt scale). +- Preview domains: `131.dev.m3tacron.com` (frontend) / `131.dev.api.m3tacron.com` (backend, internal only).