fix(tasks): admins can fetch any task by id (unblocks customer-prompt-task)

Merged
SW
4mo ago
+48-3

Problem

customer-prompt-task (Trigger.dev worker) calls GET /api/tasks?id=<externalId> to load a customer's scheduled task config. Two things broke it (recoupable/chat#1810):

  1. The endpoint became auth-gated in #345 — the worker sent no key → 401. (Fixed in the sibling tasks PR: fetchTask now sends x-api-key.)
  2. Even with a valid key, the lookup is account-scoped. validateGetTasksQuery resolves account_id from the caller's key and selectScheduledActions filters by id AND account_id. The shared worker key won't own the customer's task → 0 rows. Chicken-and-egg: the worker would need the owner's account_id to pass it, but it's calling fetchTask precisely to learn that.

This PR fixes (2).

Change

In validateGetTasksQuery, when an admin caller queries by id alone (no account_id param), drop account scoping so the single task is returned regardless of owner. Reuses the existing checkIsAdmin (Recoup-org membership) machinery already used for account_id overrides.

  • ValidatedGetTasksQuery.account_id is now optional; selectScheduledActions already only filters by account_id when present, so omitting it yields an id-only lookup.
  • Non-admin id lookups stay scoped to the authenticated account — no cross-account leak.
  • List queries (no id) are unchanged; checkIsAdmin is only called on the id-lookup / override paths.

TDD

  • RED: two new tests — admin id-lookup should drop account_id; non-admin id-lookup should stay scoped. Both failed (checkIsAdmin not called on the id path).
  • GREEN: minimal branch added. Full lib/tasks suite green (67 tests, incl. 7 here). tsc adds 0 new errors (pre-existing test-mock noise on main unchanged); eslint clean.

Merge order

Docs first: recoupable/docs#245 documents the auth + 401/403/500 + the admin-id behavior. Then this PR. Then the tasks worker PR + a prod deploy with an admin-scoped RECOUP_API_KEY.

Verification

Preview verification (admin key cross-account lookup, 401 without key, non-admin scoping) posted as a follow-up comment.

Fixes part of recoupable/chat#1810.

🤖 Generated with Claude Code


Summary by cubic

Admins can now fetch any task by id without providing account_id, unblocking the customer-prompt-task worker. Non-admin id lookups remain scoped to the caller’s account.

  • Bug Fixes
    • Update validateGetTasksQuery: for admin + id-only requests, drop account scoping; otherwise keep it.
    • Make ValidatedGetTasksQuery.account_id optional; selectScheduledActions filters by it only when present.
    • Add tests for admin cross-account id lookup and non-admin scoping.
    • No changes to list queries or override rules.