Skip to content

Comments

feat: refactor GET /api/organizations to use auth-derived accountId#216

Merged
sweetmantech merged 1 commit intotestfrom
sweetmantech/myc-4209-api-get-apiorganizations-update-account_id-similar-to
Feb 10, 2026
Merged

feat: refactor GET /api/organizations to use auth-derived accountId#216
sweetmantech merged 1 commit intotestfrom
sweetmantech/myc-4209-api-get-apiorganizations-update-account_id-similar-to

Conversation

@sweetmantech
Copy link
Contributor

@sweetmantech sweetmantech commented Feb 10, 2026

Summary

  • Refactor GET /api/organizations to use validateAuthContext + buildGetOrganizationsParams pattern (matching pulses, chats, sandboxes)
  • Account ID is now derived from API key authentication instead of requiring a mandatory query parameter
  • Rename parameter from accountId to account_id (snake_case consistency)
  • account_id is now optional — only used by org keys to filter to a specific member

Changes

Action File
NEW lib/organizations/buildGetOrganizationsParams.ts
NEW lib/organizations/__tests__/buildGetOrganizationsParams.test.ts (7 tests)
NEW lib/organizations/validateGetOrganizationsRequest.ts
MODIFY lib/organizations/getOrganizationsHandler.ts
MODIFY app/api/organizations/route.ts (JSDoc only)
DELETE lib/organizations/validateOrganizationsQuery.ts

Test plan

  • 7 unit tests pass for buildGetOrganizationsParams
  • recoup orgs list CLI works without code changes (derives account from API key)
  • curl -H "x-api-key: $KEY" .../api/organizations returns orgs for authenticated account
  • curl .../api/organizations returns 401 (was previously 400 for missing accountId)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation

    • Updated GET /api/organizations API documentation with authentication requirements (x-api-key or bearer token).
    • Changed query parameter from accountId (required) to account_id (optional) for filtering.
    • Clarified endpoint behavior varies by key type (personal, organization, or Recoup admin).
  • Refactor

    • Refactored internal request validation and parameter handling logic.

Replace unauthenticated accountId query param with auth-derived account
using validateAuthContext + buildGetOrganizationsParams pattern.

- Add buildGetOrganizationsParams with access control (canAccessAccount)
- Add validateGetOrganizationsRequest (auth + Zod query validation)
- Update getOrganizationsHandler to use new validation pipeline
- Add 7 unit tests for buildGetOrganizationsParams
- Delete replaced validateOrganizationsQuery.ts
- Rename param from accountId to account_id (snake_case)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vercel
Copy link
Contributor

vercel bot commented Feb 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
recoup-api Ready Ready Preview Feb 10, 2026 8:07pm

Request Review

@coderabbitai
Copy link

coderabbitai bot commented Feb 10, 2026

📝 Walkthrough

Walkthrough

The changes refactor the GET /api/organizations endpoint to improve separation of concerns: API documentation clarifies authentication requirements and account filtering behavior, while three new/modified modules centralize request validation and parameter construction based on API key type and access permissions.

Changes

Cohort / File(s) Summary
API Documentation
app/api/organizations/route.ts
Updated GET endpoint documentation to specify authentication requirements (x-api-key or Authorization header), clarify behavior for different key types (personal, organization, Recoup admin), and change query parameter from required accountId to optional account_id. Minor formatting adjustments included.
Validation & Parameter Building
lib/organizations/buildGetOrganizationsParams.ts, lib/organizations/validateGetOrganizationsRequest.ts
Introduced new validation layer that centralizes request handling for GET /api/organizations. validateGetOrganizationsRequest parses and validates the account_id query parameter (UUID schema), authenticates via existing auth utilities, then delegates to buildGetOrganizationsParams to construct appropriate database query parameters based on key type (personal/org/admin) and optional target account filtering with access verification.
Handler Refactoring & Deprecation
lib/organizations/getOrganizationsHandler.ts, lib/organizations/validateOrganizationsQuery.ts
Refactored handler to use new centralized validateGetOrganizationsRequest validator instead of direct query parsing; removed deprecated validateOrganizationsQuery function and related exports (organizationsQuerySchema, OrganizationsQuery type). Maintains existing response structure and error handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

APIs grow stronger when concerns align,
Validation layers, parameter designs all shine,
Access checks guard the organizational door,
Clean separation—architecture we adore! ✨

🚥 Pre-merge checks | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Solid & Clean Code ⚠️ Warning PR violates DRY principle with identical code patterns across buildGet*Params files and uses inconsistent naming conventions compared to existing similar functions. Extract common buildGet*Params logic into generic utility with strategy parameters; standardize naming conventions; fix type narrowing issues in discriminated unions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sweetmantech/myc-4209-api-get-apiorganizations-update-account_id-similar-to

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@lib/organizations/validateGetOrganizationsRequest.ts`:
- Around line 59-75: The discriminated-union narrowing is lost by destructuring
{ params, error } from buildGetOrganizationsParams; instead keep the result as a
single variable (e.g., result = await buildGetOrganizationsParams(...)), check
result.error and return the NextResponse when present, and only then return
result.params (which TS will correctly narrow to GetAccountOrganizationsParams).
Update the code paths around buildGetOrganizationsParams, error, and params to
use the single result object so the function's declared return type
Promise<NextResponse | GetAccountOrganizationsParams> is satisfied.
🧹 Nitpick comments (1)
lib/organizations/validateGetOrganizationsRequest.ts (1)

9-11: Consider exporting the inferred query schema type.

The coding guidelines for validate*.ts files state: "Export inferred types for validated data." You could export the inferred type from getOrganizationsQuerySchema for reuse.

export type GetOrganizationsQuery = z.infer<typeof getOrganizationsQuerySchema>;

As per coding guidelines, lib/**/validate*.ts: "Export inferred types for validated data."

Comment on lines +59 to +75
const { params, error } = await buildGetOrganizationsParams({
accountId,
orgId,
targetAccountId,
});

if (error) {
return NextResponse.json(
{
status: "error",
error,
},
{ status: 403, headers: getCorsHeaders() },
);
}

return params;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

TypeScript narrowing lost after destructuring the discriminated union.

After destructuring { params, error }, TypeScript can no longer correlate the two fields. Even though the if (error) guard on Line 65 returns early, params remains typed as GetAccountOrganizationsParams | null — so Line 75 could return null, which doesn't satisfy the declared return type Promise<NextResponse | GetAccountOrganizationsParams>.

Avoid destructuring the result to preserve the discriminated union narrowing:

🛡️ Proposed fix
-  const { params, error } = await buildGetOrganizationsParams({
+  const result = await buildGetOrganizationsParams({
     accountId,
     orgId,
     targetAccountId,
   });
 
-  if (error) {
+  if (result.error) {
     return NextResponse.json(
       {
         status: "error",
-        error,
+        error: result.error,
       },
       { status: 403, headers: getCorsHeaders() },
     );
   }
 
-  return params;
+  return result.params;
🤖 Prompt for AI Agents
In `@lib/organizations/validateGetOrganizationsRequest.ts` around lines 59 - 75,
The discriminated-union narrowing is lost by destructuring { params, error }
from buildGetOrganizationsParams; instead keep the result as a single variable
(e.g., result = await buildGetOrganizationsParams(...)), check result.error and
return the NextResponse when present, and only then return result.params (which
TS will correctly narrow to GetAccountOrganizationsParams). Update the code
paths around buildGetOrganizationsParams, error, and params to use the single
result object so the function's declared return type Promise<NextResponse |
GetAccountOrganizationsParams> is satisfied.

@sweetmantech sweetmantech merged commit e1061b7 into test Feb 10, 2026
3 checks passed
sweetmantech added a commit that referenced this pull request Feb 10, 2026
…216)

Replace unauthenticated accountId query param with auth-derived account
using validateAuthContext + buildGetOrganizationsParams pattern.

- Add buildGetOrganizationsParams with access control (canAccessAccount)
- Add validateGetOrganizationsRequest (auth + Zod query validation)
- Update getOrganizationsHandler to use new validation pipeline
- Add 7 unit tests for buildGetOrganizationsParams
- Delete replaced validateOrganizationsQuery.ts
- Rename param from accountId to account_id (snake_case)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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.

1 participant