decocms / decocms/studio

Migrate org-scoped backend routes to /:org URL prefix (follow-up to #3250)

Open
#3,256 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
407
Forks
57
Avg merge
5h 6m
Merged PRs (30d)
880

Description

Background

#3250 stopped persisting activeOrganizationId to the session row (it was leaking across browser tabs) and switched to a per-request x-org-id header. That fix works for normal MCP fetches via the SDK but exposed a class of bugs every time a callsite forgets the header:

  • The OAuth probe in isConnectionAuthenticated was a hand-rolled fetch without x-org-id → proxy returned 403, supportsOAuth came back false, and the OAuth popup never opened.
  • The save path POST /api/connections/:id/oauth-token had the same gap → token landed on connection.connection_token (fallback) instead of DownstreamTokenStorage, breaking buildCloneInfo ("No GitHub token found").
  • /api/vm-events and /org/:orgId/watch are SSE — EventSource can't set custom headers at all, so the header convention couldn't carry org context. We worked around it with a GET-only query-param fallback (?x-org-id=...).

Each of these was patched individually. The pattern is: the header convention is invisible from the URL, easy to forget, and structurally incompatible with EventSource.

Proposal

Move org context into the URL path for every org-scoped backend route, removing the need for the x-org-id header (and the SSE query-param workaround).

There's already precedent in the codebase:

  • /org/:organizationId/watch
  • /org/:organizationId/events/:type
  • /api/:org/models/*

After the migration:

  • /mcp/:connectionId/:org/mcp/:connectionId
  • /api/connections/:id/oauth-token/:org/api/connections/:id/oauth-token
  • /api/vm-events?.../:org/api/vm-events?... (no more x-org-id query param)
  • ...and the rest of the org-scoped surface for consistency.

authenticateRequest resolves the org from the path segment instead of the header; membership is verified the same way. Multi-tab safety comes from the URL itself — different tabs are different URLs.

Decisions to make

  1. Scope — narrow (just the routes that currently break or are fragile: proxy /mcp/*, /api/connections/:id/oauth-token*, the two SSE routes) or sweep (all org-scoped routes: /api/org-sso, /api/files, decopilot, KV, vm-events, etc.). Sweeping gives one consistent shape; narrow keeps the diff small.
  2. Slug vs id in the path — the frontend URL already uses the slug (/gimenes-local/...); reusing it reads nicer and matches what users see. authenticateRequest's membership query already supports either.
  3. Compatibility window — keep the old paths aliased and x-org-id header working during a deprecation window (matters for API-key consumers of /mcp/:connectionId and /api/connections/...)? Or hard cut?

Touched surface (rough)

Backend (Hono routes): apps/mesh/src/api/app.ts, apps/mesh/src/api/routes/proxy.ts, downstream-token.ts, vm-events.ts, plus the routes mounted under /api/....

SDK + frontend fetch helpers:

  • packages/mesh-sdk/src/hooks/use-mcp-client.ts — drop the x-org-id header, build org-scoped URL.
  • packages/mesh-sdk/src/lib/mcp-oauth.tsisConnectionAuthenticated and checkOAuthTokenStatus.
  • All oauth-token POST/DELETE callsites in apps/mesh/src/web/....
  • The three SSE consumers (vm-events-context.tsx, use-decopilot-events.ts, use-workflow-sse.ts).

Existing tests that assert the 403 cross-tenant guard (apps/mesh/src/api/routes/proxy.test.ts) need to be updated for the new path shape.

Out of scope

The interim fixes already in the codebase (per-callsite x-org-id headers, the GET-only query-param fallback in authenticateRequest) stay until this migration lands.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with apps/mesh/src/api/app.ts, apps/mesh/src/api/routes/proxy.ts, downstream-token.ts, vm-events.ts, and the listed SDK and SSE consumers. Review the existing proxy tests and decide the migration scope, path identifier, and compatibility window before tracing each org-scoped route. Done means the selected routes, clients, consumers, and cross-tenant tests consistently use the new URL shape without the header or SSE query-parameter workaround.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend, frontend
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.