Flow
What my chore save is missing
1One-item commands
Add and delete one chore at a time, with the server picking ids.
2No blind replace
Drop the replace-everything path, or make it name the version it started from.
3A lock
Hold one lock around the read and the write.
4Temp file, then rename
Never leave a half-written file where a reader can find it.
5Honest loading
Block saving after a failed load instead of starting from an empty list.
6Read the answer
Keep an edit unsaved until the server says yes.
In one day, the chore list in my staff-scheduling app went from a few chores written into the JavaScript to a file on the server. Reading those commits back, one branch bothers me most. If the browser sends a list, the server throws out what it has and saves that list instead. It checks nothing first.
From one item to everything
The first version only handled one chore at a time. It checked the token, took a chore with an id, updated it or added it, and saved the file. Delete removed one chore by id.
Then the browser started sending the whole chore list on every add and every delete. That came with the change that moved chore loading onto the API. Later, when I added assignees and due dates, the server learned a second meaning for the same request. Send one object and it updates one chore. Send a list and it replaces everything.
If the body is a list, it replaces everything.
That one line is the most dangerous thing the endpoint can do, and it has the fewest guards.
Five ways the list can get eaten
Nothing checks the items in the list. The token only says who is allowed to call.
Nothing stops two saves from running at once. The readme lists a queue file used for locking when saving, but the chore code doesn't touch it. Two saves that overlap end with whoever lands last. The browser also makes new ids by adding one to the biggest id it has, so two open tabs could pick the same one.
The browser's error handling is the one that worries me. If loading the chores fails, the page just starts with an empty list and says nothing. The next add sends a one-item list, and the server makes that the whole list. As far as I can read the code, one bad page load and one click wipe the file. I haven't seen that happen. I haven't looked, either. There's a rarer version I can only guess at. The server writes over the file in place, and if a read hits a half-written file, it gets treated as empty too.
The save never checks the answer. A rejected save looks just like a good one.
And I suspect the list check needs a newer PHP than I assumed. On an older server, that branch would break before it checked anything.
Two startup rewrites in one day
Two commits that day both changed how the page starts. One loads staff, schedule and chores together, waits for all of them, picks today's date, then draws. The other loads them one after another. Before that, the page could pick a date before the chores had loaded. I like the version that waits for everything. But neither one fixes the empty-list problem, because waiting doesn't tell "no chores" apart from "couldn't load chores."
The shape I want instead
If you're building something like this, these are the parts I'd want in place:
- Separate commands for adding and deleting one item, with the server picking the ids.
- No full replace, or one that must say which version it started from.
- A lock around the read and the write.
- Write to a temp file, then rename it over the real one.
- A browser that blocks saving after a failed load and keeps edits until the server says yes.
I'll probably just delete the replace branch, since every caller I can find only adds or removes one chore.
Before I touch anything, I want to know which PHP that server actually runs.