πŸ“„ SKILL.md

← Vault

name: chatwoot-community-upgradepage-fix

description: Fix Chatwoot (Community OR Enterprise) showing UpgradePage.vue (blank screen) when Dashboard App iframe loads, caused by /enterprise/api/v1/accounts/1/limits returning 404

triggers:

- chatwoot blank screen iframe dashboard app

- UpgradePage.vue 404 limits enterprise

- chatwoot community edition enterprise limits 404

- chatwoot enterprise edition limits 404 blank screen

- STACKLAB_KANBAN_ENABLED upgrade page overlay


Problem

Chatwoot (both Community and Enterprise editions) calls GET /enterprise/api/v1/accounts/{id}/limits on every page load to check plan limits. This endpoint either doesn't exist (Community) or is missing in the installed version (Enterprise) β†’ returns 404 β†’ Chatwoot Vuex store dispatches an error β†’ UpgradePage.vue is rendered β†’ entire app shows blank/upgrade screen, blocking Dashboard Apps iframe.

Diagnosis commands:

`bash

1. Check edition inside container

docker exec root-rails-1 env | grep -i ENTERPRISE

Community: returns empty | Enterprise: CW_EDITION=ee

2. Verify the 404 from outside

curl -sI "https://chat.rochasalesseguros.com.br/enterprise/api/v1/accounts/1/limits"

HTTP/2 404 = confirmed cause

3. Check if limits call is happening (browser Network tab)

GET /enterprise/api/v1/accounts/1/limits β†’ 404

`

Stack trace: getLimits @ account.js:18 β†’ error dispatched to Vuex store β†’ UpgradePage.vue:95 (error callback in accounts.js actions)

Fix Option A β€” Nginx response injection (RECOMMENDED, survives container restarts)

Add a nginx location block to intercept the limits call and return a fake 200 JSON response. This is the cleanest fix β€” no container changes needed.

On the VPS host (not inside the container):

`nginx

Add to the nginx config that serves Chatwoot (usually /etc/nginx/sites-enabled/chatwoot)

inside the server {} block for chat.rochasalesseguros.com.br:

location ~* ^/enterprise/api/v1/accounts/\d+/limits$ {

default_type application/json;

return 200 '{"data":{"features":{},"limits":{}}}';

add_header Content-Type application/json;

add_header X-Enterprise-Limits "mocked" always;

}

`

Reload nginx: nginx -t && nginx -s reload

Verify:

`bash

curl -s "https://chat.rochasalesseguros.com.br/enterprise/api/v1/accounts/1/limits"

Should return: {"data":{"features":{},"limits":{}}}

`

Fix Option B β€” Patch account.js inside container (ephemeral, lost on restart)

Use this if nginx approach isn't possible (e.g., shared hosting without nginx control).

`bash

Find the container

docker ps | grep -E "chatwoot|rails"

Find the account.js store file

docker exec root-rails-1 find /app -name "account.js" -path "/dashboard/store/"

Patch getLimits to swallow 404 errors

docker exec root-rails-1 sed -i \

's/(error) => {/(error) => { if (error.response?.status === 404) return; /' \

/app/app/javascript/dashboard/store/modules/account.js

Verify the patch

docker exec root-rails-1 grep -A2 "error) => {" /app/app/javascript/dashboard/store/modules/account.js

Restart container

docker restart root-rails-1

`

NOTE: If the JS assets are precompiled (RAILS_ENV=production), the source file patch won't take effect unless you also run rake assets:precompile inside the container, or rebuild the image.

Fix Option C β€” Disable STACKLAB_KANBAN_ENABLED (removes kanban, avoids the bug)

If the kanban feature is not critical and you just want a clean Chatwoot:

`bash

Edit docker-compose.yml and remove STACKLAB_KANBAN_ENABLED=true

Then: docker-compose up -d --force-recreate

`

Verification Steps

1. Open Chatwoot in browser and log in

2. Navigate to Dashboard App (e.g., /app/accounts/1/kanban)

3. The iframe should render correctly instead of blank/upgrade page

4. Browser console: 404 may still appear in Network tab but no longer blocks the app

5. Run: curl -s "https://chat.rochasalesseguros.com.br/enterprise/api/v1/accounts/1/limits" β†’ should return 200 JSON

Pitfalls

1. Container filesystem is ephemeral β€” docker exec changes to source files are LOST after docker restart. Option A (nginx) is permanent; Option B needs a volume mount or image rebuild to persist.

2. Asset pipeline β€” In production mode (RAILS_ENV=production), JS is precompiled into /public/packs/. Patching app/javascript/ source files won't affect the running app unless assets are recompiled (rake assets:precompile inside container).

3. STACKLAB_KANBAN_ENABLED flag β€” If the Chatwoot container was started with STACKLAB_KANBAN_ENABLED=true, it forces isEnterprise: "true" in the frontend JS bundle even on Community Edition, making the limits call on every page load. This flag is set in the docker-compose.yml or Docker env.

4. The limits call is non-blocking by intent β€” but the Vuex error handler in App.vue re-renders the entire app with UpgradePage.vue on ANY unhandled store error, not just the limits call. The fix must swallow the 404, not disable the error handler globally.

5. Enterprise Edition still affected β€” Even when CW_EDITION=ee is set, if the installed version doesn't include the /enterprise/api/v1/accounts/1/limits endpoint, the same 404 β†’ UpgradePage occurs. The nginx fix works for both Community and Enterprise.

Additional Bug β€” DashboardAppFrame iframe never renders (v-if on isVisible)

The DashboardAppFrame.vue component has v-if="hasOpenedAtleastOnce" which guards the iframe render. hasOpenedAtleastOnce is set to true via a watch on isVisible prop. But if isVisible is passed as a static :is-visible="true" (never changes), the watcher never fires β†’ hasOpenedAtleastOnce stays false β†’ iframe never renders.

File: app/javascript/dashboard/components/widgets/DashboardApp/Frame.vue

Fix in KanbanPage.vue:

`javascript

data() {

return { isVisible: false };

},

mounted() {

this.$nextTick(() => {

setTimeout(() => { this.isVisible = true; }, 100);

});

},

`

This changes isVisible from false→true AFTER mount, triggering the watcher which sets hasOpenedAtleastOnce = true, rendering the iframe.

References