Build a Candidate Pipeline & Placement Tracker in ViibeStack
August 18, 2026

Build a Candidate Pipeline & Placement Tracker in ViibeStack

Start here, not with the comparison

If you're reading this, you've probably already been through the case for skipping a full enterprise ATS. We're not rehashing that here. This is the build itself: the tables, the links between them, and the order to put them in so you have something recruiters are actually using by the end of the week, not a half-finished database. It follows the same bones as our lightweight applicant tracker walkthrough, but with the client and placement layer a staffing agency specifically needs.

1. Clients table

This is your foundation table, and it should be boring on purpose. Fields: Client Name, Primary Contact (name, email, phone), Status (prospect, active, dormant, do-not-work), and a notes field for account context. Don't overbuild this into a full CRM record on day one -- if you later want marketing sequences or deal stages layered on top, ViibeStack's CRM module can sit next to this table and reference the same client records. For now, the Clients table's only job is to be the thing every Job/Req points back to.

2. Jobs/Reqs table, linked to Clients

Each row here is one open requisition, not one client. A single client might have four open reqs simultaneously with different fee structures and different urgency -- if you collapse those into a single 'client' record with a status field, you lose the ability to track them independently. Fields: Job Title, Client (linked record to the Clients table), Target Fee or Bill Rate, Status (open, on-hold, filled, closed), Date Opened, and optionally Hiring Manager if it's different from the primary contact. The link to Clients matters because it's what lets you later ask 'show me every open req for Acme Corp' or 'show me every req that's been open longer than 30 days' without manually cross-referencing two spreadsheets.

3. Candidates table, linked to Reqs

This is the table people get wrong most often. The instinct is to build one flat Candidates list with a 'status' column and try to filter it by job title in your head. Don't. Link each candidate submission to a specific Req record, not just to a client. A candidate can be submitted against multiple reqs over time -- that's fine, it just means multiple candidate rows (or a junction table if you want one candidate profile tied to multiple submissions, which is the cleaner long-term structure once you're past week one). Fields per candidate row: Name, Resume/File Upload, Source (referral, job board, sourced, agency database), Linked Req, and the pipeline-stage field: Sourced → Submitted → Client Review → Interview → Offer → Placed/Rejected. The reason this needs to be a linked, per-req structure rather than one big list: a recruiter working three reqs for the same client needs to see candidate movement within each req in isolation, and your placement/fee reporting later depends on knowing exactly which req a placement closed against.

4. The kanban pipeline view, scoped per req

This is the piece that actually replaces the spreadsheet-and-email chaos, and it's the one recruiters will open every single day. Build a kanban view on the Candidates table, grouped by the pipeline-stage field, filtered to a single req at a time. A recruiter opens the req, sees six columns (Sourced through Placed/Rejected), and drags candidates across stages as things happen -- no separate status-update email, no 'let me check the spreadsheet and get back to you.' Because the stage field lives on the same record as the resume, source, and req link, moving a card is the update; there's nothing to reconcile afterward. This is also where you'll notice fast if a req is stalling -- a column with eight candidates sitting in Submitted and nothing moving to Client Review is a visible problem instead of a buried one.

5. Placement and fee tracking

Once a candidate's stage flips to Placed, that record needs to carry more than a status change -- it needs to become the source of truth for revenue. Add fields (either directly on the Candidate record or, better, on a separate Placements table linked back to the Candidate and Req): Placement Date, Fee or Bill Rate, Fee Type (flat/percentage/hourly markup), Start Date, and Recruiter (for commission attribution). Splitting this into its own Placements table is worth doing once you have more than a handful of placements, because it lets you build a clean report -- placements this month, total fees by recruiter, fill rate by client -- without that reporting logic tangled into the same table recruiters are dragging cards around in every day. This is the same instinct behind ViibeStack's analytics and reporting tools: keep the operational table fast and simple, and let reporting pull from a clean, purpose-built layer.

6. A scoped client-facing view

Clients want visibility into candidates submitted against their own reqs. The wrong way to give them that is a shared login with some fields hidden by the UI -- that's a permissions leak waiting to happen, and it means one misconfigured view exposes another client's pipeline. The right way is a scoped portal view: the client logs in and the underlying query is filtered by their Client ID, at the data layer, not just the display layer. They see candidates linked to reqs linked to their own client record, full stop -- no toggle, no shared table they could theoretically scroll past. This is exactly the pattern we walk through in building a customer self-service portal, and it's worth reading if you want the mechanics of setting up that scoped access correctly. Keep the client view read-only and narrow at first: candidate name, resume, current stage, submission date. Don't give them edit access to stage until you trust the workflow -- let them comment or flag interest and have your recruiter make the actual stage move.

7. Optional polish: notifications and a rollup dashboard

Once the core pipeline is running, two additions pay off without much effort. First, automated status-change notifications: when a client moves a candidate to Interview (or comments on a submission) in their scoped portal view, trigger a notification to the assigned recruiter instead of relying on them to check back. This is a straightforward use of workflow automation -- a trigger on the stage field change, filtered to changes that originate from the client view. Second, a simple dashboard rolling up open reqs by client, total candidates currently in active pipeline stages, and placements closed this month or quarter. Resist the urge to build this first -- it's genuinely optional polish, and it's much easier to build correctly once you have real data flowing through steps 1-5 to design it against.

The build order that actually matters

Build 1 through 4 first, in that order, and don't skip ahead. That alone -- Clients, Reqs linked to Clients, Candidates linked to Reqs, and the per-req kanban view -- is enough to fully replace a spreadsheet-and-email workflow, and you can have it running this week. Add 5 and 6 once the pipeline has proven itself out with a few real reqs moving through it; placement/fee tracking and the client portal both depend on having real stage data to scope and report against. Treat 7 as what it is: polish you add once the basics are boring and reliable, not something to chase before recruiters have a reason to open the tool every day.

← Back to the blog