Skip to content

feat(organizations): add organization slug URLs#4267

Closed
evanjacobson wants to merge 40 commits into
mainfrom
feat/org-slugs
Closed

feat(organizations): add organization slug URLs#4267
evanjacobson wants to merge 40 commits into
mainfrom
feat/org-slugs

Conversation

@evanjacobson

@evanjacobson evanjacobson commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Organization URLs were tied to opaque UUIDs, which made shared links hard to read and manage. This adds slug-backed organization URLs so organization pages can use human-readable identifiers while legacy UUID URLs continue to resolve and canonicalize safely.

The implementation follows the existing organization routing, page-context, and admin patterns: route identifiers are resolved at the boundary, downstream authorization/business logic still receives UUIDs, and migration cleanup is handled through admin tooling rather than ad hoc scripts.

Key details
  • Adds a persisted nullable organizations.slug with max-length and uniqueness constraints.
  • Adds shared route helpers so generated organization links prefer slug ?? id and server routes can resolve either slug or UUID.
  • Updates organization-scoped pages, sidebars, payment returns, integrations, Cloud/KiloClaw flows, and related UI links to use route identifiers where URLs are user-facing.
  • Keeps API/data contracts unchanged: organizationId and organization_id remain UUID contracts, and slug support is limited to route identifier boundaries.
  • Adds an admin backfill task at /admin/backfills that processes up to 1,000 legacy organizations per run and can be clicked repeatedly until no rows remain.
  • Includes an audit doc covering slug-aware route surfaces, UUID-only API contracts, compatible UUID links, and follow-up areas.

Verification

  • Manually tested and demoed the slug URL behavior shown in the Loom.

Visual Changes

N/A

Reviewer Notes

Please focus review on the route/API boundary: slugs should work as /organizations/:identifier aliases, but backend/API payloads named organizationId should continue to require UUIDs. Also review the backfill flow and any remaining UUID-generated links that are intentionally compatible through canonical redirects.

Comment thread apps/web/src/lib/cloud-agent-sdk/schemas.ts Outdated
Comment thread apps/web/src/components/cloud-agent-next/ChatSidebar.tsx Outdated
Comment thread apps/web/src/components/cloud-agent-next/NewSessionPanel.tsx Outdated
@kilo-code-bot

kilo-code-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The organizations.slug migration's CHECK constraint now correctly uses NOT VALID/VALIDATE CONSTRAINT staging, but the CREATE UNIQUE INDEX for the slug is still built synchronously without CONCURRENTLY, which will block writes to organizations during the index build.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/db/src/migrations/0178_mean_runaways.sql 2 CREATE UNIQUE INDEX for organizations.slug still lacks CONCURRENTLY, locking writes on organizations during index build (the CHECK constraint locking issue from the prior review is now fixed via NOT VALID/VALIDATE CONSTRAINT)

Previously Flagged Item Verified Resolved

  • apps/web/src/routers/organizations/organization-router.ts (updateSlug) — the mutation now wraps the slug update in try/catch and converts a 23505 unique-violation into a friendly CONFLICT ("Requested slug is not available") error, resolving the previously flagged TOCTOU race.
Files Reviewed (16 files changed since last review)
  • apps/storybook/stories/Sidebar.stories.tsx
  • apps/web/src/app/(app)/components/OrganizationAppSidebar.tsx
  • apps/web/src/app/(app)/organizations/[id]/cost-insights/activity/page.tsx
  • apps/web/src/app/(app)/organizations/[id]/cost-insights/ask-kilo/page.tsx
  • apps/web/src/app/(app)/organizations/[id]/cost-insights/config/page.tsx
  • apps/web/src/app/(app)/organizations/[id]/cost-insights/layout.tsx
  • apps/web/src/app/(app)/organizations/[id]/cost-insights/page.tsx
  • apps/web/src/app/(app)/organizations/[id]/cost-insights/settings/page.tsx
  • apps/web/src/lib/email.ts
  • apps/web/src/lib/organizations/organizations.test.ts
  • apps/web/src/lib/organizations/organizations.ts
  • apps/web/src/routers/organizations/organization-router.test.ts
  • apps/web/src/routers/organizations/organization-router.ts - 0 issues (previous TOCTOU issue resolved)
  • packages/db/src/migrations/0178_mean_runaways.sql - 1 issue
  • packages/db/src/migrations/0179_bumpy_justin_hammer.sql (unrelated cost-insights migration pulled in by rebase, no locking issues on new/empty tables)
  • packages/db/src/schema.ts
  • packages/db/src/migrations/meta/0179_snapshot.json (generated, skipped)
  • packages/db/src/migrations/meta/_journal.json (generated, skipped)

Fix these issues in Kilo Cloud

Previous Review Summaries (10 snapshots, latest commit 5fc40e4)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 5fc40e4)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

The new organizations.slug unique/check constraints are added via a locking ALTER TABLE without CONCURRENTLY/NOT VALID staging, and the updateSlug mutation has a TOCTOU race that can surface an unhandled DB error instead of a clean conflict response.

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/db/src/migrations/0178_mean_runaways.sql 2 Unique/CHECK constraints added without CONCURRENTLY/NOT VALID staging, locking organizations during index build and validation
apps/web/src/routers/organizations/organization-router.ts 562 updateSlug has a TOCTOU race on slug uniqueness; no handling for a concurrent 23505 unique-violation

Previously Flagged Items — Verified Resolved

All 6 previously open inline findings were re-verified against current HEAD and are now resolved in code (kept open on GitHub only because the threads weren't marked resolved):

  • apps/web/src/lib/cloud-agent-sdk/schemas.tsorganizationId is back to z.string().nullable(), matching the producer contract.
  • apps/web/src/components/cloud-agent-next/ChatSidebar.tsx — session navigation (basePath) is keyed off the stable organizationId, not the route slug.
  • apps/web/src/components/cloud-agent-next/NewSessionPanel.tsx — post-create redirect now uses the stable organizationId for getOrganizationAppPathForRouteIdentifier, not the route identifier.
  • apps/web/src/lib/integrations/oauth/common.ts — the catch block's error-path build uses the null-safe parsed organizationId, not the raw unparsed value.
  • apps/web/src/lib/integrations/oauth/platforms/gitlab-connect.tsbuildGitLabDetailCallbackPathForRequestedOrganization now wraps the parse in try/catch and falls back to the generic path.
  • apps/web/src/lib/organizations/organization-route-utils.tsSLUG_ROUTE_IDENTIFIER_PATTERN ({0,31}) already matches the persisted OrganizationSlugSchema character set in organization-router.ts; no rejection of valid persisted slugs.
Files Reviewed (29 files changed since last review)
  • apps/storybook/stories/OrganizationSwitcher.stories.tsx
  • apps/storybook/stories/Sidebar.stories.tsx
  • apps/web/src/app/(app)/components/AppSidebar.tsx
  • apps/web/src/app/(app)/components/OrganizationAppSidebar.tsx
  • apps/web/src/app/(app)/components/OrganizationSwitcher.tsx
  • apps/web/src/app/(app)/organizations/[id]/code-reviews/ReviewAgentPageClient.tsx
  • apps/web/src/app/(app)/organizations/[id]/code-reviews/page.tsx
  • apps/web/src/app/(app)/organizations/[id]/gastown/OrgTownListPageClient.tsx
  • apps/web/src/app/(app)/organizations/[id]/welcome/layout.tsx
  • apps/web/src/app/(app)/organizations/[id]/welcome/page.tsx
  • apps/web/src/app/admin/backfills/page.tsx
  • apps/web/src/app/api/organizations/[id]/models/route.test.ts
  • apps/web/src/app/api/organizations/[id]/models/route.ts
  • apps/web/src/app/api/organizations/hooks.ts
  • apps/web/src/components/cloud-agent-next/NewSessionPanel.tsx
  • apps/web/src/components/integrations/IntegrationDetailPage.tsx
  • apps/web/src/components/organizations/welcome/OrganizationSetupWizard.tsx
  • apps/web/src/components/organizations/welcome/organization-setup-path.ts
  • apps/web/src/components/usage-analytics/MetricDetailDrawer.tsx
  • apps/web/src/lib/bot/agent-runner.ts
  • apps/web/src/lib/organizations/organizations.test.ts
  • apps/web/src/lib/organizations/organizations.ts - 1 issue (carried into organization-router.ts)
  • apps/web/src/routers/organizations/organization-admin-router.test.ts
  • apps/web/src/routers/organizations/organization-admin-router.ts
  • apps/web/src/routers/organizations/organization-router.ts - 1 issue
  • packages/db/src/migrations/0178_mean_runaways.sql - 1 issue
  • packages/db/src/migrations/meta/0178_snapshot.json (generated, skipped)
  • packages/db/src/migrations/meta/_journal.json (generated, skipped)
  • packages/db/src/schema.ts

Fix these issues in Kilo Cloud

Previous review (commit 471efa3)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (4 files)
  • apps/web/src/app/api/integrations/gitlab/connect/route.test.ts
  • apps/web/src/lib/integrations/oauth/platforms/gitlab-connect.ts
  • apps/web/src/lib/organizations/organization-route-utils.test.ts
  • apps/web/src/lib/organizations/organization-route-utils.ts

Previous review (commit 8b1e34c)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/lib/integrations/oauth/platforms/gitlab-connect.ts 66 Unauthenticated legacy GitLab OAuth requests now preserve raw organizationId values in the sign-in callback path, which can strand users on an unresolved org route after login
apps/web/src/lib/organizations/organization-route-utils.ts 10 isValidOrganizationRouteIdentifier() now rejects trailing-hyphen slugs that the persisted organization slug schema still allows, causing org-scoped pages and APIs to 400 for those organizations

Fix these issues in Kilo Cloud

Files Reviewed (5 files)
  • apps/web/src/lib/integrations/oauth/platforms/gitlab-connect.ts - 1 issue
  • apps/web/src/lib/organizations/organization-auth.test.ts - 0 issues
  • apps/web/src/lib/organizations/organization-auth.ts - 0 issues
  • apps/web/src/lib/organizations/organization-route-utils.ts - 1 issue
  • apps/web/src/lib/user/server.ts - 0 issues

Previous review (commit 0b19c0f)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (1 files)
  • apps/web/src/lib/integrations/oauth/common.ts

Previous review (commit c4d933a)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (2 files)
  • apps/web/src/app/api/integrations/linear/connect/route.test.ts
  • apps/web/src/lib/integrations/oauth/common.ts

Previous review (commit 1b57afe)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/lib/integrations/oauth/common.ts 209 Invalid organizationId values now redirect to /organizations/<raw>/..., regressing the prior generic OAuth failure fallback

Fix these issues in Kilo Cloud

Files Reviewed (3 files)
  • apps/web/src/app/api/integrations/linear/connect/route.test.ts - 0 issues
  • apps/web/src/lib/email.ts - 0 issues
  • apps/web/src/lib/integrations/oauth/common.ts - 1 issue

Previous review (commit dbca7b2)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (3 files)
  • apps/storybook/src/mockData/organizations.ts
  • apps/storybook/stories/OrganizationSwitcher.stories.tsx
  • apps/storybook/stories/Sidebar.stories.tsx

Previous review (commit 389f44e)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (136 files)
  • apps/extension/**
  • apps/web/src/app/**
  • apps/web/src/components/**
  • apps/web/src/hooks/**
  • apps/web/src/lib/**
  • apps/web/src/routers/**
  • packages/db/**
  • docs/organization-slug-url-api-audit.md
  • pnpm-lock.yaml
  • pnpm-workspace.yaml

Previous review (commit 6553569)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (16 files)
  • apps/web/src/app/admin/components/OrganizationAdmin/OrganizationAdminDashboard.tsx
  • apps/web/src/app/admin/components/OrganizationAdmin/OrganizationAdminHierarchyManagement.tsx
  • apps/web/src/app/admin/components/OrganizationAdmin/OrganizationAdminWebhooks.tsx
  • apps/web/src/app/admin/components/OrganizationTableBody.tsx
  • apps/web/src/app/admin/organizations/[id]/page.tsx
  • apps/web/src/app/admin/organizations/[id]/webhooks/[triggerId]/page.tsx
  • apps/web/src/app/admin/organizations/[id]/webhooks/page.tsx
  • apps/web/src/app/admin/webhooks/AdminWebhookTriggerDetails.tsx
  • apps/web/src/components/admin-omnibox/AdminOmnibox.tsx
  • apps/web/src/components/cloud-agent-next/ChatSidebar.tsx
  • apps/web/src/components/cloud-agent-next/NewSessionPanel.tsx
  • apps/web/src/components/organizations/OrganizationInfoCard.tsx
  • apps/web/src/lib/cloud-agent-sdk/schemas.test.ts
  • apps/web/src/lib/cloud-agent-sdk/schemas.ts
  • apps/web/src/routers/organizations/organization-admin-router.test.ts
  • apps/web/src/routers/organizations/organization-admin-router.ts

Previous review (commit 697bc03)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/lib/cloud-agent-sdk/schemas.ts 161 Tightened session event schema now disagrees with the current producer contract and can silently drop events
apps/web/src/components/cloud-agent-next/ChatSidebar.tsx 360 Sidebar navigation keeps a stale slug path after organization slug edits
apps/web/src/components/cloud-agent-next/NewSessionPanel.tsx 911 Session creation redirect can target an outdated slug path

Fix these issues in Kilo Cloud

Files Reviewed (148 files)
  • apps/web/src/lib/cloud-agent-sdk/schemas.ts - 1 issue
  • apps/web/src/components/cloud-agent-next/ChatSidebar.tsx - 1 issue
  • apps/web/src/components/cloud-agent-next/NewSessionPanel.tsx - 1 issue
  • 145 additional changed files reviewed with no findings

Reviewed by claude-sonnet-5-20260630 · Input: 100 · Output: 38.1K · Cached: 7.1M

Review guidance: REVIEW.md from base branch main

…r the post-create router.push, so an open tab could redirect to a stale slug after organization slug changes.

Fixed apps/web/src/components/cloud-agent-next/NewSessionPanel.tsx:911 to build the post-create redirect from stable organizationId.
…ionId: z.string().nullable(), while web had narrowed it to UUID and skips failed parses.

Changed:
- apps/web/src/lib/cloud-agent-sdk/schemas.ts:161 restores sessionEventV2RowSchema.organizationId to z.string().nullable().
- apps/web/src/lib/cloud-agent-sdk/schemas.ts:202 restores sessionDeletedPayloadSchema.organizationId to z.string().nullable().
- apps/web/src/lib/cloud-agent-sdk/schemas.test.ts:21 adds regression coverage for non-UUID org IDs in session.created.
- apps/web/src/lib/cloud-agent-sdk/schemas.test.ts:30 adds regression coverage for non-UUID org IDs in session.deleted.
Comment thread apps/web/src/lib/integrations/oauth/common.ts Outdated
Comment thread apps/web/src/lib/integrations/oauth/platforms/gitlab-connect.ts Outdated
Comment thread apps/web/src/lib/organizations/organization-route-utils.ts Outdated
Comment thread packages/db/src/migrations/0178_mean_runaways.sql Outdated
Comment thread apps/web/src/routers/organizations/organization-router.ts Outdated
- packages/db/src/migrations/0178_mean_runaways.sql: replaced ADD CONSTRAINT ... UNIQUE with Drizzle-compatible CREATE UNIQUE INDEX.
- packages/db/src/migrations/0178_mean_runaways.sql: added the check constraint as NOT VALID, then VALIDATE CONSTRAINT.
- packages/db/src/schema.ts: changed slug: text().unique() to slug: text() plus explicit uniqueIndex('organizations_slug_unique').on(table.slug) so future Drizzle diffs preserve the index form.
Changed apps/web/src/routers/organizations/organization-router.ts to:
- Remove the pre-update slug availability assertion from updateSlug.
- Treat the DB unique constraint as the authoritative concurrency guard.
- Catch Drizzle/Postgres 23505 errors, including wrapped cause errors.
- Convert those errors into the existing friendly TRPCError CONFLICT with Requested slug is not available.
Comment thread packages/db/src/migrations/0178_mean_runaways.sql
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants