Skip to content

#616 Show Managers Who Has A Draft Application, Without Exposing Answers - #674

Open
b-at-neu wants to merge 3 commits into
devfrom
616-show-managers-drafts-without-answers
Open

#616 Show Managers Who Has A Draft Application, Without Exposing Answers#674
b-at-neu wants to merge 3 commits into
devfrom
616-show-managers-drafts-without-answers

Conversation

@b-at-neu

@b-at-neu b-at-neu commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Closes #616

Summary

  • A manager or admin can now see how many people have a draft application for their position, and who they are — via a purpose-built read path (getDraftApplications/getDraftApplicationsCount) that selects only identity and timestamps, never answers or files.
  • buildApplicationWhere, getApplicationForReview, and REVIEWER_APPLICATION_STATUSES are all deliberately untouched — /manage/applications/[id] still 404s for a draft, for managers and admins alike.
  • Drafts stay out of the default queue (decision (a) from the plan): a status filter (Draft) swaps the results region for an inert, identity-only table, and a "N applications in progress" strip under the page header keeps the count visible without filtering.

Changes

  • prisma/data/applications.tsgetDraftApplications/getDraftApplicationsCount plus private buildDraftListWhere/buildDraftListOrderBy; buildApplicationListWhere guarded so a draft status filter can never overwrite listable's own status: { not: 'draft' }.
  • lib/types.tsDraftApplicationListItem (no status, no applicantName, no answer relations) and ApplicationStatusFilter; widened ApplicationFilters['status']. Removed the now-dead ReviewerStatus alias.
  • lib/constants.ts — comment-only change: APPLICATION_STATUS_VALUES/APPLICATION_STATUS_OPTIONS documented as the queue's filter list (draft in, withdrawn out); REVIEWER_APPLICATION_STATUSES/_OPTIONS untouched.
  • lib/utils.ts — extracted buildApplicationsHref(filters, page?) from applications-pagination.tsx, now shared by pagination and the count strip's link.
  • app/(main)/(auth)/manage/applications/page.tsx — widened the status searchParam enum, fetches the draft count alongside positions/applicants, branches the results region on filters.status === 'draft'.
  • components/features/draft-applications-results.tsx (new, server) — draft rows + count, pagination, page clamping, privacy line.
  • components/features/draft-applications-table.tsx (new, client) — DataTable with no checkbox column, no row links, no status actions.
  • components/features/drafts-in-progress-notice.tsx (new, server) — the count strip.
  • components/features/applications-pagination.tsxnoun prop (default 'application') so the drafts view reads "… drafts".
  • components/features/applications-toolbar.tsx — status Select now maps APPLICATION_STATUS_OPTIONS (includes Draft); the bulk bar and status dialog keep the reviewer-only list since those are write paths.
  • components/features/applications-table-skeleton.tsxshowSelection prop so the drafts skeleton renders no checkbox column.
  • prisma/actions/applications.tsrevalidatePath('/manage/applications') added to createDraftApplication's success paths and deleteDraftApplication.
  • docs/PERMISSIONS.md — the draft row's reviewer-visibility cell replaced ("identity only … never answers, files or the detail page"); a new bullet records the split as deliberate policy.
  • docs/WORKFLOWS.md — PM-8 updated (drafts filter, strip, inert rows) and corrected "scoped by reviewable" → listable, matching the actual query. AP-5 is untouched — applicants are not notified.
  • Tests: new tests/db/draft-visibility.test.ts; extended tests/db/authorization.test.ts, tests/unit/constants.test.ts, tests/unit/utils.test.ts.

Testing plan

  • As a manager of one position: start drafts as two applicants on that position and one on a position you don't manage. /manage/applications shows "2 applications in progress" and none of the drafts in the default queue.
  • Click View drafts — both your drafts appear with name, email, started and last-updated dates; the third does not.
  • Confirm a draft row is inert: no checkbox, no , applicant name is not a link, and the bulk bar never appears.
  • Copy a draft's id and open /manage/applications/<id> — 404, as a manager and as an admin.
  • As an admin: the drafts view lists drafts across all published positions.
  • Edit a draft's answers as the applicant, reload the drafts view — Last updated moves, no answer text appears anywhere.
  • Delete the draft as the applicant — it leaves the drafts view and the count on reload; submit another — it leaves the drafts view and appears in the normal queue.
  • Filter by position, then by Draft: the strip's count and the drafts list both respect the position filter; Clear filters returns to the unfiltered queue.
  • Sort the drafts table by Applicant and by Last updated, both directions.
  • A draft whose applicant has no name shows their email in the Applicant cell.
  • As an applicant, start an application and walk the apply flow: the copy is identical to before this change — no mention of manager visibility anywhere.
  • 375px / 768px / 1280px: mobile cards show name, email, position and both dates with no action affordances; the toolbar and strip stack correctly.
  • A manager who does not manage any of the drafting applicants' positions sees "No drafts in progress" (empty state), and the strip is hidden.
  • Filtering the drafts view down to zero rows shows "No drafts match these filters" with a working Clear filters back to the unfiltered drafts view.

Automated checks

  • npm run prettier:check — pass
  • npm run eslint:check — pass
  • npm run tsc:check — pass
  • npm run test:unit — 316/316 pass (one pre-existing, unrelated failure in tests/unit/email-delivery-events.test.ts due to a missing DATABASE_URL at module scope — not caused by this change)
  • npm run test (db project) — could not run in this sandbox: local Postgres port 5432 is already bound by an unrelated container and npm run db:start fails to bind. Per CLAUDE.md's documented fallback ("fall back to test:unit if Postgres is unavailable"), the new/extended DB tests (tests/db/draft-visibility.test.ts, tests/db/authorization.test.ts additions) are unverified against a live database here, though they type-check and follow the exact fixture/scoping patterns of the neighboring passing tests. Please run npm run test in CI/review to confirm.

Notes

  • Decision (a) from the plan gate: drafts excluded by default, revealed by the Draft filter, with a count shown separately. Position-card stat cluster intentionally unchanged (a separate decision, per the plan). Applicants are not told their draft is visible — no change to any applicant-facing copy.

Adds a purpose-built read path (getDraftApplications) so a manager or
admin sees who has started an application for their position, without
ever exposing answers, files, or the draft detail page. listable,
reviewable, and getApplicationForReview stay untouched.

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 Sep 5, 2026
@b-at-neu b-at-neu self-assigned this Sep 5, 2026
@vercel

vercel Bot commented Sep 5, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated
aplio Ready Ready Preview Sep 6, 2026 12:13am UTC

@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 labels Sep 5, 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 · needs revision

2 open — 2 🟡 Low (see inline)

Comment thread prisma/data/applications.ts Outdated
Comment thread prisma/data/applications.ts
@b-at-neu b-at-neu added needs revision Review found issues that need fixing revising Revise agent working (in-flight) and removed reviewing Review agent working (in-flight) needs revision Review found issues that need fixing labels Sep 5, 2026
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@b-at-neu

b-at-neu commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator Author

Revision — Cycle 1

fixed R1-L1, R1-L2 · 78904ec

@b-at-neu b-at-neu added ready for review PR ready for review agent reviewing Review agent working (in-flight) and removed revising Revise agent working (in-flight) ready for review PR ready for review agent labels Sep 5, 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 2 · approved

0 open — clean

@b-at-neu b-at-neu added approved Review passed, ready to merge and removed reviewing Review agent working (in-flight) labels Sep 5, 2026
@b-at-neu

b-at-neu commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator Author

Feedback from human design review

Simplify the draft-visibility UI — three changes:

  1. Delete DraftsInProgressNotice entirely (component file + its render in app/(main)/(auth)/manage/applications/page.tsx). No persistent "N applications in progress" card at the top of the page anymore.

  2. Delete the separate DraftApplicationsTable/DraftApplicationsResults components. Drafts should render through the same ApplicationsTable/ApplicationsResults used for regular reviewable applications, not a bespoke parallel table. When the Draft filter is selected, ApplicationsResults should fetch via getDraftApplications/getDraftApplicationsCount and pass those rows into ApplicationsTable, which needs to render them correctly:

    • No checkbox column, no row link to a detail page, no ApplicationStatusActions for draft rows (they stay inert — matches the current DraftApplicationsTable behavior).
    • Column set for a draft row: Applicant (name + email, same display rule as today), Position, Started (createdAt), Last updated (updatedAt) — instead of the regular table's Submitted/Status columns.
    • Sorting stays limited to name/date for drafts, same as today's DraftApplicationsTable.
    • This will require ApplicationsTable to accept a union of the regular application row type and DraftApplicationListItem, discriminating on whether status/checkbox-relevant fields are present (or an explicit isDraftView prop) to pick the right columns/behavior per row.
  3. Add contextual helper text, shown only when the Draft filter is selected (not persistent) — a short privacy explanation directly above the table (e.g. "Drafts show only the applicant's name and email — no answers are visible until they submit."), replacing the notice card's job of explaining what a draft row means.

Keep everything else: the "Draft" status filter option, the identity-only getDraftApplications/getDraftApplicationsCount data layer, the privacy/security guarantees (no answers, no detail-page access), and the count still being visible somehow if cheap (a small count next to the Draft filter option itself is fine, just not a separate top-of-page card).

@b-at-neu b-at-neu added needs revision Review found issues that need fixing revising Revise agent working (in-flight) and removed approved Review passed, ready to merge needs revision Review found issues that need fixing labels Sep 6, 2026
Drop the persistent DraftsInProgressNotice card and the bespoke
DraftApplicationsTable/Results; drafts now render through the same
ApplicationsTable/ApplicationsResults, with an isDraftView flag
switching columns, sort fields and the inert row treatment. The
privacy explainer moves above the table and only shows in draft
view; the Draft filter option gains a small count instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@b-at-neu

b-at-neu commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator Author

Revision — human design review

Addressed the design-review comment above: deleted DraftsInProgressNotice and the separate DraftApplicationsTable/DraftApplicationsResults; drafts now render through ApplicationsTable/ApplicationsResults via an isDraftView prop (inert rows, Started/Last-updated columns, name/date-only sorting). The privacy explainer is contextual (shown only in draft view, above the table) instead of a persistent card, and the Draft filter option now shows a small count. ef94e8a

@b-at-neu b-at-neu removed the revising Revise agent working (in-flight) label Sep 6, 2026
@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 labels Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claude Will be worked on by Claude reviewing Review agent working (in-flight)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Show Managers Who Has A Draft Application, Without Exposing Answers

1 participant