Repository navigation
fix: make node slugs unique per user - #84
Merged
Merged
Conversation
Node slugs were globally unique, so two users couldn't both name a node "hermes". They're display-only (generated from the name), so scope them per user like routes. Migration 0003 also re-asserts the routes change from 0002, whose snapshot never recorded it (drizzle-kit regenerated it) and which production had drifted away from until 2026-09-22. Each per-user index is created before the global one is dropped, and every statement uses IF [NOT] EXISTS, so it's safe wherever part of it already applied. A schema test pins both unique indexes to (user_id, slug).
Strix Security ReviewNo security issues found. Review summaryReviewed the schema, migration, journal, generated snapshot, and new test introduced by this PR. The change relaxes node-slug uniqueness from global (slug) to per-user (user_id, slug), matching the existing routes behavior. Tracing slug usage across the codebase confirms it is display-only and never used as an access-control or lookup key: node authentication uses token hashes, node retrieval uses IDs, and webhook dispatch scopes routes by (userId, routeSlug). The migration is idempotent and ordered so uniqueness is preserved at every step. No security issues were identified in the changed code. Updated for Reviewed by Strix |
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.
Why
Node slugs were globally unique (
nodes_slug_key), so two users couldn't both name a nodehermes. Slugs are display-only (generated from the node name), so they're now unique per user, matching routes.Changes
db/schema.ts:nodes_slug_keybecomesnodes_user_id_slug_keyon(user_id, slug).0003:IF [NOT] EXISTSeverywhere, so it's safe on any database where part of it already applied.routeschange from0002. That migration's snapshot never recorded its own change (drizzle-kit generateregenerated it), and production had drifted back to the global route index until today, when I fixed it by hand.tests/db/schema-unique-indexes.test.tspins both unique indexes to(user_id, slug). It was written first: the nodes case failed, and the routes case passed because only production had drifted.Production
The migrations workflow is disabled, so after merge this is applied by hand: rehearsed on a Neon branch, then applied in one transaction that also records it in
drizzle.__drizzle_migrations(file SHA-256 + journalwhen), asdrizzle-kit migratewould.yarn vitest run: 247/247. Lint clean.