Repository navigation
Renaming or deleting a category is all or nothing, and names the app uses are refused (#100, #117) - #253
Open
smilne3 wants to merge 6 commits into
Open
Renaming or deleting a category is all or nothing, and names the app uses are refused (#100, #117)#253smilne3 wants to merge 6 commits into
smilne3 wants to merge 6 commits into
Conversation
Migration 023 adds rename_category and delete_category. Each does a category's three writes in one transaction, so a failure partway can no longer leave picks under a name no category has. Both run as the signed-in person, so RLS still applies, and only authenticated may call them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With nothing to return, any reply without an error means the change was made, so an empty reply can't leave the outcome unknown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e app uses (#100, #117, #243, #246) The categories route now renames and deletes with one call each, to rename_category and delete_category, so all of a change lands or none of it does. A category that's gone answers 404, and a name another category has 409, both in words. Any other refusal is logged, never shown in the database's words. Uncategorized, Other and None, in any case, and the names every object inherits, are refused on add and rename. A test ties the list to the names the app produces. The invariants check no longer lets the categories route write picks. db/seeds/023_category_rename_delete_checks.sql finds anything earlier failures left behind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…e to 023's names (#100) - A write whose reply was lost is now logged, with its status, as every other write route logs before deciding what to answer. - delete_category stops the whole call if its delete matches nothing, so a policy that let the row be locked but not deleted can't clear the picks and budget of a category that stays. - An ended session says "Your session ended. Sign in again.", as every other route does, instead of "unauthorized". - Tests: the route's argument names and functions against 023's own, the row lock, the 400s for a missing id or name, and the checks query's name lists against the names the app refuses. - Comments: the old route's failures described as they were, and the checks query's advice on leftovers, which a rename now repairs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the test table (#100) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e top of the list (#100) On a phone the top of the list is a long scroll above the Add box, so on the owner's iPhone check a refused "Other" looked like nothing happened: each tap cleared the message and put it back off screen. CategoryManager keeps one message, and now renders it after the row or add box that sent the save. A row that's gone, deleted here or on the other phone, leaves its message in the row's place, so "Deleted …" shows where the row was. Tests pin each placement, and all 9 mutants of it are caught. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This fixes #100, #117, #243 and #246. Renaming or deleting a category can no longer be left half done, and Settings refuses category names the app already uses for something else. Its messages now show where you're looking, on a phone too.
Migration 023 must be run in Supabase's SQL editor before this merges. The new code calls the two database functions it adds, and can't rename or delete a category without them.
What changes for you
How
db/migrations/023_category_rename_delete.sqladdsrename_category(category_id, new_name)anddelete_category(category_id). Each does its three writes in one transaction.security invoker), so row-level security applies as it did when the route made the writes itself.anoncan't call them; signed-in people can.app/api/categories/route.ts. PATCH and DELETE make one.rpc()call each, and no longer read the category first. For all three writes:components/CategoryManager.tsxstill keeps one message, and now shows it under the row or add box that sent the save. Once that row is gone, deleted here or on the other phone, the message keeps the row's place.lib/category-names.tsholds the refused names and says what each is used for.tests/unit/category-names.test.tsties the list to the names the app actually produces: the bank fallback, the Trends fold and Jev's "none".scripts/check-invariants.mjsno longer lets the categories route writeuser_category. So the old three-request rename can't come back unnoticed.db/seeds/023_category_rename_delete_checks.sqlis one read-only query. It lists anything earlier failures left behind, and any category already using a refused name.Checked
auth.uid(). Nothing ran against the real database. 27 checks pass, each calling the functions by argument name, as PostgREST does:anoncan't call either function, and both run with an emptysearch_path.Left for later
Owner's steps
Closes #100. Closes #117. Closes #243. Closes #246.
🤖 Generated with Claude Code