Skip to content

#393 Share The Remaining Authorization Scope Copies In Application Actions - #523

Merged
b-at-neu merged 1 commit into
devfrom
393-share-remaining-authorization-scope-copies
Aug 20, 2026
Merged

#393 Share The Remaining Authorization Scope Copies In Application Actions#523
b-at-neu merged 1 commit into
devfrom
393-share-remaining-authorization-scope-copies

Conversation

@b-at-neu

Copy link
Copy Markdown
Collaborator

Closes #393

Summary

  • Consolidates the two hand-rolled manager-scoping clauses in prisma/actions/applications.ts into a shared lib/auth/scopes.ts, alongside the file-private buildBaseWhere that used to live in prisma/data/applications.ts.
  • Expresses the draft vs withdrawn distinction as a 'listable' | 'reviewable' argument on the shared builder, instead of each caller patching a post-spread status: { notIn: [...] }.
  • Replaces the as casts on /applications search params with a zod schema.

Changes

  • lib/auth/scopes.ts (new) — buildReviewablePositionWhere, buildApplicationScopeWhere (typed Omit<Prisma.ApplicationWhereInput, 'status'> so a caller's status filter can never overwrite the manager scoping), and buildApplicationWhere(user, 'listable' | 'reviewable').
  • prisma/data/applications.ts — dropped buildBaseWhere and the two post-spread withdrawn patches; getApplicationForReview, getApplications, getApplicationsTotal use buildApplicationWhere(user, 'listable'); getApplicationStatusCounts, getRecentApplications use buildApplicationWhere(reviewer, 'reviewable'); getReviewablePositions uses buildReviewablePositionWhere.
  • prisma/actions/applications.tsupdateApplicationStatus / updateApplicationStatuses lose their admin/manager ternaries and the "Merge, don't overwrite" comments in favor of the shared builders; dropped the now-unused PUBLISHED_POSITION_WHERE / NON_REVIEWABLE_APPLICATION_STATUSES imports.
  • lib/constants.ts / lib/types.ts — added APPLICATION_SORT_FIELDS / APPLICATION_SORT_DIRECTIONS as the single source for the sort unions and the page's zod enums.
  • app/(main)/(auth)/applications/page.tsx — a searchParamsSchema (zod) replaces the as casts, the typeof === 'string' checks, and the VALID_SORT_* arrays; every field is .optional().catch(undefined) so an unparseable or repeated (string[]) value is dropped without discarding the rest or throwing during render.
  • tests/db/authorization.test.ts — new coverage for the action-side position scoping (draft/soft-deleted position, withdrawn application) and the listable/reviewable split on the data side.

No behavior change: the scoping semantics, the two actions' { error } copy, and the page's happy-path rendering are identical to before.

Testing plan

  • As a manager of one position: /applications lists only that position's applications, withdrawn included, drafts excluded; the position filter offers only your positions.
  • Same manager: open an application detail page, move it through two statuses — success toasts, badge updates, dashboard counts move.
  • Same manager: bulk-select rows and apply a status — updated/skipped counts read as before.
  • Same manager: paste the id of an application on another manager's position into /applications/<id> → 404 page.
  • Same manager: attempt updateApplicationStatus/updateApplicationStatuses on an application belonging to a position they don't manage, or one that's on a draft/soft-deleted position, or one that's withdrawn → denied (throw / skipped, not a data leak).
  • As an admin: the list shows both managers' applications; dashboard pipeline counts and recent activity exclude withdrawn rows.
  • URL hardening on /applications: ?status=bogus, ?sort=bogus, ?sort=name:sideways, ?status=applied&status=reviewing (repeated param), ?q= (empty), a 5,000-character q — each loads the page with the bad filter ignored and the good ones applied; no error page.
  • ?sort=name:asc, ?status=reviewing, ?positionId=<id>, ?userId=<id> still work, including the per-user deep link from the users table.
  • npm run test (unit + db) green.

Automated checks

  • npm run prettier:check — pass
  • npm run eslint:check — pass
  • npm run tsc:check — pass

Notes

  • The third manager clause in prisma/actions/question-files.ts (getQuestionFileUrl) is deliberately left alone — it's owner-or-manager and intentionally reaches drafts/draft positions, so folding it into the reviewer scope would be a behavior change, not this ticket.
  • getManagedPositions / isManager also stay as-is — management surfaces include draft positions, a different predicate despite the resemblance.
  • The ENGINEERING.md §3 capability-matrix row naming the shared builder is left to a main-session PR, since .claude/ isn't writable by pipeline agents.

buildApplicationWhere/buildApplicationScopeWhere/buildReviewablePositionWhere
replace the file-private buildBaseWhere and the two hand-rolled manager
clauses in actions/applications.ts; the 'listable' | 'reviewable' argument
replaces the per-caller withdrawn patches, and the omitted status key on
the scope builder makes overwriting the manager scope a type error rather
than a "merge, don't overwrite" comment. /applications search params are
now zod-parsed instead of cast.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@b-at-neu b-at-neu added the claude Will be worked on by Claude label Aug 19, 2026
@b-at-neu b-at-neu self-assigned this Aug 19, 2026
@vercel

vercel Bot commented Aug 19, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
aplio Ready Ready Preview Aug 19, 2026 11:21pm

@b-at-neu b-at-neu added ready for review PR ready for review agent reviewing Review agent working (in-flight) and removed ready for review PR ready for review agent reviewing Review agent working (in-flight) labels Aug 19, 2026

@b-at-neu b-at-neu left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Code Review — Cycle 1 · approved

0 open

@b-at-neu b-at-neu added approved Review passed, ready to merge and removed reviewing Review agent working (in-flight) labels Aug 20, 2026
@b-at-neu
b-at-neu merged commit 3f80e7c into dev Aug 20, 2026
14 of 23 checks passed
@b-at-neu
b-at-neu deleted the 393-share-remaining-authorization-scope-copies branch August 20, 2026 02:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Review passed, ready to merge claude Will be worked on by Claude

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Share the Remaining Authorization Scope Copies in Application Actions

1 participant