Repository navigation
Releases: Ganek-dev/ganek
Release list
v0.6.0
Sixth release, two days after v0.5.0: the whole hiring team and the Monday question. Screening questions on the apply form, scorecards and a reviewer role, interview scheduling on plain calendar invites, a delayed rejection email, a richer handoff to your ATS, and a dashboard built around who is waiting on whom, with a new Reports page. Thirty-two merged branches, seven migrations (head 0045). One thing to read before upgrading: Google Calendar is gone, see below.
Highlights
- Open roles on the dashboard. One row per open role: live candidates per stage, who is waiting on you and for how long, who is overdue, what moved this week, and a status chip (Stalled, Needs attention, On track, Empty) with its rule written under the title. Chips describe the process, never a person. A closed role that still has live candidates stays on the board. Five tiles sit on top, and a stalled role lands in your queue. The overdue limit is yours to set under Settings, Hiring, Pipeline: 7 days by default, 1 to 60.
- Waiting on you, waiting on candidate. Every live application is on someone's clock, worked out from the quiz, the interview and the stage. Two new chips on Applicants filter by it, also in the export.
- Reports. A new page with a period and a job filter. It follows the applications created in the period to where they are now: funnel with pass-through and where the rest went, median time in stage with the oldest live candidate, median time to hire, sources by outcome, score distribution, applications per week and a comparison with the period before. Every median shows its n and reads "-" below 3. No benchmarks and no pass lines.
- Screening questions. Per-job questions on the apply form, with a default set for new jobs. Answers mark the applicant and can be filtered on; a preferred answer never moves, rejects or emails anyone.
- Scorecards and the reviewer role. Hand a candidate to a colleague and get criteria ratings, a recommendation and a comment back, on a form you define per workspace or job. Booking an interview requests one from the interviewer automatically, and the queue shows who is holding a candidate up. A new reviewer seat gives a colleague a small
/reviewarea with only the candidates handed to them. - Interviews without Google Calendar. Slots come from the availability you set and your own bookings. Both sides get a standard calendar invite by email, so it works with Google, Microsoft 365, Apple and anything else that opens an .ics file. Reschedules and cancellations update it, the interviewer gets the 24-hour reminder too, and an interview can carry a location.
- Send the rejection email later. Reject now and let the email go out later, or cancel it from the timeline before it leaves.
- Handoff to your ATS. Webhook payload v2 adds split names, the application message, links and a CV block; the CSV export gains
first_nameandlast_name; Send test delivers a realistic sample. API keys can fetch CVs (GET /applications/{id}/cv). New docs page with Zapier and Make recipes.
Upgrade from v0.5.0
- Google Calendar is removed. Migrations 0040 and 0041 drop stored calendar connections,
google_event_idandmeet_url, so existing interviews lose their Meet link and no longer sync to a calendar. If you have interviews booked ahead, note their links before upgrading. Google sign-in stays. TheGANEK_GOOGLE_*settings now only concern sign-in. - Invites update in place over SMTP. Over Mailjet they arrive as attachments only, with no in-place update.
- Migrations 0039 to 0045 apply automatically on
docker compose up. Back up first:scripts/backup.sh. - No new environment variables, no compose change.
docker compose pull && docker compose up -dis the whole upgrade. - Webhook payload v2 only adds fields. Existing receivers keep working.
- Erasing an application now also deletes its webhook delivery rows.
- Reports only sees what retention keeps. Rejected and withdrawn applications leave it when your retention window deletes them, so long periods overstate pass-through.
- API: new
GET /stats/board,GET /stats/reports,GET /applications/{id}/cvand/review;waiting=team|candidateon the applications list and export;PATCH /company/settingsacceptsstage_limit_days./stats/overviewkeeps its shape, and the dashboard no longer readsquizandweeklyfrom it.
Known limits
- The admin shell has no mobile layout yet: below tablet width the fixed sidebar makes the dashboard and Reports wider than the screen.
Run it
git clone https://github.com/Ganek-dev/ganek && cd ganek
docker compose upContainer images: ghcr.io/ganek-dev/ganek-backend:0.6.0 and ghcr.io/ganek-dev/ganek-frontend:0.6.0 (linux/amd64 and linux/arm64).
Docs: the quickstart and the self-hosting guide on ganek.dev; the compliance pack is in docs/compliance/. Try it first at demo.ganek.dev. Hosted version: join the waitlist at ganek.io.
License: AGPL-3.0.
v0.5.0
Fifth release, three days after v0.4.1: the recruiter's day-to-day on the applicant side. Candidate emails you can read, edit and own before they go out, a timeline per application that shows every email with its text, an applicant list built for hundreds of rows, and a round of quiz fixes. Twenty-one merged branches, four migrations (head 0038), no breaking change for self-hosters.
Highlights
- Read the email before you send it. Advance and Reject with "Email the candidate" on now open the email as this candidate receives it: subject and text, rendered by the same code that sends it. The bulk bar previews the first selected candidate's mail with the line "Shown for X; each candidate gets their own values."
- Your templates. Settings gained an "Emails" tab: one section per kind (assessment invite, reminder, interview, rejection) with the Ganek default plus your own templates, one default per kind, Set as default, Duplicate, Edit, Delete. The editor has placeholder chips, a live sample preview and a validation message naming any unknown placeholder. The assessment link, the status link and the privacy footer are always added by Ganek and cannot be lost. The stage dialog and the bulk bar pick a template; the chosen text is snapshotted when you confirm, so a later edit never changes an email already on its way.
- Edit this email. One send, one text: change the subject and body for this candidate only, without touching the template. Braces stay as typed; the fixed block and footer still follow.
- Send a message. A free subject and body to a candidate from the applicant panel, previewed live, with replies going to your own inbox (Reply-To). It shows in the timeline like every other email.
- Rejection reason, internal. An optional reason (picklist) and a note on each rejection, from the dialog or the bulk bar. Never emailed, never a placeholder: it lives in the timeline, the CSV export and the Article 15 data bundle, so keep it factual. A candidate who withdraws is recorded as "withdrew".
- Timeline per application. Stage moves with who did them, every email with its delivery state, quiz milestones (issued, started, completed, expired), notes, interviews, newest first. Sent emails show their subject and the full text behind "Show text" (the candidate's personal links are masked). "Longest in stage" sort and "in screening for 4d" in the panel header come from the new
stage_changed_atstamp. Stage moves get an undo toast. - Applicant list for real volumes. Search by name or email, filters for score, quiz state, source, integrity flags and application date, sort by date, score, name or stage age, all in the URL. A sticky bulk bar moves or rejects the selection, exports the selected rows and emails each candidate when asked. New
POST /applications/bulk-stage. - Google Jobs card. The job overview shows the JobPosting markup the public page emits, with Google's required-field check, a copy button and a link to Google's documentation. The demo instance switches the markup off and the card says so.
- Quiz fixes. Questions that ran out of time are counted separately on candidate surfaces and in the status page; the countdown ring derives from the server clock and resyncs when a tab comes back; integrity flag messages number questions by serve order.
- Copy. Arrow glyphs are gone from admin copy (words or an icon), with a guard like the dash guard. Job pages build their meta description from the posting text.
Upgrade from v0.4.1
- Migrations 0035 (
applications.stage_changed_at, backfilled), 0036 (applications.rejection_reason,rejection_note), 0037 (email_templates) and 0038 (email_outbox.rendered_subject,rendered_text) apply automatically ondocker compose up. Back up first:scripts/backup.sh. - No new environment variables, no compose change.
docker compose pull && docker compose up -dis the whole upgrade. - The plain-text version of the four stage emails now matches their HTML version (the designed text); the HTML is unchanged. Workspaces that never open the Emails tab keep today's emails.
- Outbox rows store the rendered subject and text from this release on; older rows show kind and state only in the timeline.
- API:
PATCH /applications/{id}/stageacceptstemplate_id,subject,body,rejection_reason,rejection_note; bulk endpoints accepttemplate_id,rejection_reason,rejection_note. New:GET /applications/{id}/timeline,GET /applications/{id}/email-preview,POST /applications/{id}/message,/company/email-templates. The CSV export gainedrejection_reasonandrejection_notecolumns at the end.
Run it
git clone https://github.com/Ganek-dev/ganek && cd ganek
docker compose upContainer images: ghcr.io/ganek-dev/ganek-backend:0.5.0 and ghcr.io/ganek-dev/ganek-frontend:0.5.0 (linux/amd64 and linux/arm64).
Docs: the quickstart and the self-hosting guide on ganek.dev; the compliance pack is in docs/compliance/. Try it first at demo.ganek.dev. Hosted version: join the waitlist at ganek.io.
License: AGPL-3.0.
v0.4.1
Patch release, one day after v0.4.0: the job overview finished and hardened, and one house rule applied to every line of copy. Ten merged branches, no migration (head stays 0034), no breaking change for self-hosters.
What changed
- Overview numbers agree with each other. The Applications tile, the apply-rate denominator and the per-job 7-day count now use the same UTC calendar days as the views and the daily chart (today and the 29 days before it). The tiles say so in their tooltips.
- Empty states that tell the truth. A live job with no views yet says "No views yet. Share it:" with the share links right there. A closed job says views were not counted and offers nothing to share. A job whose applications predate the counter says views are counted from the 0.4.0 update on.
- Accessibility. The daily chart's accessible name carries the period's totals instead of thirty mouse-only tooltips. The custom share-link input has a real label, a polite live status line and aria-invalid. When the company summary cannot load, the share cards say so instead of showing a skeleton forever. An axe check guards the overview page.
- Share links. Built with the URL API (fragments stay last, an existing
srcis replaced). A custom name that is already a built-in source says so and keeps its link;directis refused, since it is the name of untracked traffic. - Counters under load. The per-day source budget is serialised per job and day, so a burst of new tracked-link names can no longer overshoot the 50-source cap.
- Bot detection. "bot" counts only where crawlers put it, so phones such as CUBOT count as people again. The user-agent table grew on both sides.
- Optional
GANEK_SSR_SECRET. Set the same long random string on the backend and the frontend and only the page render can count a view; anyone calling the API with the view headers but without the secret is served as usual and not counted. Unset, nothing changes. - No em or en dashes anywhere. Every line of copy, from page titles and email subjects to the question bank, uses a plain "-". A repo-wide guard keeps it that way.
Upgrade from v0.4.0
- No migration, no new required setting.
docker compose pull && docker compose up -dis the whole upgrade. GANEK_SSR_SECRETis optional; see.env.exampleand the configuration page. The compose file passes it to the frontend service.- The question bank text changed (dashes only). Instances that seeded the bank keep their stored copies; nothing to do.
Run it
git clone https://github.com/Ganek-dev/ganek && cd ganek
docker compose upContainer images: ghcr.io/ganek-dev/ganek-backend:0.4.1 and ghcr.io/ganek-dev/ganek-frontend:0.4.1 (linux/amd64 and linux/arm64).
Docs: the quickstart and the self-hosting guide on ganek.dev; the compliance pack is in docs/compliance/. Try it first at demo.ganek.dev. Hosted version: join the waitlist at ganek.io.
License: AGPL-3.0.
v0.4.0
Fourth release, two days after v0.3.0: the job overview and everything a recruiter needs to see how a posting is doing, plus a public demo that shows it. Thirteen merged branches, two migrations (head 0034), no breaking changes for self-hosters.
Highlights
- Job overview. A job's row now opens an overview, not the editor: lifecycle line (live since, days open, closed after), public URL with Copy and Open, stat tiles, pipeline with stage pills and a candidate table, status and assessment cards, and the quiz preview. The editor moved to
/edit. Counts only: nothing on the page ranks, passes or recommends. - Page views, counted without a tracker. Every public job page load by a person is counted server-side as a daily total per job and source. No cookie, no script, no IP, no user agent, no visitor identifier is stored, and the compliance pack says so. Bots, link prefetches, previews and your own signed-in visits are excluded. The overview shows views (30 days and all time), a daily chart beside applications, an apply rate (from 20 views), and the jobs list shows views per job. Counters are advisory by design; the shared-secret hardening is a later card.
- Where candidates come from. Applications record a source: a tracked link name, a UTM source, a known site such as Google, LinkedIn or Indeed, your own website, another site's domain, or direct. Never the full referring URL. The applicant detail shows it, the overview's Sources table lines views and applications up per source.
- Share this job. Ready-made links per channel (LinkedIn, Indeed, X, newsletter, or a name you type) with Copy; each lands under its own row in Sources. Name links after channels, never after a person.
- Candidate preview for drafts. "View as candidate" and a 7-day preview link render an unpublished job exactly as candidates will see it, with no indexing, no structured data and no apply form.
- Jobs list defaults to Open and keeps the status filter in the URL.
- Demo. The demo workspace now carries sources and 30 days of page views so the overview reads like a live careers page, the candidate-facing demo strip invites visitors to the recruiter side (one-click sign-in on the login page), the README and docs link demo.ganek.dev, and the backend image ships the question bank so an image-only deployment boots with a seeded bank.
- Members see the full overview. The public link and share links no longer depend on an admin-only endpoint.
Upgrade from v0.3.0
- Migrations 0033 (
jobs.closed_at, backfilled for already-closed jobs) and 0034 (job_views) apply automatically ondocker compose up. Back up first:scripts/backup.sh. - No new environment variables.
- The backend Dockerfile now expects the repository root as its build context (
docker build -f backend/Dockerfile .); the compose files already do this. Custom build pipelines need the same change. - Compliance pack:
docs/compliance/README.md, the DPIA template and the self-hosting GDPR guide gained the aggregate page-view sentences and the records-of-processing template names the application source label. If you keep copies, refresh them. - Dashboard "N of M attempts" counts now exclude re-issued (invalidated) attempts, so numbers may shift slightly for workspaces that re-issued quizzes.
Run it
git clone https://github.com/Ganek-dev/ganek && cd ganek
docker compose upContainer images: ghcr.io/ganek-dev/ganek-backend:0.4.0 and ghcr.io/ganek-dev/ganek-frontend:0.4.0 (linux/amd64 and linux/arm64).
Docs: the quickstart and the self-hosting guide on ganek.dev; the compliance pack is in docs/compliance/. Try it first at demo.ganek.dev. Hosted version: join the waitlist at ganek.io.
License: AGPL-3.0.
v0.3.0
Third release, one day after v0.2.0: the work that makes a public demo safe to run, plus the accommodation and audit features that came out of the first week of hardening. Eleven commits, two migrations (head 0032), no breaking changes for self-hosters.
Highlights
- Extra time on the quiz. A recruiter grants 1.5x or 2x per applicant from the integrity review page; the grant is frozen on the attempt like the limit it scales, re-issues carry it forward, and the export shows it. Accessibility first: a 15-second question measures reading speed unless someone can adjust it.
- Who looked at which candidate. A read-access audit trail per applicant (views, CV downloads, exports) and a company-wide access log under Settings with filters and CSV export, for the Art. 30 and Art. 32 accountability story.
- Difficulty calibration from real answers. The question bank now reports how each question actually performs against its difficulty rating, so the next curation pass is data, not opinion.
- Demo workspace, ACME Ganek.
scripts/dev_seed.shbuilds a fictional company with four jobs, 17 applicants and 11 completed quizzes through the real service layer;--resetrebuilds it. Every name, address and link is fictional or points at Ganek's own properties. - Demo mode for a public demo (
GANEK_DEMO_MODE=true). Apply keeps working end to end, but nothing a visitor types or uploads is kept: name, email and links are replaced before the write, the message is dropped, CV upload is refused and a sample PDF is attached, no email leaves the box. Password, two-factor, invites, user admin and Google sign-in answer 403 so the shared login keeps working for the next visitor. The frontend shows a banner, hides the CV field, hands the candidate the assessment link on screen, drops Google Jobs JSON-LD and sets noindex, and the login page offers one-click sign-in as the demo admin. A worker cron (GANEK_DEMO_RESET_SLUG) rebuilds the company nightly at 04:07 UTC.
Upgrade from v0.2.0
- Migrations 0031 (quiz attempt time multiplier) and 0032 (access log) apply automatically on
docker compose up. Back up first:scripts/backup.sh. - New optional environment variables, all documented in
.env.exampleand off by default:GANEK_DEMO_PASSWORD,GANEK_DEMO_RESET_SLUG,GANEK_DEMO_MODE. Never setGANEK_DEMO_MODEon a real workspace. - Public apply now accepts a submission without
cv_object_keyandcv_filenameat the schema level but still answers 422 "CV is required" outside demo mode; API clients see no change.
Run it
git clone https://github.com/Ganek-dev/ganek && cd ganek
docker compose upContainer images: ghcr.io/ganek-dev/ganek-backend:0.3.0 and ghcr.io/ganek-dev/ganek-frontend:0.3.0 (linux/amd64 and linux/arm64).
Docs: the quickstart and the self-hosting guide on ganek.dev; the compliance pack is in docs/compliance/. Hosted version: join the waitlist at ganek.io.
License: AGPL-3.0.
Ganek v0.2.0
Second release: the hardening and integration work that came out of running v0.1.0 for seven weeks. Over 120 commits, seven migrations (head 0030), no breaking changes for self-hosters beyond the upgrade notes below.
Highlights
- Two-factor login with TOTP, recovery codes and "sign out everywhere".
- Proof-of-work captcha (ALTCHA, self-hosted, no third party) on public forms in multi mode.
- Per-tenant abuse guards: active jobs, applications per hour, candidate emails per day, with a usage card and an 80% warning banner. 0 switches a guard off.
- Email you can trust: provider abstraction (SMTP or Mailjet), bounce and complaint webhooks feeding a suppression list, a DKIM/SPF guide, a test send from Settings.
- Operations: deep
/api/health(DB, Redis, S3, worker liveness), compose healthchecks, request ids on every log line and response, JSON logging, optional Sentry viaGANEK_SENTRY_DSN, CDN-friendly immutable logo URLs, backup and erasure-aware restore scripts with a guide. - Integrations: CSV/JSON export of the applicant list, per-company API keys (read or write scope), and outbound webhooks for
application.created,stage.changed,quiz.completedwith HMAC-SHA256 signatures, retries and a delivery log, all from Settings > Developers. Verification snippets in the docs. - Recruiter quality of life: dashboard queue (quiz flags to review, unbooked interviews, drafts without a quiz) with per-user dismissal, display names, a cleaner multi-mode signup with a "what you get" panel and a post-verify landing.
- Question bank: a difficulty recalibration pass (26 mid-band questions re-rated after review), distribution now 1:38 2:56 3:87 4:43 5:1 across 225 questions.
- Docs site (Astro Starlight) built from
docs/and audited in CI.
Upgrade from v0.1.0
- Migrations 0024 to 0030 apply automatically on
docker compose up(themigrateservice). Back up first:scripts/backup.shis new in this release and the guide is in the docs. - The object-storage image moved to
pgsty/minioafter the Docker Hub and quay.io images rotted. Pull the newdocker-compose.ymlor update theminioservice; the bucket and data are unaffected. - New optional environment variables, all documented in
.env.example:GANEK_SENTRY_DSN,GANEK_EMAIL_PROVIDERand the Mailjet keys,GANEK_CAPTCHA_ENABLEDandGANEK_CAPTCHA_SECRET,GANEK_QUOTA_*,GANEK_ENCRYPTION_KEY(recommended: lets you rotate the signing secret without invalidating stored Google tokens and webhook secrets). - Images are now published for linux/amd64 and linux/arm64.
Run it
git clone https://github.com/Ganek-dev/ganek && cd ganek
docker compose upContainer images: ghcr.io/ganek-dev/ganek-backend:0.2.0 and ghcr.io/ganek-dev/ganek-frontend:0.2.0.
Docs: the quickstart and the self-hosting guide on the docs site; the compliance pack is in docs/compliance/. Hosted version: join the waitlist at ganek.io.
License: AGPL-3.0.
Ganek v0.1.0
First public release.
Ganek is an open-source careers page with skill screening built in: every applicant can take a short, timed quiz, and you interview the ones who show they know the material. The quiz decides who you talk to; the conversation verifies.
Highlights
- Careers page + apply flow you can self-host and brand, SSR with Google Jobs JSON-LD.
- Timed screening quizzes from a curated YAML question bank (difficulty 1-5), server-side timing and scoring, per-tag breakdowns, question pools or hand-built questionnaires.
- Integrity signals, not surveillance: three event types (focus lost, paste, window resize), fully disclosed to candidates before the attempt, informational only. No webcam, no keystrokes, no IP in telemetry.
- Human decisions only: no auto-reject, no auto-advance, no ML anywhere - a deliberate product boundary.
- A full recruiting pipeline: applicant review, notes, stages, bulk actions, team roles, Google Calendar interview scheduling with live availability.
- GDPR-ready by design: per-company privacy notices, retention purge with no off switch, one-click erasure, DSAR export, candidate request routes, and a complete compliance pack in
docs/compliance/.
Run it
git clone https://github.com/Ganek-dev/ganek && cd ganek
docker compose upContainer images: ghcr.io/ganek-dev/ganek-backend:0.1.0 and ghcr.io/ganek-dev/ganek-frontend:0.1.0.
See the README for the quickstart and production hardening checklist. Hosted version: join the waitlist at ganek.io.
License: AGPL-3.0.