Shibil Mohammed
Back to all work

Internship · EdTech SaaS · Experiment Labs, 2025

A rejection screen designed for the person being rejected.

Review tools are built for reviewers. I designed this one from the student's side: starting from the rejection they would receive, and working backwards to the button the admin clicks.

Role
Sole product designer, six months
Surface
Internship marketplace, admin review screen
Worked with
Engineering directly. No PM, no written PRDs.
Versions
v1 to v3
Status
Designed and handed off. Never reached production.
Evidence
No users, no outcomes. Requirements reconstructed from my own decision log. The bets are named at the end.
Student Submission Details: task context, submission status panel, the brief, a copyable link to the submitted work, a required rejection reason field with helper text, and an asymmetric button pair
The whole judgment on one surface: task context, status, brief, the submitted work, and the two verbs at two prices. Approve is filled. Submit Rejection is a ghost and is gated on a reason.

At a glance

Consultancy admins review student task submissions and approve or reject them. The baseline drew approve and reject as equal buttons, and let a rejection leave silently.

This design makes rejection cost more than approval: a required, specific reason and a deliberate confirm. Not because rejection is bad, but because the real output of a review screen is not the admin's decision. It is a message a student has to act on.

The problem was in how the screen defined its own output

On an internship marketplace, companies post tasks, students submit work, and consultancy admins review it. The failure sits upstream of any pixel.

The output is misdefined

The screen looks like it produces a decision, approved or rejected. What it actually produces is a message that lands in a student's task view. The baseline designed for the decision and ignored the message.

Two unequal verbs, drawn equal

Approval ends a loop. Rejection starts one: the student has to understand what failed, fix it, and resubmit. The baseline gave both verbs the same visual weight and the same one-click cost, which prices the expensive verb like the cheap one.

A silent rejection is unfixable

"Not approved," with no reason, gives the student nothing to act on. They cannot fix what they were not told was broken. The seconds an admin saves by skipping the reason come back as follow-up questions, blind resubmissions and clarification threads, with interest.

For the marketplace this compounds. Students are the supply side. Rejections that teach nothing burn the supply side while generating support work for the same admins who saved the seconds.

Design the rejection first

Start from the worst message the tool can send, make that message useful, then work backward to the interface that produces it. The approval path costs almost nothing to design. The rejection path is the product.

One distinction shaped the whole screen: approve closes a loop, reject opens one. A verb that creates work for another human should cost more to fire. The interface prices the two verbs by what they create, not by how they look side by side.

One boundary kept that cost honest: the price of rejecting is paid in specificity, not in friction theatre. The reason field is the work. The confirm is the only added step. Nothing else slows the admin down.

Four constraints, and where each one bites

ConstraintWhat it meantThe decision it forced
No PRDs Direction arrived through working sessions. Nobody was writing requirements down, so I kept my own decision log. Every choice on this page traces to a logged rationale. It is also the only reason this case study can exist.
Permissions preceded the UI Roles and their allowed actions were fixed in a role-action matrix before screens were drawn. The interface expresses the permission model instead of papering over it. Which verbs render, on which surface, for which role.
Admin time is the scarce resource Review is a queue task. Seconds are the budget. Approval stays one click. The entire added cost lands on rejection, where it converts into student progress.
Handoff without me in the room Sole designer, engineering builds from the file. Every state specified. This is where the product's first reusable components came from.

Two users, and only one of them ever sees this screen

The admin works a review queue. Her fast path is judgment in seconds: open the submission, check it against the task, decide. Every second the design charges her has to buy something.

The student, Sarah Johnson in the screen's worked example, receives the outcome in her task view. Her ability to act depends entirely on what the admin typed. She never sees the review screen. She only sees what it sends.

The tension is structural: the design spends the admin's time on the student's outcome. The design target is the rejection case. If the screen is honest and specific there, approvals take care of themselves.

How the screen works

One surface holds everything needed to judge: task context, submission status, the student, the brief, and the submitted work with a copyable link. No tab-hopping to decide.

Then the two verbs, at two prices. Approve Submission is one click and terminal. Submit Rejection is gated on a reason.

Two states of the rejection reason field: empty with the submit button disabled, and filled with a specific written reason and the submit button enabled
The gate, in two states. Empty means the verb cannot fire. The field carries two lines of instruction: the bar ("specific enough that the student can act on it without asking follow-up questions") and the destination ("notes go directly to the student in their task view"). It tells the admin where the words land before they are written.
The confirmation step shown after submitting a rejection, presenting the written reason back to the admin before it is sent
Submitting a rejection opens a confirm step, not a silent send. It names the student, states when she will see it, and says it cannot be undone. This step came out of a design review, not the first draft.

Per-student and per-task review are different jobs. Judging one student's submission against a brief is not the same as sweeping one task across many students, so they are different surfaces rather than one screen straining to do both.

Two surfaces compared: Student Submission Details, read-deep, approve or reject for one student; and Task Overview, scan density, per-row action across twelve students
Same shell, same components, same tokens. Different defaults, different primary action, different density. One is read-deep for a single decision. The other is scan-and-batch across twelve. A tabbed single screen would have made both half-legible.

The engine: three mechanisms, v1 to v3

The original screen treated approve and reject as equal choices. It looked balanced, and balance read as neutral. But neutrality between unequal verbs is a bias toward cheap misuse of the expensive one.

Verbs are priced by what they create

Approve is terminal, so it costs one click. Reject is generative, it creates work for the student, so it costs a required reason and a confirm. The screen charges the externality to the person creating it, at the moment they create it, which is the only moment the price changes behaviour.

The reason is the product

A required field alone produces compliance, not quality. An admin can type "no" and satisfy the validator. The design cannot force a good reason. What it can do is set the bar in the helper text, print the destination on the field so the admin writes to a person rather than into a form, and use the confirm step as a forced re-read of what the student is about to receive. Whether that is enough is a named, testable bet, not an assumption.

Permissions render the UI

The role-action matrix sits upstream of every surface. A role's screen contains the verbs that role can fire, as decided by the matrix. The interface expresses the permission model instead of decorating around it. Permissions drove the UI, not the other way around.

Team Members screen listing each member with their role, status, and the actions available on that row
The role-action matrix, rendered. Each member carries a role and a status, and the actions available on a row are what that role permits. The same matrix decides which verbs appear on the review screen. Permissions were the input to the interface, not a check bolted on afterwards.
Comparison of the shipped asymmetric button pair against the rejected destructive-red treatment, each annotated with its rationale
Shipped, asymmetric weight: approve is a filled primary, reject is a ghost, hierarchy readable at a glance. Rejected, destructive red: frames the student's work as a threat. Wrong emotional register.

Key product decisions

DecisionThe obvious buildWhy I rejected itAccepted cost
Rejection requires a reason Keep the reason optional so admins stay fast. An unreasoned rejection is unfixable for the student, and generates the follow-up load it pretended to save. Rejections are slower, always, on purpose.
Asymmetric buttons A symmetric pair. It looks balanced in a design review. Equal weights price unequal verbs equally. The footer looks lopsided to a purely visual read. It is lopsided. So are the verbs.
Confirm on reject, none on approve Confirm both for consistency, or neither for speed. Consistency between a terminal verb and a generative one is false consistency. Only the verb that creates work for an absent person gets the deliberate step. One extra click, on exactly one path.
Per-student and per-task as separate surfaces One screen with tabs and filters. Two different jobs on one surface means both stay half-legible. More screens to build at a startup, offset by the shared components underneath them.
Permissions upstream of screens Design the screens, then bolt on role checks. The matrix is the input. Surfaces derive from it, not the reverse. Design blocked on permission decisions early. Slower to start, no rework after.

The product around the screen

The review screen is where the argument is sharpest, but it was not the only surface. Over six months I designed the admin side end to end: the dashboard, task creation, the team and permissions surface, and the review flow.

Admin dashboard showing task counts and an empty state for in-progress tasks with a create action
The empty state is the first screen a new admin sees. It names what is missing, gives the action, and tells them what it costs: a new task assigned in under two minutes.
Two-step task creation form covering company information then task information, with rich text fields, a video brief upload or record option, and submission constraints
Task creation, split into company then task. A brief can be recorded rather than written, because the people posting tasks are operators, not copywriters. Deadline, hours and applicant cap are set here, and they are what the review screen later judges against.

The connection matters more than the breadth. The constraints an admin sets at creation are the constraints the reviewer judges against. A brief with no stated deliverable produces a rejection nobody can write well, which is the same failure as an unreasoned rejection, one screen upstream.

Where the design system came from

This screen is where the product's first component library came from. Working alone toward an engineering handoff, every state had to be specified well enough to build without me in the room: pending, approved, rejected, the gated footer, the confirm, and the empty states on every surface that can be empty.

The two review surfaces share a shell, a component set and a token set, and differ only in defaults, density and primary action. That is the test of whether a system is real: two different jobs, one set of parts.

The components and their documented states were the handoff. The decision log was the PRD that did not otherwise exist.

What I would test, and what would settle it

This never reached users, so these are bets. Each one has the metric that decides it, including the two that would tell me the design is wrong.

Reasoned rejections reduce clarification load

The efficiency argument for the required field. If it fails, the field costs admin time and returns nothing.

MetricFollow-up messages per rejection, before and after the required reason.

Reasoned rejections improve resubmissions

The student-side argument. This is the one the whole design is for.

MetricFirst-resubmission pass rate after a reasoned rejection, against the unreasoned baseline.

The boilerplate risk

Required fields decay into ritual. Falling distinctness means the field has become a validator to satisfy, and the core bet fails. This is the one most likely to break.

Metric, and kill criteriaDistinct-reason ratio and median reason length per admin over time. Sustained decay means the required field was the wrong instrument, and I would replace it with a reason picker plus a free-text escape.

The confirm earns its click

A nonzero cancel rate is mistakes caught. The step has to justify itself or go.

Metric, and kill criteriaCancel rate at the confirm step. Near zero after the first month makes the modal a candidate for removal.

Limitations, and what comes next

This screen never got users. Nothing I designed reached production during my tenure, which is startup reality, so there are no outcome claims anywhere on this page and there will not be until something like it ships. The reasoning is what I have.

The requirements are reconstructed from my own decision log rather than a PRD, which means they carry my framing of the working sessions, not a stakeholder-signed source of truth.

And the design covers the message's origin, not its landing. The student's task view, where the rejection actually arrives and where Sarah decides whether it is actionable, is the other half of this flow and deserves the same treatment this half got.

Next, in order: design the student-side receipt of a rejection; pressure-test the reason field against real admin behaviour; instrument the four bets.

An approval ends a conversation. A rejection starts one. The screen should know which button it is drawing.

Review tools are built for the person with power in the flow. Their output is received by the person without it. Designing from the receiving end does not slow the tool down. It defines what the tool is for.

The admin clicks the button. The output lands on someone who never sees the screen.