Description
After logging in with an account that has no communicator and no boards on the server, doing the first board sync with two or more local boards pending fails with 500 Internal Server Error on PUT /communicator/:id.
The first board push succeeds (POST /communicator). The second board push then issues a PUT with a payload that still carries the default communicator fields (email: 'support@cboard.io', author: 'Cboard Team') instead of the user's data, which the server rejects.
Steps to reproduce
- Create an account that has no communicator nor boards on the server.
- Before logging in, have at least two local boards pending sync (e.g. created while unlogged or modified default boards).
- Log in and let the sync engine run (
getApiObjects → syncBoards → pushLocalChangesToApi).
- Observe Network tab: first POST
/communicator returns 200, second PUT /communicator/:id returns 500.
Root cause
pushLocalChangesToApi in src/components/Board/Board.actions.js calls updateApiObjectsNoChild for each board needing creation. That helper ends with upsertApiCommunicator(comm):
- First call:
comm.id === 'cboard_default' → goes through createApiCommunicator (POST). api.js strips the id and overrides email / author with the user's data, so the POST succeeds.
- The
CREATE_API_COMMUNICATOR_SUCCESS reducer only copies id and lastEdited from the response, leaving email and author as the default values locally.
- Second call:
comm.id is now the Mongo id from the server → goes through updateApiCommunicator (PUT). The PUT body is sent verbatim, still carrying email: 'support@cboard.io' and author: 'Cboard Team' → server returns 500.
The rest of the app (CommunicatorDialog: copyBoard, setRootBoard, deleteMyBoard, board reorder) avoids this by calling verifyAndUpsertCommunicator before any communicator push, which forks the default communicator to one owned by the user (new shortid + user's email / author). The new sync engine path bypasses this step.
Expected behavior
The sync engine should follow the same invariant as the rest of the app: before pushing the active communicator to the API, ensure it has been forked from the default if it still belongs to support@cboard.io.
Description
After logging in with an account that has no communicator and no boards on the server, doing the first board sync with two or more local boards pending fails with
500 Internal Server ErroronPUT /communicator/:id.The first board push succeeds (POST
/communicator). The second board push then issues a PUT with a payload that still carries the default communicator fields (email: 'support@cboard.io',author: 'Cboard Team') instead of the user's data, which the server rejects.Steps to reproduce
getApiObjects→syncBoards→pushLocalChangesToApi)./communicatorreturns 200, second PUT/communicator/:idreturns 500.Root cause
pushLocalChangesToApiinsrc/components/Board/Board.actions.jscallsupdateApiObjectsNoChildfor each board needing creation. That helper ends withupsertApiCommunicator(comm):comm.id === 'cboard_default'→ goes throughcreateApiCommunicator(POST).api.jsstrips the id and overridesemail/authorwith the user's data, so the POST succeeds.CREATE_API_COMMUNICATOR_SUCCESSreducer only copiesidandlastEditedfrom the response, leavingemailandauthoras the default values locally.comm.idis now the Mongo id from the server → goes throughupdateApiCommunicator(PUT). The PUT body is sent verbatim, still carryingemail: 'support@cboard.io'andauthor: 'Cboard Team'→ server returns 500.The rest of the app (CommunicatorDialog:
copyBoard,setRootBoard,deleteMyBoard, board reorder) avoids this by callingverifyAndUpsertCommunicatorbefore any communicator push, which forks the default communicator to one owned by the user (new shortid + user's email / author). The new sync engine path bypasses this step.Expected behavior
The sync engine should follow the same invariant as the rest of the app: before pushing the active communicator to the API, ensure it has been forked from the default if it still belongs to
support@cboard.io.