Repository navigation
Conversation
syncPages names each local file by page.name, but every custom (page-builder) page shares the name "legacy". On campaigns with more than one custom page, all of them are written to the same legacy.json (last write wins), so most custom pages never appear locally and the surviving file's identity changes between syncs. Name files by the page's unique name when it is unique across the campaign, and fall back to the page path otherwise (cause-areas.json, terms.json, ...). Residual collisions after sanitization are disambiguated with a short uuid suffix. Deploy is unaffected: pages are PATCHed by the uuid stored inside each file. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
Reviewed by Cursor Bugbot for commit 72243dd. Configure here.
Two-pass assignment so a custom page whose path sanitizes to a template page's name (e.g. /profile vs the profile template at /:id) can never take that template's filename, regardless of API order. The custom page gets the uuid-suffixed name instead. Addresses Bugbot review on raisely#85. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Good catch from Bugbot — fixed in 5489e7d. |
Two-pass assignment so a custom page whose path sanitizes to a template page's name (e.g. /profile vs the profile template at /:id) can never take that template's filename, regardless of API order. The custom page gets the uuid-suffixed name instead. Addresses Bugbot review on raisely#85. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@xolott-ark @giovanny-keela Hi there! Are either of you able to approve this PR? It has been outstanding for a while and breaks basic functionality of the cli. |
KeinerM
left a comment
There was a problem hiding this comment.
@k-r-a-s-s Thank you for tracking this down, and sorry this took a while to review. The write-up made the bug easy to reproduce, and the template-name reservation you added after the Bugbot comment works well.
We tested the branch on a staging campaign. Sync now writes every page, and the filenames stay the same between runs. We found one case that affects people who are upgrading.
Sync doesn't remove the file it wrote under the old name, so after the first sync two files share a uuid. In our test:
legacy.jsonandrenamed-home-page.jsonmagicLink.jsonandmagic-link-a0a04680.json
raisely local picked the old magicLink.json, and raisely deploy would send both files as updates for the same page, so the old content could win.
Could you have syncPages remove those old files after it writes the new ones? Only files whose uuid was part of this sync and whose filename differs from the new one. Files from pages that weren't in the sync, and files that aren't valid JSON, should stay. A test with an old legacy.json in the pages folder would cover it.
If you'd rather not, we're happy to push this change to your branch or follow up in a separate PR. Thanks again for the fix.
|
|
||
| fs.writeFileSync( | ||
| path.join(pagesDir, pageFileName(page)), | ||
| path.join(pagesDir, fileNames[index]), |
There was a problem hiding this comment.
One small follow-up here: could we remove old page files whose UUID we just wrote under a new name, like legacy.json? Details in the review summary.

Problem
raisely update/raisely initwrite each synced page topages/<page.name>.json. Template pages have unique names (home,dashboard,profile, …), but every custom page-builder page hasname: "legacy"— so on any campaign with more than one custom page, all of them are written to the samelegacy.json, last write wins.Observed on our campaign: the API returns 72 pages, 55 of which are custom (
name: "legacy"). After a sync, only the ~20 uniquely-named template pages plus a singlelegacy.jsonexist locally — 54 custom pages never land on disk, andlegacy.jsonholds whichever custom page the API happened to return last (which can change between syncs).Beyond the missing files, this is a correctness hazard:
raisely deployPATCHes every local page JSON by its embedded uuid, so a stalelegacy.jsonsnapshot of a semi-random page can silently revert that page's body/status/path in the admin.Fix
Extract the naming logic into
pageFileNames(pages), which computes names for a campaign's page set as a whole:nameis used only when it's unique within the campaign (all existing template-page filenames are unchanged:home.json,dashboard.json, …);/cause-areas→cause-areas.json), matching the existing fallback already used for unnamed pages;Deploy needs no changes — it already resolves the target page from the
uuidinside each file, not the filename.Notes
legacy.jsonis left behind and can be deleted (it duplicates one of the new files' uuid).tests/sync.test.jscovering unique names, the shared-legacyfallback, unnamed pages, sanitization, and suffix disambiguation. Full suite passes (111/111).🤖 Generated with Claude Code
Note
Medium Risk
Sync output filenames change for campaigns with multiple custom pages, which can leave stale
legacy.jsonlocally but fixes silent data loss and deploy correctness risk from wrong page bodies keyed by uuid.Overview
Fixes page sync so multiple custom (page-builder) pages no longer overwrite a single
legacy.jsonwhen they all sharename: "legacy".pageFileNames(pages)replaces per-pagepageFileName: it assigns filenames across the whole campaign—uniquepage.namevalues still map to stable template files (home.json, etc.), while shared or missing names use path-based names with sanitization, and uuid suffixes when paths collide after sanitization. A two-pass rule reserves unique name-based filenames so API order cannot steal e.g.profile.jsonfrom a template page.syncPageswrites each page using the computed filename; deploy behavior is unchanged because targets are resolved by embedded uuid, not filename. Newtests/sync.test.jscovers sharedlegacy, unnamed pages, sanitization, template reservation, and collision suffixes.Reviewed by Cursor Bugbot for commit 5489e7d. Bugbot is set up for automated code reviews on this repo. Configure here.