fix(tasks): admins can fetch any task by id (unblocks customer-prompt-task)
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):
- The endpoint became auth-gated in #345 — the worker sent no key → 401. (Fixed in the sibling
tasksPR:fetchTasknow sendsx-api-key.) - Even with a valid key, the lookup is account-scoped.
validateGetTasksQueryresolvesaccount_idfrom the caller's key andselectScheduledActionsfilters byidANDaccount_id. The shared worker key won't own the customer's task → 0 rows. Chicken-and-egg: the worker would need the owner'saccount_idto pass it, but it's callingfetchTaskprecisely 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_idis now optional;selectScheduledActionsalready only filters byaccount_idwhen 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;checkIsAdminis 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 (checkIsAdminnot called on the id path). - GREEN: minimal branch added. Full
lib/taskssuite green (67 tests, incl. 7 here).tscadds 0 new errors (pre-existing test-mock noise onmainunchanged); 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_idoptional;selectScheduledActionsfilters 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.
- Update