The brand, site and recruiter portal behind a senior-specialist and executive search firm.
Recruitment workflows covering candidate intake, screening, scoring and outreach.

- Client
- Restart Recruitment
- Sector
- Recruitment
- Stack
- SvelteKit, Astro, Postgres
- Forced row-level security
- 23 tables
Restart runs executive and senior-specialist search with a written shortlist rationale on every hire. The internal stack enforces that standard: structured scorecard screening per role so every brief is judged the same way, and reporting across open roles, pipeline and time-to-fill.
The portal and its security model
We built the brand, the marketing site, and the full recruiter portal behind them: candidates, clients, jobs, interviews, offers and placements, an outreach engine over Outlook OAuth, and Docusign and Stripe webhook integrations. The security model: forced Postgres row-level security on twenty-three tables, per-request membership re-checks, and TOTP sign-in with hashed one-time recovery codes, pinned by eleven invariant tests so a later change cannot regress it.
What we built.
- Brand identity and editorial site
- Candidate intake, screening, and scorecard flows
- Outreach engine with Outlook OAuth, and a recruiter portal: candidates, clients, jobs, interviews, offers, placements, reporting
- Forced Postgres row-level security on twenty-three tables, and TOTP two-factor sign-in
How it is secured.
Tenant data behind forced Postgres row-level security on twenty-three tables, TOTP two-factor sign-in, and eleven invariant tests (TOTP replay, OAuth timing, webhook input caps) pinning the security model.
Inside the build.
A scorecard on every brief
Every role in the portal carries a structured scorecard, and every candidate on it is screened against the same criteria, with the recruiter's screening notes kept on the record. A role moves from draft to open, and from open to on hold, filled or cancelled, and each move writes an audit row in the same transaction as the change.
Matching compares an open role with the candidate pool on skills overlap, location, compensation band and seniority, and opens an application for each candidate scoring above 50 out of 100, ready for the recruiter to screen. The match score is stored and shown as a range, a low and a high figure.
An uploaded CV is parsed into a structured candidate record, returned as strict JSON against a fixed schema, and the original file is kept in Azure storage. From there a candidate moves through applications, interviews, offers and placements, each record linked to the application it came from, and every placement carries its follow-ups. A new candidate is checked for duplicates by email address and phone number within the firm before the record is created.
Job feeds bring listings in from configured sources into a firm-wide feed. Each source records when it last ran, whether the run succeeded, and how many listings it brought in. Listings are scored against open roles, and each match keeps its score with a breakdown of how it was reached.
Outreach a recruiter sends
Outreach runs in cohorts. A recruiter builds a cohort of targets, starts its pipeline run from the cohort's own page, where each run is logged with its status, and reviews each draft in the Outlook drafts folder of the sending mailbox, where it lands through Microsoft Graph. Nothing is sent until the recruiter has reviewed it and pressed send.
Replies come back into the portal for triage: promote the person to a candidate, mark them not interested, or snooze. An unsubscribe goes on a suppression list that holds across every tenant on the platform, so a person who opts out once is excluded from every later cohort. The unsubscribe link carries a signed token, so the opt-out applies to the right person without them signing in.
Interviews, offers and reporting
A recruiter connects their Outlook calendar through a delegated Microsoft 365 sign-in, and every interview also produces a calendar file to send to the candidate. Offers are raised from the application and signed through Docusign, and the signed status comes back by webhook. Billing runs through Stripe, with payment events received the same way. An in-app notification is written in the same transaction as the action that caused it, so the two commit together.
Reporting covers open roles, pipeline and time-to-fill. The figures are calculated per tenant straight from the database each time the page loads.
Tenancy and sign-in
Restart is multi-tenant. Postgres row-level security is forced on twenty-three tables, covering candidates, clients, jobs, applications, interviews, offers, placements, outreach, notifications, recovery codes and the audit log. Forcing it holds the table owner to the same policy as the application.
Membership is re-checked on every request, and a write that crosses tenants is authorised against the caller's role in the target tenant. Viewers are read-only, and a user who belongs to more than one tenant chooses which one to work in at sign-in. Staff sign in with TOTP. The authenticator window accepts the previous and next 30-second codes, and a replay guard refuses any code already used inside that window. Recovery codes are single-use and stored as argon2id hashes with a 64 MB memory cost. Every privileged action writes a row to the audit log, and sign-in and MFA attempts are rate limited per source address. TOTP secrets and calendar refresh tokens are encrypted at rest with AES-GCM.
How it is built
Restart is one TypeScript monorepo. The recruiter portal is SvelteKit, wrapped with Capacitor for iOS and Android from the same code, and the marketing site is Astro. Shared packages hold the brand, the database client with its row-level security helpers, the Zod schemas checked at every API edge, and the recruitment logic for parsing, scoring and outreach. Postgres sits under Prisma, the infrastructure is defined in Bicep for Azure's Australia East region, and the stack choices are recorded as architecture decisions in the repository.
The repository is self-contained by rule. No symlink or import reaches outside it, so the whole platform can move to Restart's own cloud account in one transfer.
Services involved.
Start an engagement.
Tell us what you need built, reviewed or secured.