Skip to content

Worker dashboard URLs are workspace-implicit: /app/workers/{id} carries no workspace, and worker_id is not globally unique #2078

Description

@federicodeponte

Problem

The canonical worker detail route is /app/workers/[id]params: { id } only, no workspace (or user) in the URL (engine/apps/web/app/workers/[id]/page.tsx).

The workspace is resolved at request time from get_active_workspace_id() (a session/context var set from the active workspace cookie/header), NOT from the URL. And worker_id is not globally unique — it is scoped by workspace (workspace_id_for_worker(worker_id); every Supabase query does .eq("workspace_id", ...); the run recipe lookup is keyed by (worker_id, user_id, workspace_id)).

Consequences:

  • Opening /app/workers/{id} with a different workspace active resolves to the wrong workspace's worker or 404s.
  • The same worker_id can exist in multiple workspaces → the bare link is ambiguous.
  • Links are not portable/shareable across sessions; they only work because the recipient's session happens to default to the right workspace.

This is the same defect class as the run-proxy silent-403 just fixed in #2075 (worker config resolved by worker_id without workspace scope). The routing layer has the same worker_id == globally-unique assumption.

Proper fix

Worker URLs must be workspace-deterministic. Options:

  • Path-scoped: /app/w/{workspace_id}/workers/{worker_id} (preferred), or
  • Query-scoped: /app/workers/{id}?ws={workspace_id}, or
  • Globally-unique opaque worker ids.

Requirements: keep back-compat (old /app/workers/{id} must still resolve — look up the worker's workspace for the authenticated user, redirect + pin the active workspace; handle the not-a-member / ambiguous cases), update all internal navigation links to the scoped URL, and have the API/active-workspace resolution prefer the URL's workspace when present.

Repo note: dashboard UI lives in the engine (engine/apps/web), so the fix is an engine change here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions