AQYR: one recruitment platform for agencies, employers, and the candidates between them
AQYR runs the whole hiring cycle. A job is briefed and the advertisement is written from it. The role goes live on multiple job boards, on the company's own careers page, and inside whatever recruitment software they already run. Every application is read, scored against the role, and waiting in a ranked list before anyone opens it.
We built the platform behind it: the architecture, the access model between organisations, the engine that reads and scores CVs, the integrations, and the infrastructure it runs on.
- 3 ways to describe a role: typed, spoken, or a job description uploaded
- 0 searches that start before the recruiter has checked what was understood
- 21 modules covering the hiring cycle, on one codebase
- 9 capability areas, from access control to activity logging
- 6 user types, each with a different view of the same data
- 6 scoring dimensions behind every ranked candidate
- 4 entry points into the scoring engine, all taking the same path
- 1 candidate record per person, however many systems they arrived through
These are structural facts about the build rather than survey results, which is why they are the ones on this page.
What the platform does
Follow one person through it and the product explains itself.
Not in a form. In a sentence, spoken or typed, or by uploading the job description. The system works out what they mean, fills in what it can from the roles and industries that firm already hires for, shows its reading back, and waits. Nothing is searched until the recruiter agrees with it.
A recruiter enters a title, a location, a salary and a few requirements. The advertisement is drafted from that, section by section, and the priority skills are dragged into order of importance. One action publishes the role to several job boards, to the company's own careers page, and into their existing recruitment software.
Their CV is stored, the application is recorded, and the confirmation appears immediately. Nothing heavy happens while they are waiting.
By then every CV has been read and every applicant scored against the role, each with a breakdown of how the score was reached and which of the priority skills the person can actually evidence. From there the recruiter shortlists, adds notes, moves people between stages, and sends the client a recommendation report.
Candidates who were not right for this role are kept in a talent pool that stays current, so the next similar role starts with a warm list rather than a blank page.
- Client
- AQYR, a recruitment platform for agencies and in-house hiring teams
- Product
- Multi-tenant B2B SaaS with a candidate-facing portal
- Our scope
- Web application, backend platform, CV parsing and candidate scoring engine, integrations, cloud infrastructure
The one fact that shaped everything
Most multi-tenant platforms are built around one rule: keep tenants apart. This one could not be.
AQYR has to let tenants across the boundary on purpose.
An external recruitment agency works a client company's roles. They need that client's jobs, candidates, notes and email history, and none of it for any other client on the platform. Two competing agencies can be working the same employer at the same time. The same agency can be working two employers who compete with each other.
So the requirement is not isolation. Isolation is the easier problem. The requirement is permission that is granted deliberately, scoped narrowly, and withdrawn at three different levels, evaluated fresh rather than assumed from a session that started an hour ago.
There is a second fact of similar weight, and it is the one recruitment platforms most often get wrong.
The largest group of people on the platform are not the customers.
Candidates outnumber recruiters by orders of magnitude, and a CV is one of the densest personal records a person ever produces: full name, address, phone, email, every employer, every date, qualifications, work rights, salary expectation. Most of those people never signed up for anything. They applied for a job.
Everything below follows from those two facts.
The five decisions that mattered
If you read nothing else on this page, read this.
The recruiter describes the role in their own words. What runs is what they confirmed, not what a model guessed.
An agency recruiter can reach a client's data because they were connected, approved and staffed onto that account, not because they hold a recruiter account.
Reading a CV and scoring a candidate happen on a queue, so a candidate gets an instant confirmation and a recruiter can post a job to thousands of people without the screen hanging.
Two independent methods, six visible dimensions, and a written explanation, because a recruiter has to justify a shortlist to a client.
Candidate data and client credentials are protected on the assumption that the likeliest threat already has a valid login.
The search is checked before it runs
Finding candidates used to mean filling in a form. Job title, location, industry, skills, years of experience, each in its own box. The recruiter already knew the role. They just had to break it up and type it back in one piece at a time.
The search then looked for the exact words they had typed. Ask for shutdown experience and you would not see someone whose CV said offshore turnaround maintenance, even though it is the same job. That person was already in the database. They just could not be found.
If the assistant misreads the request and searches anyway, it returns a confident list of the wrong people. The recruiter cannot tell a good search from a misunderstood one. They find out when the client rejects the shortlist.
They can type it, say it out loud, or upload the job description. No form.
It already knows which industries the firm works in and what roles it has hired for, so the recruiter does not re-enter things the platform already has.
Not a form, one question.
Mechanical engineer. Perth. Mining and resources. Three to five years. The recruiter can accept that or change it, and the search does not start until they do.
Job descriptions and candidate profiles are turned into embeddings, which are a way of representing what text means, and stored in PostgreSQL using pgvector. That is how the system connects shutdown experience to offshore turnaround maintenance.
Previous jobs, industries, roles and candidates all feed the search, so it fits how that firm actually recruits.
With a count for each group: AQYR candidates, the firm's own candidates, and candidates found externally.
They can type a candidate's name directly, and a slightly wrong spelling still finds the right person. Or they can point at a candidate they like and ask for more like them, which compares experience and background rather than job title.
A search takes a sentence instead of a form. The recruiter describes the role the way they would describe it to a colleague.
People already in the database start turning up. Nothing was added. The search just stopped depending on the exact words in a CV.
A misunderstanding costs one click. The recruiter sees what the assistant understood before anything runs, so a wrong reading is corrected rather than acted on.
Repeating a keyword no longer helps. Someone currently doing the job ranks above someone whose CV mentions it five times.
Searches can be reused. Any search can be saved, run again later, or turned into a job with the details already filled in.
The recruiter controls the shortlist. They can remove a candidate with a reason, and put them back later if things change.
Access between organisations is a grant
The platform recognises six kinds of user, and the difference between them is the access model rather than the interface.
AQYR staff who approve new companies and oversee connections
The main contact at a customer company
Other staff at that company, usually with fewer permissions
An external recruiter working a client's roles
A named person on one job, such as a hiring manager
A candidate
The fourth row is the hard one. An agency is a tenant in its own right, with its own staff and its own other clients, being handed scoped access into a different tenant's data. That is deliberate cross-organisation access, which is a materially harder problem than keeping tenants apart, because the answer cannot be no.
A role-based model fails here immediately. If access came from holding an agency account, every agency would reach every client. If it came from a per-client flag, the flag would be set once and never revisited, and a recruiter who left the account three months ago would still be reading it.
Access is a grant that passes four gates in order.
A client decides whether agencies can find the company at all. An agency does not see, and so cannot request, a company it has not been permitted to find. This is the gate most platforms skip, and skipping it makes every customer permanently enumerable by every other account on the system.
Each connection request is accepted or declined by the client itself, individually. There is no bulk state in which agencies are broadly trusted.
The agency names which of its own recruiters staff the account. Being employed by a connected agency does not grant access. Being staffed on the account does.
Access is evaluated against the connection as it currently stands rather than as it stood when the session began. A recruiter removed from an account loses it on their next request rather than their next login, which is the difference between revocation and a request to please log out.
Withdrawal then works at three levels, and each one leaves the others intact.
One named individual loses access and the agency relationship continues. This exists because the real-world event is usually one person rather than one firm, and forcing a client to choose between tolerating that person and terminating a working relationship guarantees they tolerate the person.
The whole grant ends. Other agencies working the same client are unaffected.
No new requests can be made at all.
Underneath all three, platform admin keeps an oversight view of every live connection, so "who currently has access to what" is a question with an answer rather than an investigation.
Two competing agencies can work the same employer without either learning the other is there. Neither the connection list nor the candidate records reveal the second relationship.
Access ends when the relationship ends rather than when a session does. Because the check runs per request against current state, the window in which a removed recruiter is still working closes immediately.
The client holds the controls, not support. Discoverability, approval, per-recruiter blocking and disconnection are all client-side actions. None of them require a ticket, which is what makes them get used rather than deferred.
Onboarding an agency stopped being a trust decision about a firm and became a scoped, revocable, individually staffed grant about a specific engagement. That is a materially easier conversation for a client to have.
Four gates is more machinery than a permission flag, and it shows up in three places. Onboarding an agency takes more steps than flipping a switch. Evaluating access per request costs more than trusting a session claim. And the oversight view is a surface somebody has to maintain.
Each has a bounded answer. The onboarding steps are the product working, not friction, because a client who cannot see who they are admitting will not admit anyone. The per-request evaluation is a cached lookup rather than a recomputation. The oversight view pays for itself the first time someone asks who has access to a client's candidate data, which in recruitment is a question that arrives with a lawyer attached.
Nothing heavy runs where a person is waiting
Scoring is heavy and it arrives in waves. Post one job or change a role's requirements, and thousands of candidates need scoring in the same second. That load profile is not an edge case in recruitment. It is the normal shape of the work.
Handling it inside a normal web request means the request is held for the length of the batch, and the length of the batch is set by how much data the client happens to have rather than by anything the platform controls. The candidate waiting on a confirmation screen and the recruiter waiting on a job post both pay for it.
The scoring engine runs separately from the rest of the platform, and it is entered at four points: a candidate applies, a recruiter adds someone by hand, a batch of CVs is imported, or a role's requirements change and every applicant is re-scored. All four take the same path, which is why all four behave the same way under load.
The backend places one message per candidate on a queue and responds immediately. Workers pick the work up at their own pace, and throughput becomes a dial rather than a redesign: more speed means more workers on the same queue.
Three properties make it safe to retry, and they matter more than the throughput.
Running the same scoring message twice does nothing the second time rather than writing a duplicate score or a duplicate candidate.
A message either finishes or comes back for another attempt. This matters because a candidate without a score is invisible to the recruiter rather than merely late, so a lost message is a lost person, a missed match and a wrong shortlist.
Scoring that started and never finished is picked up automatically, so recovery does not depend on anyone noticing.
A large batch works through on separate machines with live progress and a mid-run cancel, and every record comes back marked as created, updated, already present or unusable.
Publishing one role to five boards does not create five streams of traffic. It creates one, aimed at the same public job page, at the same time, from candidates and board crawlers alike. A busy client posting twenty roles turns that into a load pattern the platform generated itself.
High-repeat public reads are cached, so the same job page is served without reaching the application and the database behind it every time. It is the same principle as keeping heavy work off the request path, applied to traffic the product creates rather than traffic it receives.
Job posting and re-scoring return in milliseconds regardless of batch size. A recruiter can change a role's requirements at four in the afternoon without deciding whether it is worth the wait.
A candidate gets an instant confirmation. The heaviest work in the product happens after the only moment a candidate is watching.
Heavy load stopped competing with the site. Bulk import and mass scoring run on separate machines, so a client onboarding ten thousand candidates does not slow the platform for everyone else.
Throughput became a capacity decision rather than an engineering project. Faster means more workers on the same queue.
A score has to be defensible
Two problems sit behind every ranked list, and most platforms solve only the first.
Recruiters do not get to choose what candidates send them. Files with a real text layer, scanned pages with none, and photographs of printed pages all arrive, and a general-purpose language model reads a two-column resume as nonsense, because a resume is a layout as much as it is a document.
A recruiter has to explain a shortlist to a client. A score nobody can explain is a score nobody can defend, and a score that is fully explainable is usually keyword matching wearing a percentage.
Files with extractable text are read directly. Scanned pages with none are read optically. Documents that defeat both fall to a vision model reading the page image. Every rung exists because a real document failed the one above it.
What reads the text is a model fine-tuned specifically on resumes rather than on ordinary prose, so it works out which names are employers and which are people, how dates attach to each role, and which skills the document can genuinely evidence rather than merely mention. The output is a structured profile, and that profile rather than the original file is what everything downstream searches and scores against.
Traditional matching compares the candidate against the role mathematically, using two knowledge graphs maintained in-house, one connecting job roles to the skills they involve and one covering employers. A vector model lets the engine judge that two differently worded phrases mean the same thing, so a match does not depend on the candidate happening to use the recruiter's vocabulary. Alongside it, a language model reads the whole CV in context, with the job description and context about the hiring company, and produces a written recommendation in a consistent shape every time.
rather than to us. They are adjustable per role, so the ranking reflects what matters for that hire rather than what mattered on average across a training set.
A recruiter corrects a profile rather than typing one, which is the difference between a tool people use and one they abandon in week three.
The ranking is explainable to a client. Every score opens into its breakdown, with a written summary of strengths and weaknesses and a per-skill confidence indicator, so a shortlist is a case rather than an assertion.
Candidates are not filtered out for using the wrong words. Matching on meaning rather than exact keywords surfaces people that keyword search would have skipped, which is where most of the value in a large candidate database is sitting.
Requirements can change without a re-run being a decision. Re-scoring every applicant against an adjusted brief is one action, because of decision two.
Protecting the people who never signed up
The largest group of people on this platform have no account on it. A CV is one of the densest personal records a person produces, and a recruitment database is a concentration of them: contact details, addresses, employment history, qualifications, work rights, salary expectations, and often a note about why somebody was not put forward.
Two things make it a harder target than it first appears.
A candidate database can be sold, which is not true of most business data. And the person most likely to take it is not an outsider. It is somebody who already has a valid login.
Alongside candidate data, the platform holds each client's own credentials for their job boards, their recruitment software and their work mailboxes. Those credentials are not ours, and losing them is a breach of systems we do not run.
Everything downstream searches, filters and scores against the profile, which keeps the source document out of most code paths that touch candidate data.
Keys are managed separately from the data they protect. Reading the database is therefore not the same as reading the candidate base.
Each connects with only the permissions it needs, and no administrative credential exists in the application at all. This is the layer that matters if something does get through, because an injection runs with the privileges of the credential it landed on. The ceiling on the damage is set before the attack rather than negotiated after it.
Never embedded in code, images or configuration. Because they are fetched rather than baked in, a client's board or mailbox credential can be rotated without a deployment. Rotation you can actually perform is rotation that happens, and that matters considerably more when the credential belongs to the customer rather than to us.
The candidate portal and each client's careers page are reachable by anyone, which is exactly what makes them useful. External traffic terminates at a single controlled entry point, and the data stores behind it are not reachable from the internet.
Candidate management, job management, communications and user activity each produce an entry, written in the background rather than by anyone remembering. Recruitment decisions get questioned months later, sometimes by a candidate and sometimes by a regulator, and a trail assembled retrospectively is not a trail.
In a system holding this much personal data the threat that matters most is rarely an outsider breaking in, which is why the monitoring asks what an account is doing rather than only what it is permitted to do.
A database read is not a candidate list. Field-level encryption means the most saleable thing in the system is not sitting in plaintext behind one credential.
Clients can rotate their own credentials on their own schedule rather than waiting for our release cycle, which turns a security recommendation into something that actually gets done.
A question that arrives months later has an answer. Who changed this candidate's status, who sent that message, who moved this job. Recruitment generates those questions routinely and usually long after the fact.
The most likely form of candidate data loss is the one being watched for. An insider event leaves no trace in an access control list, so watching behaviour rather than permissions is what makes it visible at all.
Security and confidentiality are the two anybody reaches for. The one that actually governs this product is privacy, and it is a different thing.
Privacy is about the people the data is about: whether they know what is held, whether they have a say, and whether a request about them can be answered. On a recruitment platform those people are candidates, who outnumber the paying users by orders of magnitude and mostly never signed up for anything.
That is why duplicate merging is a privacy control rather than a data quality one. A person fragmented across four records cannot be given a straight answer about what is held on them, or have it deleted on request, no matter how good the intent behind the reply.
The control set was designed against the criteria rather than mapped to them later. That is a statement about how it was built, not a claim to hold an attestation.
The constraints we designed around
Platforms that carry real volume across real integrations meet constraints. Some belong to partners who will not change their systems for you. Some appear when a threshold is crossed. Some come from the industry itself.
Building for all of them on day one is not prudence, it is waste. The work is knowing which to design for up front, which to instrument and address at the threshold, and which are somebody else's decision to be routed around cleanly.
Every job board wants the job differently
One role often needs to appear on five or six boards at once, and no two want it the same way. One insists on a salary range in its own format. Another wants a work type code and a category from its own fixed list. Some cap the character count, some are particular about permitted markup, most want screening questions, and every board has its own credentials.
Posting is also not the end of it. Boards expire ads, reject them, or take a while to put them up, so a job the system believes is live may not be live at all, and by the time anyone notices by hand, days of the hiring window are gone.
The recruiter fills the job in once and picks their boards. Per-board requirements are held per client and applied automatically, and the recruiter never sees any of it. Then each posting is checked on a short timer rather than assumed to have worked.
Advertising a job everywhere is one action instead of six. The ads view reflects reality, so a failed or expired posting is visible immediately rather than discovered later. A job can be pulled from a single board without touching the others. And an application from an external board arrives as a full candidate record, already read and scored, sitting in the same ranked list as a direct applicant.
One person can reach the platform through a job board application, a sync with the client's own recruitment software, a bulk import, and a recruiter's mailbox, and rarely with the same details each time. A middle name here, a second email address there, an old phone number from a CV uploaded two years ago.
The people most exposed by this platform are the ones with no account on it. A CV carries contact details, address, employment history, qualifications, work rights and salary expectation, and most candidates never signed up for anything.
People sign in with an existing work account, and every account also has to exist on the platform. Two systems have to agree on one person's identity on every sign-in, and two systems that maintain their own records will eventually disagree.
Location search ran on services the provider then deprecated. That is not a defect to schedule around at leisure. It is a countdown attached to a filter used across the entire product.
The migration also surfaced an existing weakness. The filter in use ranked international cities unreliably, and the client did not want postcodes or street addresses appearing in results at all.
The impact, depending on your job
The access model is what makes this a platform rather than a directory with scoring on top. Two competing agencies working the same employer without either learning the other is there is not a feature. It is the reason a company hands over its candidate data at all.
The talent pool compounds. A candidate database that keeps itself current turns sourcing cost into an asset, so the second hire in a role is cheaper than the first rather than the same price again.
Both sides are served without forcing either into a shape they do not work in. Agencies subcontract, employers work in teams, and a model that ignores either loses that side of the market to whoever does not.
The access model is the part worth your attention. Deliberate cross-organisation access is harder than isolation, and the four gates plus per-request evaluation are what make it a control rather than a policy. Everything else follows the same instinct: work separated by what governs its duration, syncs that reconcile rather than overwrite, and a scoring path that is safe to retry because it was designed to be.
Most of what is on this page came from decisions about where complexity should live. Per-board requirements are configuration rather than code. Four entry points into the scoring engine take one path, so all four behave the same under load. Reconciling syncs mean a failed run is retried rather than investigated.
That is what keeps a team shipping features in year two instead of maintaining twenty-one special cases and a folder of one-off import scripts.
Recruiter time moves from reading to deciding. Every CV arrives read, scored and explained, so the expensive hour is spent on judgement rather than on data entry.
The candidate database becomes an asset rather than an archive. Talent pools stay current as new people arrive, so the cost of sourcing a candidate is paid once rather than every time a vacancy opens.
Advertising is one action rather than six. Board-specific requirements are handled by the platform, which removes a per-job admin cost that scales with every role.
Throughput scales with workers rather than with engineering. Handling more volume is a capacity decision, not a rebuild.
Talk to the client, not just to us
Everything on this page is our account of our own work. That is worth roughly what you would expect it to be worth.
So we would rather introduce you. If you are seriously evaluating us, we will arrange a reference call with a client who has been through a build like this one, and you can ask them the questions you would rather not ask us.
Built with
We name the layers rather than the suppliers on the candidate data path, because a supplier map is our client's exposure rather than our credential. Full detail available under NDA.
More case studies
View all case studiesInvestor Relations for ASX — investor relations
Multi-tenant IR platform for ASX-listed companies.
Read case studyKeylr — property marketplace
Trust, dispatch and payments as one system.
Read case studyBonds — relationship wellness
A two-person platform where privacy is a data-layer property.
Read case studyBuilding a platform where the wrong person seeing the wrong record is not an acceptable outcome?
Tell us what you're building, and we'll tell you honestly how we'd approach it.