Skip to content
Sam Hankins

rssHQ · 2017–present

The System Held the People

Designing a recruiting platform around the relationships a spreadsheet couldn't hold.

Roadshow Staffing runs product demo events in warehouse clubs nationwide. I designed and built a recruiting and applicant tracking platform where every decision a recruiter makes triggers the right downstream actions automatically, so the team can trust the system and focus on the people.

Role

Designer and Builder

Sole practitioner. End-to-end ownership of design and build.

Timeline

2017 to present

Consulting era through purpose-built platform.

Stack

Supabase · React

Built with Claude Code and Cursor.

It's Monday. The recruiter has events to staff in Phoenix, Dallas, and Columbus. Setup starts Wednesday night. Some of these hires won't be made until Wednesday morning. Eleven candidates are filed under "Needs to be rescheduled," and there's no way to tell which ones are actually ready to move without opening each record one by one.

Recruiting is relationship work.

The recruiting team didn't treat any of this as noise. They tracked people whose cars broke down, whose partners landed in the hospital, who went quiet and resurfaced three months later asking if anything was available near them. Because the person who falls off this week is the same person you'll need next month for another event in the area.

When a candidate falls through the cracks, someone has to fill that gap by Thursday, and the team was the only thing holding the memory of who was warm, who was promising, who had been strong but unavailable the last time around. The client never sees any of this. By Wednesday night, the shelves are set. By Thursday, the demos are running. The relationship work is what makes that happen, and it lives in a place the tool can't see.

This is relationship work: you might need that person next month.

The workarounds were the spec.

When I first started working with Roadshow in 2017, the pipeline lived in Google Sheets. I moved it into Airtable so the team could finally see the whole thing in one place: forms replaced raw email intake, data flowed into a shared database, and the team could work from one record.

That solved the visibility problem. It didn't solve the relationship problem.

After a hiatus brought on by the pandemic, the company continued it's work at a different scale and picking back up where we left off.

I came back in 2024 to design and build a purpose-built platform. The Airtable workarounds had only gotten deeper. I worked alongside the founder and a recruiter through real weeks: the Phoenix show going sideways, the Wednesday morning rush to find someone, the hour they'd spend reconstructing who was warm for a rush hire in Dallas. The diagnosis came from watching the work happen, not from asking about it.

Airtable workarounds composite: applicant names with context notes embedded ('Sig other has broken rib.' 'Hold, needs new car.' 'Call May 2020, graduated?'), outreach column with personal shorthand, and status dropdown showing 'Call 2/2/ 11:00' as a single-select option alongside Hold and MIA
The workarounds weren't sloppy. They were the team refusing to lose the relationship, even when the tool gave them nowhere to put it.

Three things the team was doing in Airtable that Airtable wasn't designed for:

Names as notes.

Context went into the applicant's name field, because the name was the only thing that showed up everywhere the record did. "Sig other has broken rib." "Hold, needs new car." "Call May 2020, graduated?"

Outreach as personal diary.

The outreach column had become a free-text log of every voicemail and text, written in shorthand legible only to whoever wrote it: "HOLD - 10/11 - VM/text Mother is having health issues. 10/8 call/text..."

Statuses as calendar entries.

"Call 2/2/ 11:00" was a single-select option in the application status field, alongside Hold, Decision Made, and MIA.

Airtable Application Status dropdown showing the first half of options: Application, Awaiting Interview Time, Interviewing, Needs to be rescheduled, Needs Decision, Paperwork Sent, Paperwork Sent - Sam's, and Sent Training Materials Airtable Application Status dropdown continued: Send to Onboarding, TEMP REVIEW, Hold, Declined Offer, MIA, Complete, Packet Complete, Decision Made, MI, and 'Call 2/2/ 11:00' used as a status option
Nineteen statuses in a single-select field. Some are pipeline stages, some are calendar reminders, some are one-off tags created for a single person. The dropdown became a living record of every situation the team had encountered and tried to name.

The workarounds weren't sloppy. 'Interviewing' alone covered five distinct situations: invite sent, invite waiting, interview scheduled, interview completed, notes missing. The workarounds existed because the team refused to lose the relationship, even when the tool gave them nowhere to put it. The workarounds were the spec.

  1. 01

    Compliance is a design constraint.

    Costco audits happen. Employment law exposure is real. Every decision a recruiter makes about a candidate needs to be traceable and producible.

  2. 02

    The team turns over too.

    What one recruiter knows about a candidate can't live only in that recruiter's head. The system has to hold the relationship even when the person who built it moves on.

  3. 03

    The pipeline isn't linear.

    People go quiet and resurface. Someone who was strong but unavailable for one event needs to stay visible for the next. The tool was treating the pipeline as a flow. The team was treating it as a way to remember people across time.

The tool had to hold relationships, not track states.

Four decisions where the tool started doing the remembering.

Decision 01

Status is the output of a decision, not the input.

I inverted the recruiting workflow.

In the old workflow, the recruiter's status selection was step one. The work was a cascade of manual tasks that followed. "Invite to Interview" meant drafting a message, copy-pasting the email address, sending it, waiting for a response, coordinating back and forth, adding the appointment to a calendar, then returning to Airtable to update the status manually. Every step was the recruiter's job. Every step had to be remembered.

What a recruiter sees in rssHQ is a single contextual action button on each applicant card: Invite to Interview, Recommend, Hire for Event. The button reflects where the applicant is and what the right next move is. Choosing it doesn't record a status. It is the decision, and it triggers everything downstream. The invite goes out with a scheduling link. The candidate picks a time. The interview lands on the calendar automatically. The status updates itself.

VIDEO

Side-by-side: the old 7-step manual invite cascade (draft, copy-paste, send, coordinate, calendar, update record) vs. the single contextual action button in rssHQ

Seven manual steps across messaging, scheduling, calendar, and record updates. One contextual action.

The wrong version first

The workarounds I'd documented in Airtable looked like a schema problem. I reduced the team's many improvised statuses down to a tighter pipeline (Applied, Reviewing, Interviewing, Recommended, Hired) and wired up automations. The assumption was that cleaner labels would mean clearer thinking.

What actually happened

In testing, the recruiter would pause before selecting, unsure which label fit or what skipping a step would cost. The pause wasn't about the menu length. It was about the gesture. "Interviewing" wasn't just the wrong word. It was the wrong kind of word. It named a state, not an action. The recruiter didn't need to update someone's status to Interviewing. They needed to invite them to interview. One is a label you set after the fact. The other is a commitment to a person the tool can act on directly.

PHOTO

Side-by-side: the reduced-pipeline dropdown prototype vs. the final contextual action button

The dropdown prototype named a state. The contextual action button made a commitment.

What I chose

A single contextual action button per applicant card. The recruiter makes one decision; the system handles everything downstream. The action is the status.

What I rejected

A tighter status dropdown that wired up automations downstream. Cleaner labels, same gesture.

Why

The founder was hesitant about how opinionated the system was. A recruiter used to moving freely between statuses would feel the constraints immediately. I held the position because the math was clear: the seconds a structured decision costs are seconds. The hours the old cascade cost were hours.

Decision 02

A blank Hold is a parking lot. A Hold with a reason is a decision.

Hold was the one status I kept, and I didn't love the decision. The team was attached to it. It meant something to them, even if they weren't consistent about what. Removing it would have created more resistance than it resolved.

So I kept it, with one condition: Hold requires a written reason. A blank Hold loses the person. A Hold with a reason is a bookmark you can return to: the specific thing you noticed about this candidate, the specific context you'd want to remember three months from now when the right event comes along. The required-reason field turns a parking lot into relationship memory, captured in the recruiter's own voice.

What I chose

Hold kept, but requires a written reason in the recruiter's own words. A parking lot becomes a decision with context attached.

What I rejected

A dropdown of canned reasons: great candidate wrong timing, reference pending, availability conflict. Faster to fill in, easier to audit.

Why

The point was to preserve the nuance the team was already holding in their heads. The second you ask them to pick from a list, you lose the thing you're trying to capture.

Decision 03

Skip any step, but leave a trail.

The system doesn't force recruiters through a fixed sequence. If someone needs to skip a step, they can. The system logs the skip with a required reason. Nothing disappears silently. Every deviation from the expected path is visible and traceable in the applicant's activity history.

That's a compliance decision. Roadshow operates across state lines with Costco audits and employment law exposure. "Who did what and why" is the record the business might need to produce on a Tuesday afternoon. It's also a relationship memory decision. The same activity history that satisfies an auditor is the same record the team reads when they're picking up someone else's candidate for the first time. The reason one recruiter wrote next to a skipped step three weeks ago is the reason the person covering for them needs to see today.

One record, two stakeholders, no tradeoff. The compliance use case and the continuity use case converged on the same interface, because the thing the auditor needs to see and the thing the teammate needs to see are structurally the same thing: what happened, when, and why.

What I chose

One unified activity history. Every skip is logged with a required reason, readable by auditors and teammates equally.

What I rejected

Split records: a compliance-facing audit trail and a team-facing activity feed, each optimized separately.

Why

The minute you split them, the compliance log fills with terse entries no one reads, and the team feed fills with casual notes that won't hold up to a legal query. One record forces the team to write in a way that serves both purposes.

Decision 04

Here's the design response I'm proudest of, and it's the one I didn't fully design on purpose.

Warm is a persistent state that lives outside the active pipeline. It's a first-class tab in the applicant navigation on every event, and it's surfaced in the Staffing Progress widget: right under the "3 of 6 staffed" progress bar, a secondary line that reads "1 interviewing - 1 warm." That second number is the thing the tool knows that nothing else in the category knows. The widget isn't just telling the recruiter whether the event is staffed. It's telling them how many people they could reach for if it falls apart before Wednesday.

WIDE

Staffing Progress widget showing '1 interviewing - 1 warm' as a secondary line below the main staffed/total progress bar

Not just how staffed you are. How much you have in reserve.

Warm found three different uses. Only one was planned.

  1. What I built it for. Strong candidates worth remembering next time we were staffing in their region. A way to say "keep this person accessible" without cluttering the active queue.
  2. What the team found. Warm became the state for strong candidates who applied to a fully-staffed event and would have made the cut with one more slot.
  3. What the team also found. Warm became the state for "call them first if someone falls off this week" backups for the current event.

Warm held up because it was defined by what it protects, not by what it does. The state exists to keep people the team can't afford to lose within the team's reach. Any use case that shares that shape fits the same state, which is why three different ones converged on it without me planning for two of them.

The companion move: recommendations across events.

Warm holds people within one event's orbit. The companion move reaches across events. When a recruiter clicks "Add Applicant," the search modal puts people who already have applications in for other events in the same state at the top of the results. The recruiter doesn't have to remember who else might be reachable nearby. The tool does the remembering, at the exact moment the recruiter is asking "who else could I pull in?"

PHOTO

Add Applicant modal showing in-state candidate recommendations at the top of the results list

Recommendations at the moment of need. The tool surfaces who else is reachable before the recruiter has to ask.

What I chose

Recommendations across all states, surfaced at the moment a recruiter is actively looking to add someone.

What I rejected

Warm-only recommendations in the Add Applicant modal. Cleaner, more opinionated, easier to explain.

Why

A candidate in Review on one event is still reachable for a different event in the same region. The continuity I was designing for is about the person, not about their status on any single event.

The work didn't shrink. The friction around it did.

7 → 1

steps in the interview invite flow, from a manual cascade to one contextual action

rssHQ

Every decision a recruiter makes stamps the applicant's activity history automatically: invitations sent, hold reasons recorded in the recruiter's own words, status changes traced to the person who made them and why. The state of the relationship lives in one consistent place, readable by anyone on the team. The design work is the decision buttons. The activity history is where you can see that they're working.

PHOTO

Applicant detail page showing the activity history sidebar. Callouts on: a hold entry with its reason, a re-engagement entry, a system-generated reference outreach.

The activity history is readable by anyone on the team. No shorthand, no decoding required.

rssHQ currently runs at $0/month with no per-seat pricing, replacing a top-tier Airtable subscription and separate communication tools, on a model that matches how the business actually moves: constant turnover, seasonal team changes, no friction to onboard.

The dropdown story isn't just a wrong-first-version anecdote. It's the practice the rest of the project ran on. Working as the sole designer and builder, with AI tools collapsing the time from idea to deployable prototype, meant I could test assumptions by shipping them. The team's hesitations could only become signal because I was close enough to the build to react to them in real time. The recruiter would pause on a label, I'd change it the same day, and we'd both see what the change did the next day. Most design feedback loops are weeks. This one was hours.

The biggest scope call was cutting scheduling to go deep on recruiting. The original vision included scheduling, shift management, and event coordination. Every conversation kept circling back to the pipeline, and the pipeline kept revealing more depth than I'd planned for. I cut everything else. I'd make the same call earlier next time.

The cost of holding every layer of a product in your head at once: design, data model, business logic, compliance requirements. I compensated deliberately: recorded working sessions, tracked 80+ decisions in a numbered log with dates, statuses, and impact summaries. Nothing went to code with an unresolved question attached. That rigor was the substitute for a team. It worked, and I could feel where it would stop working.

What's next

Let's talk

I'm open for new work: whether that's a full-time role, a freelance engagement, or something I haven't thought of yet. If you're working on something where 10 years of designing (and building) for high-stakes environments would be useful, I'd love to hear about it.