Access
Who can interact with hiring information?
A session identifies the person, a role decides what they may do, and both are checked again in the database. Four roles: Owner, Admin, Recruiter and Viewer.
Scoreboad is designed to keep hiring information controlled, reviewable, and connected to the people responsible for hiring decisions. Everything on this page is a mechanism in the product today — described precisely, with the gaps named rather than left out.
Overview
Five areas, each one backed by a mechanism in the product rather than a posture.
Who can interact with hiring information?
A session identifies the person, a role decides what they may do, and both are checked again in the database. Four roles: Owner, Admin, Recruiter and Viewer.
How is information kept in the right workspace?
Every table carries an organization and a row-level policy. A record addressed by an id from another workspace comes back as not found.
How is AI-generated information handled?
A model returns a structured result that is checked in code before anyone sees it. It holds no database handle and no tools.
Where do people inspect what was produced?
AI output is shown beside the material it came from, on a screen built for correcting it. What the model said is kept alongside the correction.
What activity can be traced afterwards?
Eighty-six catalogued event types record who did what, to which record, and when. Access-changing events are restricted to Owners and Admins.
Architecture
Eight layers, in order. Each one names the mechanism that performs it.
Signs in with email and password or Google, through Supabase Auth.
An HTTP-only session cookie, refreshed at the edge on every request. Routes are protected by default: anything not on the public allowlist requires a session.
The route resolves the workspace and the role from that session — never from the URL, the body or a header.
The active-workspace cookie is only a hint. It is re-checked against real membership rows on every request, so a forged value yields the default workspace rather than access.
Row-level security is the real boundary, not the route handler — the browser holds an authenticated database client, so a rule that exists only in application code is not a rule.
Jobs, candidates, applications, interviews and evaluations, each row owned by one workspace and reachable only from it.
Structured input in, a validated structure out. No tools, no database handle, and no write to a candidate's record.
A person reads the result beside its source and decides. The decision is recorded against them.
Access control
Hiding a button is cosmetic — a request made with curl never runs your interface. So each access rule is written in three places, and the database is the one that decides.
Controls a role may not use are not rendered. This is for clarity, and it is treated as carrying no security weight at all.
Every route handler resolves membership and role from the session before it does anything else. Five routes are public by design — the application form, three candidate coding-session routes and one webhook — and each is authorised by a signed token or an HMAC signature instead.
Row-level security policies and role-checking functions, plus triggers for the rules a policy cannot express: only an Owner may grant or revoke Owner, nobody may change their own role, and a workspace cannot be left without an Owner.
Data isolation
Every table that holds hiring information carries the workspace that owns it, and row-level security decides what a query returns — including a query the application never wrote.
Workspace A
Workspace B
An id belonging to another workspace returns 404. Answering 403 would confirm the record exists, which is an oracle worth nothing to a legitimate user and a great deal to anyone enumerating ids.
Never a request body, a query parameter or a header. Those are attacker-controlled by definition.
Around twenty triggers stop a correctly-owned row from pointing at another workspace's parent record — the shape of isolation bug that a per-table policy on its own will not catch.
Data handling
Resumes, applications, screening answers and interview feedback are all written by people who did not ask to be processed by software. What follows is what the product enforces at each edge.
AI and human review
Every AI feature returns a structured result that is checked in code and then shown to a person beside whatever it was derived from. No model writes to a candidate's record, and when the provider is unavailable the manual workflow still works.
No tool access and no database handle. It receives structured input and returns text.
A screening report stores the AI's original fields and the correction separately, so what the model produced and what a person changed it to are both visible afterwards.
The screening call opens by saying it is automated and may be recorded. That disclosure cannot be reordered or switched off.
Nothing here claims the AI is unbiased, accurate or objective. It is not audited for bias, and no part of the product treats its output as a finding — which is why a person reads it before it counts for anything.
Auditability
The activity log is a closed catalogue of eighty-six event types, so every row renders as a sentence rather than a raw slug — and so a summary of it can be checked against it.
This is an activity record, not a tamper-evident ledger. It is not claimed that every action in the product is logged permanently.
Privacy
Candidate information is handled where hiring happens rather than in a separate compliance surface. These are the controls that exist in the product today.
An organisation's administrators have a privacy screen in the product — retention settings and candidate data handling live there, beside the workspace they apply to.
The screening call discloses that it is automated and may be recorded. Outbound messages carry an unsubscribe link that is a signature rather than a stored token, so it cannot be leaked from a database copy.
A recipient is masked in the log row itself, and the full address stays on the candidate's record where it belongs.
How this information is handled end to end — what is collected, what AI does with it, and what is not in place yet — is set out in full on the privacy page. Read the Scoreboad privacy page
Principles
Each one restates a mechanism described above, so no principle here can be true on this page and unsupported further up it.
Four roles, checked in the interface, the API and the database. The database check is the one that counts.
Every row belongs to a workspace, and row-level security decides what a query returns rather than the code that wrote it.
AI proposes, a person applies. There is no path through the product that turns model output into a decision on its own.
Uploads, ids, webhook payloads and AI output are all narrowed before use, with database constraints as the backstop.
A closed catalogue of events records who did what and when, with access-changing events restricted to Owners and Admins.
Recipients masked at write time, IP addresses stored only as a keyed hash, credentials encrypted behind a column-level revoke.
Status
A security page that lists only strengths is an advertisement. These are the gaps, named because finding them out later is worse than reading them now.
No SOC 2, ISO 27001, HIPAA, PCI DSS or CCPA attestation. None is held, none is in progress, and no badge appears anywhere on this site.
No penetration test and no external security review has been carried out.
Five security headers are set — framing, sniffing, referrer, transport and permissions. A CSP is not among them, because a policy loose enough to ship quickly would be theatre.
No MFA, no session-revocation screen and no login-attempt lockout of our own.
Uploads are type-checked and size-capped, and they are never executed or served from our origin — but their contents are not scanned.
There is no security address to report an issue to yet, and inventing one would be worse than the gap: a report sent into nowhere is a vulnerability nobody is working on.
The walkthrough covers the whole flow, end to end, including where a person has to sign off.