Data retention schedule
Last reviewed 20 October 2026 · Next scheduled review 29 July 2027
Controller of record: Mentum. Contact: privacy@mentumjobs.com (data protection), dpo@mentumjobs.com (privacy contact, no Data Protection Officer is designated), security@mentumjobs.com (security reports), support@mentumjobs.com (operational).
Anchors: Privacy Policy, Terms of Service, Data Processing Agreement, Sub-processor list, Acceptable Use Policy, Service Level Agreement, Cookie Policy.
Launch notification list
We delete unconfirmed launch email addresses after 7 days, all entries after 6 months from joining, and entries 30 days after we send the launch email, whichever is sooner. You can remove your address using the link in either email or ask privacy@mentumjobs.com to erase it. Joining the list does not create an account, and we do not use it for other marketing.
This Data Retention Schedule is Mentum's published statement of how long each category of personal data is kept, what event starts the retention clock, and how the data is destroyed at the end of its period. It is the operational counterpart to the Privacy Policy: the Privacy Policy explains what Mentum processes and why. This Schedule sets the how long and how it ends.
1. Purpose and scope
1.1 Purpose
This Schedule discharges Mentum's obligation under UK GDPR Article 13(2)(a) to inform data subjects of “the period for which the personal data will be stored, or if that is not possible, the criteria used to determine that period”. It also operationalises Article 5(1)(e) (storage limitation) by binding every personal-data category to a defined retention period, deletion trigger, and destruction mechanism.
1.2 What this document is not
- It is not the Privacy Policy. The Privacy Policy is the canonical disclosure of lawful bases, data categories, recipients, transfers, and data-subject rights. This Schedule presupposes that policy and goes deeper on retention only.
- It is not the Data Processing Agreement. The DPA governs the contractual processor terms between Mentum and its paying customers. This Schedule describes Mentum's controller-side practice.
- It is not Mentum's internal Records of Processing Activities (ROPA). ROPA is the Article 30 record and goes wider (lawful bases, recipients, transfers) and shallower (no per-table cron timing). Where this Schedule and ROPA disagree, this Schedule is authoritative for retention timing and ROPA is corrected at its next review.
1.3 How to read this alongside the Privacy Policy
- The Privacy Policy gives the summary retention statements that a candidate or employer can read in two minutes.
- This Schedule gives the per-table retention statements that a DPO or auditor can verify against the code and migrations.
2. Lawful basis recap
Mentum's processing rests on the following Article 6 bases (see Privacy Policy § 3 for the full mapping):
- Article 6(1)(b), Contract. Account creation, matching, chat, interview booking, employer search of candidate profiles, adviser conversations for candidates who have opted in. This is the lawful basis for the majority of retention rows below.
- Article 6(1)(a), Consent. Marketing communications, AI-feature opt-in, and cookie categories beyond strictly necessary. Consent records themselves carry a statutory retention period (see § 9).
- Article 6(1)(f), Legitimate interests. Security telemetry, application audit logs, abuse prevention. Balancing-test outcomes are recorded in Mentum's internal ROPA.
- Article 6(1)(c), Legal obligation. Consent retention under UK GDPR Article 7(1) and Article 17(3)(e). Breach-register retention under Article 33, PECR record-keeping. See § 9.
3. Two retention concepts you'll see in this document
This Schedule uses two distinct end-of-life mechanisms, and the distinction matters.
3.1 Deletion
The row is physically removed from the database. After the daily retention sweep, a hard DELETE (or a chain of foreign-key-cascading deletes) takes the data out of the live system. The only residual copy is in Supabase's encrypted, time-limited backup window (see § 10). Most rows on this Schedule are deleted at end-of-life.
3.2 Pseudonymisation
The row is preserved, but the identifying columns are nulled or replaced with the literal token [Removed]. The remaining row preserves relationships, employer records and statistics. It can still be linked back to the person. Two specific cases use pseudonymisation rather than deletion:
- The 36-month inactivity sweep on candidate profiles. A candidate who has not logged in for 36 months has their personal identifiers blanked from
candidate_profilewhile structural columns are retained for aggregate analytics. - Chat messages after a match closes. Closed-match chat content is replaced with a retention notice. The surrounding metadata (sender, timestamp, match reference) is preserved for employer-side recordkeeping.
In both cases the row is still personal data under UK GDPR, because it can still be linked back to the person, so your rights still apply to it. Full removal happens when you delete your account (§ 8).
4. Retention schedule for candidate data
The following table is the authoritative per-category retention schedule for personal data Mentum processes about candidates. Underlying table names are shown in code font after the plain-English category name for auditor cross-reference.
| Data category | Retention period | Deletion trigger | Destruction mechanism |
|---|---|---|---|
Active candidate account (candidate_profile) | While account active. 24 months of login inactivity → deactivation, 36 months → pseudonymisation (identifiers nulled to [Removed]) | Last login, or account creation if there has been no login, older than the threshold | pg_cron @ 04:15 UTC via run_retention_cleanup() |
| CV file storage | Until account deletion or the 36-month pseudonymisation sweep | User-triggered erasure or 36-month inactivity sweep | Synchronous on DELETE /api/auth/account. On the 36-month path the 04:15 UTC retention-cleanup-daily job nulls cv_url and enqueues the storage object paths into pending_storage_purge. The 05:00 UTC retention-storage-purge-daily job then deletes the actual storage bytes (a two-step flow, not a standalone Python sweeper) |
| Profile photo | Until account deletion, explicit user deletion or the 36-month inactivity sweep | User-triggered erasure, clearing the photo in profile settings or the 36-month inactivity sweep | Synchronous on DELETE /api/auth/account or explicit photo deletion removes the file. The 36-month sweep queues the file before clearing the photo link, and the 05:00 UTC storage-purge job deletes the bytes |
Chat message content (chat_message.content) | 12 months after the parent match enters a closed status, 36 months absolute outer bound regardless of status | Closed match status or absolute age over 36 months | Pseudonymisation (row preserved, content replaced with a retention notice, with sender, timestamp and match reference preserved), pg_cron @ 04:15 UTC |
| Chat attachments | Aligned with message content, purged when the closed-match window elapses | Closed match + 12-month window | Two steps, like CV files: the retention sweep pg_cron @ 04:15 UTC clears the attachment metadata and queues the storage object. The bytes are deleted from the bucket by the storage-purge job at 05:00 UTC the same morning. |
AI match explanations and ratings, summaries, feedback (match_ai_score, match_ai_summary, match_ai_positive_feedback, match_ai_negative_feedback, match_stats) | Lifetime of the underlying job posting | Parent job deleted at 6 months inactive with no active matches or user erasure | pg_cron @ 04:15 UTC FK-cascading delete or synchronous on DELETE /api/auth/account |
Enhanced career insights (match_enhanced_insights) | Lifetime of the parent match | Same as match explanations above | Same as match explanations above |
Adviser conversations (advisor_conversation) | 24 months after the conversation is marked inactive (fixed in the scheduled job run_retention_cleanup()) | is_active = false and age over threshold or user erasure | pg_cron @ 04:15 UTC via run_retention_cleanup() |
Career-trajectory cache (career_trajectory_cache) | Until account deletion. After 7 days the saved content is treated as out of date and rewritten the next time you ask for it. | You ask again, or you delete your account. | Rewritten on the next request and deleted with your account. There's no time-based deletion. |
| Notifications, read | 6 months | is_read = true and age over 6 months | pg_cron @ 04:15 UTC |
| Notifications, unread | 12 months | is_read = false and age over 12 months | pg_cron @ 04:15 UTC |
| Notification preferences | Until account deletion | User-triggered erasure | Synchronous on DELETE /api/auth/account |
| Push subscriptions | Until user opt-out or account deletion | User opt-out via app settings or user erasure | Synchronous on user action or DELETE /api/auth/account |
Behaviour events (candidate_behaviour_event) | 6 months (fixed in the scheduled job run_retention_cleanup()) | Age over threshold | pg_cron @ 04:15 UTC |
Eligibility declarations (candidate_requirement_status), your self-declared answers to a role's licence, clearance, professional-registration, qualification and shift-availability requirements. Also the suggestions we make when a CV you saved mentions a licence, registration or check (candidate_requirement_suggestion), with your yes or no to each: a suggestion is not an answer, and nothing uses it until you say yes | Until account deletion. Any single answer can be cleared back to unanswered at any time, which deletes that row immediately. A ready-by or renewal date you add stays only with the answer it was given for. A suggestion, and your yes or no to it, is kept for the same time, so that one you turned down is not made again. Answers, dates and suggestions are included in the Art. 20 data export, with the suggestions listed apart from the answers. | User-triggered erasure or the candidate clearing an individual answer | Synchronous on DELETE /api/auth/account via the delete_candidate_account RPC |
| Saved matches, bookmarks, blocked companies, question answers, skills, experience, education, interests, accessibility preferences, availability (all candidate-owned rows) | Until account deletion | User-triggered erasure | Synchronous on DELETE /api/auth/account via the delete_candidate_account RPC |
Match details rows (match_details) | Lifetime of the parent job, anonymised rather than deleted on candidate erasure. The candidate identifier is set to NULL while the row is preserved for the employer's recordkeeping (employment-law defensibility) | Parent job purged at 6 months inactive + no active matches or user erasure | pg_cron @ 04:15 UTC FK cascade (job-deletion path) or synchronous FK NULL on erasure |
Interview scorecards (interview_stage_feedback, stage_feedback_score), the employer's per-stage rubric scores, hire recommendation, free-text notes, strengths and concerns, and the optional note the employer chooses to share with the candidate | Structured scores follow the parent match. Free-text notes, strengths, concerns and candidate feedback become due for clearing 6 months after both the hiring process for that job ends and the job closes, measured from the later event. The job must still be inactive. Ordinary job edits do not reset a recorded closure date | Parent match record deleted on the job purge in § 5, or the employer deletes the scorecard, or the scoring staff member's account is deleted | A separate nightly process clears settled free text in capped batches. Parent deletion and the existing erasure/inactive-subject controls can act sooner. A backlog can delay the nightly pass |
Staged CV re-upload (candidate_cv_staging), including raw CV text and extracted fields while you review them | 7 days | The staged upload is older than 7 days, or you delete your account | cleanup-cv-staging at 04:25 UTC daily, or deletion with the account |
Precomputed fit scores (candidate_job_match_score) | While the job is active, then 7 days from its last update, or creation if it has never been updated | The job has been inactive for at least 7 days, or you delete your account | cjms-inactive-job-purge-daily at 04:45 UTC, up to 500,000 rows per run. Job deletion removes any remainder |
Uploads not yet attached (candidate_storage_upload) | 15 minutes for a pending upload, or 1 hour for a chat attachment | The upload is still pending when its expiry time passes, or you delete your account | expire-pending-candidate-uploads every 15 minutes expires up to 500 rows and queues their files for the 05:00 UTC storage purge |
Issued offer letters and signature evidence (match_offer) | Until candidate erasure, deletion of the parent match or company, or the 36-month inactive-subject clean-up | The candidate link is removed, the parent is deleted, or the candidate is inactive and has not logged in for 36 months, measured from creation if there has been no login | Clears copied letter text, version and hash, signer name, signing time, IP address, user agent and signature hash. Offer terms and response statistics remain |
Optional equality answers and profile linkage (candidate_equality_monitoring,candidate_profile.equality_monitoring_token) | 24 months from the last save. Withdrawal, account erasure or the 36-month inactive-subject clean-up can remove them sooner | Answer expiry, withdrawal of consent, account erasure or the inactive-subject clean-up | Deletes answers. Withdrawal and erasure clear the private profile token immediately, and the inactive-subject clean-up clears it too |
Outbound webhook delivery records (company_webhook_delivery) | Delivered records expire 30 days after completion. Every state has an absolute limit of 90 days from creation | The first age limit reached, candidate unlinking, parent deletion or the 36-month inactive-subject clean-up | A bounded daily sweep deletes up to 5,000 records. Unlinking also deletes them immediately. Copies already received by an employer follow its retention controls |
Headline read
- Many records remain until account deletion. The 24-month deactivation and 36-month pseudonymisation sweeps do not erase every child record. For a profile that has never logged in, account creation starts the inactivity clock. There is no general timed deletion of profile-less auth accounts or draft jobs.
- The two pseudonymisation points are deliberate. The 36-month sweep is the inactivity floor. Closed-match chat is the per-match floor. Both are explicit choices rather than incomplete deletion logic.
- The
match_detailsrow is the only “preserved-but-anonymised” employer-facing artefact is preserved because deleting it would corrupt the employer's hiring record. The candidate identifier is removed. The row remains as a hiring-decision record under employment law. - An account that was never completed is removed on an event, not a clock. Choosing “Log in with Google” on the login page without a Mentum account leaves a login record that holds nothing but the email address, has no role and no profile, and cannot be used. Signing up by email with the same address deletes that record before the new account is created. It is not a sweep: a record nobody signs up over is retained until then.
5. Retention schedule for employer and job data
| Data category | Retention period | Deletion trigger | Destruction mechanism |
|---|---|---|---|
Active employer account (company_profile) | While account active. No inactivity timer. Deleted only on user-triggered erasure | User-triggered erasure | Synchronous on DELETE /api/auth/account via the delete_employer_account RPC |
Employer calendar connection (user_calendar_connection), an employer staff user's calendar authorisation, held only as encrypted ciphertext, with the granted scopes and the calendar identifier | While the connection is live. A revoked connection keeps its credential-free metadata for 90 days. Revocation itself wipes both encrypted token columns immediately | Disconnect, a terminal authorisation failure, or account erasure (all wipe the encrypted tokens immediately), then 90 days from revocation for the metadata row | Immediate wipe on revoke, pg_cron @ 04:15 UTC via run_retention_cleanup() (bounded to 1,000 rows a night), FK cascade when the staff account is deleted |
Calendar mirror delivery records (calendar_sync_outbox), per-booking sync intents and their external calendar event identifiers. No candidate identifier and no names | 90 days after the intent reaches a terminal state, and only once the linked interview ended over 90 days ago or the booking link has been erased. Queued, retrying and processing intents, and any intent whose booking still has pending work, are never swept | Terminal state + 90-day age + the interview ended or the booking link erased | pg_cron @ 04:15 UTC via run_retention_cleanup() (the same bounded call), FK cascade when the connection or the staff account is deleted |
| Employer-posted job, active state | While is_active = true. Auto-deactivated at 90 days from posted_on if there are no active matches | 90-day age + no active matches | pg_cron @ 04:15 UTC flips is_active = false, bounded to 5,000 jobs a night so a larger cohort drains over the following nights. Pre-launch carve-out: the frozen pre-launch Adzuna job corpus is intentionally retained for matching development and is not subject to the 90-day deactivation until launch. |
| Employer-posted job, inactive state | 6 months after the last update to the row (falling back to the creation date where a row was never updated), provided no active matches remain | is_active = false for over 6 months, no active matches, and the job is not classified as hiring outside the UK. That last condition is a deliberate exemption: a job classified as foreign keeps its row so the country classification and the cross-source duplicate identity are retained. The comparison treats an unresolved or unset classification as not foreign | pg_cron @ 04:15 UTC hard-delete with full match-tree FK cascade |
| Feed-sourced job, inactive state, untouched by any user | 7 days after the last update to the row. A feed job any user has interacted with (a match, a saved or watched job, an employer claim) keeps the 6-month clock above | is_active = false for over 7 days, feed-sourced, no match, saved, watched or claim row, and not classified as hiring outside the UK. The same shared exemption applies as in the row above | pg_cron @ 04:15 UTC hard-delete with full FK cascade (15,000-job nightly cap) |
| Adzuna inbound job description text | 30 days after posted_on once the parent job is inactive | Inactive Adzuna job + 30-day age threshold | pg_cron @ 04:15 UTC updates description text to NULL. The parent row is preserved |
| Job ingestion queue, processed | 7 days | Processed status + age over 7 days | pg_cron @ 04:15 UTC |
| Job ingestion queue, failed | 30 days | Failed status + age over 30 days | pg_cron @ 04:15 UTC |
Skill processing log (skillprocessinglog) | 30 days | Age over 30 days | pg_cron @ 04:15 UTC |
Market snapshot (market_snapshot) | 12 months | Age over threshold | pg_cron @ 04:15 UTC |
Skill metrics history (skill_metrics_history) | 6 months | Age over threshold | pg_cron @ 04:15 UTC |
Skill trend (skill_trend) | 6 months | Age over threshold | pg_cron @ 04:15 UTC |
Employer analytics snapshot (employer_analytics_snapshot) | 24 months | Age over threshold | pg_cron @ 04:15 UTC |
Salary benchmark cache (salary_benchmark_cache) | 12 months | Age over threshold | pg_cron @ 04:15 UTC |
Company intelligence cache (company_intelligence_cache) | 12 months | Age over threshold | pg_cron @ 04:15 UTC |
Company intelligence history (company_intelligence_history) | 52 weeks | Age over threshold | Weekly snapshot job @ 04:30 UTC Sundays |
Salary benchmark history (salary_benchmark_history) | 52 weeks | Age over threshold | Weekly snapshot job @ 04:30 UTC Sundays |
Regional market snapshot (regional_market_snapshot) | 180 days | Age over threshold | Daily capture job @ 03:15 UTC |
Employer check records
An employer's right-to-work and DBS records become due for deletion 6 months after the hiring process for that job ends, whether or not the job itself is deleted. A passed right-to-work check with an expiry date is kept until 30 days after that date if this is later than the 6-month date. Earlier erasure and parent deletion can remove the records sooner.
If the employer used an online share code, we delete it as soon as they settle the check, and a code that's never settled is deleted after 30 days, measured from the check date or the last update if no check date was recorded. Our nightly clean-up works in batches, so deletion can happen after the due date. Employers keep their own legal evidence of the check outside Mentum.
Headline read
- Employer accounts have no inactivity timer. Unlike candidate accounts, an employer account remains live until the user actively deletes it. This is deliberate: long-running employer relationships are a normal commercial pattern.
- Jobs go through three states with three clocks. Active (90 days posted with no matches), then inactive (6 months for hard delete, measured from the last update to the row and falling back to its creation date where it was never updated), with Adzuna-sourced descriptions further accelerated to a 30-day text NULLification once the parent goes inactive.
- Analytics tables intentionally outlive jobs. 6-to-24-month windows for market and skill analytics support employer dashboards that compare period-over-period. They hold aggregated analytics, not candidate-attributable data.
6. Retention schedule for operational and audit data
These tables matter less to a typical end user but are the artefacts auditors and DPOs ask about during procurement.
| Data category | Retention period | Deletion trigger | Destruction mechanism |
|---|---|---|---|
Data access log (data_access_log), every employer→candidate PII access | 24 months (fixed in the scheduled job run_retention_cleanup()) | Age over threshold | pg_cron @ 04:15 UTC via run_retention_cleanup() |
Security events (security_events) | 12 months (fixed in the scheduled job run_retention_cleanup()) | Age over threshold | pg_cron @ 04:15 UTC |
Candidate abuse-control events (candidate_abuse_control_event), one row per admission decision taken by the candidate abuse and rate controls: the event type, the outcome (allowed, denied or observed), a hashed IP prefix and device hash, a small detail object, and the candidate, account and match where known | 90 days, measured on the event date | Age over 90 days | A separate pg_cron @ 04:37 UTC job outside run_retention_cleanup(). Each run deletes at most 10,000 rows, so a backlog drains over the following nights. Ahead of the clock: FK cascade when the candidate profile or the match is deleted, and the account reference is set to NULL when the account is deleted |
Application audit (audit_errors, audit_runs) | 12 months (fixed in the scheduled job run_retention_cleanup()) | Age over threshold | pg_cron @ 04:15 UTC |
Pipeline run log (pipeline_run_log) | 6 months | Age over threshold | pg_cron @ 04:15 UTC |
LLM usage log (gemini_usage_log), cost and token attribution | 90 days (the permanent record is a per-day aggregate with no per-user attribution) | Age over threshold | pg_cron @ 04:15 UTC |
Email send log (email_send_log) | 12 months | Age over threshold | Separate pg_cron @ 04:20 UTC (email-send-log-retention-nightly) and the main retention cron |
Push send log (push_send_log) | 6 months | Age over threshold | pg_cron @ 04:15 UTC |
Email unsubscribe tokens (email_unsubscribe_token) | 30 days | Age over threshold | pg_cron @ 04:15 UTC |
Employer board event feed (kanban_board_event), tells an open employer browser to refetch. Company, job and match references plus an optional staff actor reference, no candidate identifier and no free text | 24 hours | Age over 24 hours | pg_cron @ 04:15 UTC via run_retention_cleanup(), bounded to 5,000 rows a night so a backlog drains over the following nights |
Cron health log (cron_health_log), clipped-run monitor | 90 days | Age over threshold | pg_cron every 30 min via detect_clipped_cron_runs() |
Consent records (user_consent), statutory carve-out | 7 years (84 months) | Age over threshold (survives account deletion) | pg_cron @ 04:15 UTC, see § 9.1 |
Breach register (breach_register), statutory carve-out | Indefinite | None, retained for Art. 33 record-keeping | No automated purge, see § 9.2 |
| Asynchronous task store (Redis) | 10 minutes | TTL | Redis-managed TTL expiry |
| Idempotency-Key store (Redis) | 24 hours | TTL | Redis-managed TTL expiry |
| Rate-limit keys (Redis) | 24-hour sliding window + 2-hour slack | TTL | Redis-managed TTL expiry |
Headline read
- Operational logs run on three-band retention. Security and access logs hold the longest (12–24 months). Pipeline logs hold mid-term (6 months) and the raw LLM-cost log short-mid-term (90 days, with a permanent non-attributable daily aggregate). Transactional Redis state holds short-term (minutes to a day).
- Email send-log retention is enforced twice. A standalone 04:20 UTC cron supplements the main 04:15 UTC retention sweep. It is kept as a separate job so the email log's deletion can be checked on its own. Both jobs are idempotent.
- Consent records and the breach register survive account deletion. These are spelled out below.
7. AI-generated artefacts
Mentum applies data-minimisation controls at the boundary with its LLM providers: OpenAI for the standard AI workloads (gpt-6-luna) and for the eight premium response surfaces (gpt-5.6-luna), and Google Gemini for embeddings, skill estimation, reading scanned CV files where that fallback is switched on, and as the standard-route fallback. The data flowing outbound varies by feature:
- CV parsing and CV optimisation are the two paths where name-bearing CV text is sent to an LLM provider, because the name appears in the CV body. Both go to OpenAI. A scanned, image-only PDF is first transcribed by Google Gemini, as uploaded, where that fallback is switched on. On the parsing path National Insurance numbers, dates of birth and postal addresses are stripped before the call. On the optimisation path they are not, because redacting them would corrupt the rewritten CV the candidate asked for. Parsed CV data is persisted to structured fields on
candidate_profile. - Match explanations, skill estimation and culture-fit run on the standard route (OpenAI, except skill estimation, which runs on Google Gemini) and strip the candidate name before fan-out: the provider sees structured profile data without the identifier.
- Enhanced insights, career trajectory, adviser conversations, Career Compass and interview practice run on OpenAI's premium route with the same minimisation (name omitted, high-risk personal data stripped).
AI-generated outputs, including match explanations, insights, adviser transcripts and trajectory caches, are subject to the candidate-side retention rows in § 4. There is no Mentum-side provider persistence beyond those rows. On the Google side, the Google Cloud Data Processing Agreement is in effect for the paid Gemini API Mentum uses (see the sub-processor list). OpenAI doesn't use our API data to train its models, and we haven't opted in to that. We ask OpenAI not to store responses, but it may still keep some data for a limited time under its own terms, so we don't claim it keeps nothing. OpenAI's data processing agreement and transfer terms for our production account will be in place before real candidate data is sent to it. Batch API files for job-description extraction contain listing text, not candidate data, and are deleted when the batch settles, with a 7-day provider-side expiry as the backstop.
8. User-triggered erasure (UK GDPR Art. 17)
A candidate or employer who wishes to exercise the right to erasure (“right to be forgotten”) under UK GDPR Article 17 does so by deleting their account in their app settings, which calls DELETE /api/auth/account.
8.1 What happens synchronously
When the deletion request is accepted (after explicit in-app confirmation), the request handler executes the role-appropriate RPC (delete_candidate_account or delete_employer_account) within the same HTTP request, before the 2xx response is returned. The RPC performs:
- Hard delete of all candidate-owned PII rows, including profile, skills, experience, education, interests, question answers, saved matches, bookmarks, blocked companies, notifications, notification preferences, push subscriptions, accessibility preferences, availability records, and the related child rows.
- Storage-bucket purge removes the CV file and profile photo from object storage.
- Auth account deletion removes the underlying authentication user row, which propagates as a SET NULL or cascade to every other table holding the foreign key.
- FK-cascading behaviour for match-history rows means
match_detailsrows have the candidate identifier set to NULL rather than being deleted, so the employer's hiring record remains structurally intact while the candidate is no longer attributable. Chat messages are scrubbed (content replaced with a deletion notice, with sender and timestamp preserved).
8.2 What does not happen synchronously
- Backup retention. Supabase's point-in-time recovery keeps an encrypted snapshot and a continuous record of changes for 7 days. Deleted rows remain in that recovery window until it expires. There is no separate daily database-backup window while this is on. Mentum has no operational access to the backup contents and does not restore backups except in a documented disaster-recovery scenario (see § 10).
- Statutory carve-outs. Consent records (Art. 7(1) and Art. 17(3)(e)) and breach-register entries (Art. 33) survive account deletion. See § 9.
8.3 Cross-reference
For the procedural detail on exercising any data-subject right (verification, response times, complaint route), see Privacy Policy § 11.
9. Statutory retention carve-outs
Two categories survive account deletion because UK GDPR or PECR requires it.
9.1 Consent records
Retention: 7 years (84 months). Survives account deletion under UK GDPR Article 17(3)(e) (processing necessary for the establishment, exercise or defence of legal claims) read with Article 7(1) (the controller's burden to demonstrate that consent was given). The 7-year window aligns with the UK limitation period for contract and tort claims under the Limitation Act 1980.
Practical effect: even after a candidate or employer deletes their account, Mentum keeps an attenuated record showing which consent was given, at what time, for what purpose, and when it was withdrawn. The record does not include the substantive personal data the user has erased. It is a metadata receipt.
9.2 Breach register
Retention: indefinite. Retained under UK GDPR Article 33(5). The Article 33 record-keeping obligation has no defined expiry, and the supervisory authority (ICO) may request the historical record at any time during an investigation. The breach register contains incident metadata only. It does not store the affected data subjects' personal data beyond pseudonymised counts and category labels.
9.3 Other carve-outs
- Security telemetry retained for legitimate interest (
security_events,data_access_log), see § 6. These are not consent-based and are retained for the duration described regardless of any deletion request, on the legitimate-interest basis (Art. 6(1)(f)) of operating a secure platform. The Art. 21 right to object is balanced against Mentum's documented legitimate interest. - Application audit logs (
audit_errors,audit_runs) are retained for the 12-month window described in § 6 on the same legitimate-interest basis.
10. Backup retention
10.1 Backup window
The production database is backed up by Supabase's Point-in-Time Recovery: a daily encrypted snapshot plus a continuous record of changes, kept for 7 days, so the database can be restored to any moment in that window. Uploaded files (CVs, photos and documents) are not included in that backup. A nightly copy of each uploaded file is kept in a separate encrypted storage bucket for 7 days.
10.2 What this means for an Art. 17 request
A data subject who has exercised the right to erasure will see their data removed from the live database within the same HTTP request (see § 8). The data continues to exist within the encrypted backup window for up to 7 calendar days, at which point the natural rotation removes the backup copy. The same 7-day window applies to the nightly file copies: an erased file leaves every backup within 7 calendar days of being deleted from live storage.
Mentum does not perform partial restores or surgical edits to backup contents because the operational shape of the backup system does not support row-level intervention. If a backup is restored as part of a disaster-recovery event, Mentum will re-run the retention process immediately after the restore so that prior erasure requests are re-applied.
10.3 Recovery targets
Mentum's Service Level Agreement states the following recovery targets, which haven't yet been tested with a full restore drill:
- Recovery Point Objective (RPO): ≤ 5 minutes (PITR Write-Ahead Log window).
- Recovery Time Objective (RTO): ≤ 4 hours for the database tier.
- Storage RTO: ≤ 8 hours for a service outage. A deleted or lost file can be restored from the nightly copy, losing at most a day of changes.
11. How retention is enforced
11.1 Automation
All time-based retention in this Schedule is enforced by pg_cron jobs running in the production database. There is no human review step. The relevant jobs:
retention-cleanup-dailyat 04:15 UTC daily runs the masterrun_retention_cleanup()PL/pgSQL function which executes every cleanup case in §§ 4, 5, and 6 except the standalone jobs listed below. All cases run in one transaction, so an error in any one case undoes that night's whole sweep, and the next night's run repeats it.retention-storage-purge-dailyat 05:00 UTC daily drains thepending_storage_purgequeue (populated by the 04:15 job when it nullscv_url) and deletes the actual storage bytes. Runs viapg_net→POST /api/internal/cron/run-retention-storage-purge. The 04:15 job enqueues the object paths. This job removes the files, so CV-file destruction is a two-step flow, not a standalone Python sweeper.email-send-log-retention-nightlyat 04:20 UTC daily is a standalone job foremail_send_logdeletion, kept as a separate job so the email log's deletion can be checked on its own.purge-candidate-abuse-eventsat 04:37 UTC daily runs a standalone 90-day sweep ofcandidate_abuse_control_event(§ 6), bounded to 10,000 rows a run. The minute is chosen so it does not contend with the employer-analytics snapshot that runs at 04:35.detect-clipped-cron-runsevery 30 minutes is an internal health monitor that flags any cron job whose runtime was clipped by Supabase's 120-second platform default. Writes tocron_health_log(90-day retention per § 6) and surfaces in the on-call alerts.cleanup-cv-stagingat 04:25 UTC daily. Deletes staged CV uploads after 7 days.cjms-inactive-job-purge-dailyat 04:45 UTC daily. Deletes precomputed fit scores for jobs inactive for at least 7 days, up to 500,000 rows per run.expire-pending-candidate-uploadsevery 15 minutes. Expires unattached uploads past their window and queues their files for deletion.purge_settled_hiring_recordsat 04:52 UTC daily. Enforces the employer-check and interview free-text clocks in sections 4 and 5 in capped batches.- Hiring-detail clean-up in the 04:15 UTC sweep. Clears eligible offer and signature evidence, equality answers and their private token, and webhook delivery records. The sweep also removes expired equality answers and webhook deliveries.
11.2 Configurability
The scheduled clean-ups can't be changed by configuration. Each period is written into the code and changes only through a reviewed code change. Only the short-lived Redis timers in § 6, the career-trajectory refresh window and the 7-day file-backup window shown here are read from configuration.
11.3 Trigger types
Two trigger types govern retention:
- Date-based. For “Age over 12 months”, the row's
created_ator equivalent column is compared againstnow() - interval '12 months'within the cron-driven RPC. Most rows in §§ 5 and 6 fall here. - State-based. “Closed match status” or
is_active = falsemeans the row's status column drives the clock, not the calendar. Chat-message pseudonymisation and job-deletion paths fall here.
The 24-month and 36-month candidate-profile inactivity clocks start from the last login, or from the date the account was created if the person has never logged in. Active users have no time-based deletion of their profile.
11.4 Monitoring trail
The sweep doesn't yet keep its own record of what it deleted. The scheduler records that each job ran, its status and how long it took, and a check every 30 minutes flags any run cut short by the platform time limit.
12. Changes to this schedule
Mentum updates this Schedule on an annual cadence (the Next scheduled review date at the top of this page) and off-cycle on any material code change to the retention RPCs, pg_cron schedules, or deletion paths.
- Material changes to a retention period, category or deletion trigger are notified to data subjects via the Privacy Policy banner and reflected in the Last reviewed date on this page.
- Editorial changes, such as clarifications, link updates and formatting fixes, do not trigger re-notification. The Last reviewed date is still bumped so the audit trail is unambiguous.
Data subjects or customers who require a historical version of any prior period of this Schedule may write to privacy@mentumjobs.com and we will provide the relevant prior version.
13. Contact and complaints
For questions or complaints about Mentum's retention practice:
- Privacy contact: dpo@mentumjobs.com and privacy@mentumjobs.com
- Security reports: security@mentumjobs.com
- Operational support: support@mentumjobs.com
If you are not satisfied with Mentum's response, you have the right to lodge a complaint with the Information Commissioner's Office (ICO):
- Website: ico.org.uk/make-a-complaint
- Telephone: 0303 123 1113
- Postal: Information Commissioner's Office, Wycliffe House, Water Lane, Wilmslow, Cheshire SK9 5AF
You may also lodge a complaint with the data-protection supervisory authority of your habitual residence or place of work within the UK or EEA.
Related: Privacy Policy | Terms of Service | Data Processing Agreement | Sub-processors | Service Level Agreement | Cookie Policy