fix(rename): surface duplicate-slug 409 instead of 500 (v1.21.1)
Some checks failed
CI / Lint (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled

mesh.slug actually carries a UNIQUE constraint (mesh_slug_unique)
even though the schema comment claimed otherwise. Trying to rename
to a slug another mesh already owns blew up as a generic 500.
Now: caught at the route, surfaced as 409 with body
{"error":"slug \"<x>\" is already taken"}; CLI maps it to
EXIT.ALREADY_EXISTS and prints the message.

Schema comment corrected to match DB reality.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-05-03 15:49:28 +01:00
parent 5785454ac9
commit 65e63b0b27
4 changed files with 31 additions and 13 deletions

View File

@@ -78,12 +78,14 @@ export const mesh = meshSchema.table("mesh", {
id: text().primaryKey().notNull().$defaultFn(generateId),
name: text().notNull(),
/**
* Cosmetic slug derived from name at creation. NOT unique, NOT used for
* identity — `mesh.id` is the canonical identifier everywhere (URLs,
* invites, broker lookups). Kept for display/debugging only. Two meshes
* can freely share a slug.
* URL-safe identifier — globally unique across all meshes (constraint
* `mesh_slug_unique` on the DB). `mesh.id` (UUID) remains the canonical
* primary key for FKs and broker routing, but slug is the identifier
* users see and type (CLI picker, --mesh flag, dashboard sidebar).
* v0.7.0 collapsed this with mesh.name; both columns now hold the
* same value, and a follow-up migration drops mesh.name.
*/
slug: text().notNull(),
slug: text().notNull().unique(),
ownerUserId: text()
.references(() => user.id, { onDelete: "cascade", onUpdate: "cascade" })
.notNull(),