v3.24.2 – ATS Engine Rebuild, Claims Accuracy Audit, Account Deletion & Legal Remediation
LatestThis patch release rebuilds the ATS parsing engine, adds self-service account deletion, and remediates a full audit of every public claim on the marketing site against the code that has to honour it.
The audit found 90 defects. Marketing promised features that did not exist, the security page asserted guarantees the repository could not support, and the legal pages had structural gaps. All of it is now either true, labelled as forthcoming, or gone.
32 commits · 512 files · v3.24.1 → v3.24.2
⚠️ Breaking
Free trials are removed from every plan. Creator Pro monthly previously applied an automatic 7-day trial for first-time subscribers — narrower than the Terms described, which also claimed one for the Job Hunter Bundle. No plan now carries a trial, and TRIALING has been removed from the SubscriptionStatus enum with an accompanying Prisma migration.
No subscription was ever created under the trial, so no existing records are affected. One case "trialing" remains in the provider status mapping by design: we control what we request, not what the payment provider's webhooks send, and mapping it to ACTIVE fails safe for anyone who somehow holds one.
🔒 Security
DELETE /users/mewas reachable with any API key holdinguser:write— the same scope required to rename an account. That put a long-lived integration token, including one pasted into an unrelated third-party tool, one call away from irreversibly destroying every document, portfolio, credit, and payout record on an account. Account deletion is now session-only, enforced by a newdenyApiKeyAuthmiddleware and covered by a test verified against the guard being removed.- Published portfolio snapshots now record the server's own watermark decision.
removeWatermarkarrived inside the client-supplied content payload and was persisted verbatim, never checked against thewatermark_removalentitlement. - Contact form logging no longer records submitter identity. It logged name, email, and subject, exceeding the server-log contents the Privacy Policy discloses.
- The security page no longer asserts what the repository cannot prove. Removed: LocalStorage encryption (the studio writes plaintext JSON), AES-256 at rest, TLS 1.3 specifically, zero logging, cryptographic purge, WASM/Canvas rendering (exports use
@react-pdf/renderer), a GitHub OAuth scope string for scopes never configured, and a PGP key that was never published. A stated but unsupported security guarantee is worse than no claim. - Removed the advertised bug bounty and "24h SLA Guarantee", neither of which existed, and added a safe-harbour clause so good-faith researchers have stated authorisation. Previously researchers had no assurance and real exposure under computer-misuse law.
✨ Added
ATS engine
AtsResumeParseServicewith bounding-box layout detection, identifying multi-column resumes and ruled table grids that scramble extraction order- Worker-based PDF and DOCX extraction via
ExtractPool, with contact extraction, section segmentation, and keyword tokenization - A separate, more generous extraction quota (3 anonymous / 6 free / 300 paid) so uploading a file no longer consumes a scan — previously an anonymous visitor spent their only 48-hour scan just by uploading
ParsedViewexposing the raw parsed stream, detected sections, and the linear reading flow the engine actually sees
Account deletion
- Self-service deletion from the Studio profile page, with a Danger Zone card and a type-your-email confirmation modal listing exactly what is destroyed
denyApiKeyAuthmiddleware restricting irreversible whole-account actions to session-authenticated first-party requests
Legal
- Notice-and-takedown section with a reporting address, required notice contents, acknowledgement and decision timelines, a counter-notice route, and a repeat-infringer policy. The enforcement machinery already existed; only the policy was missing.
- A named Grievance Officer and Data Protection Contact, with dedicated email and postal address, published in both the Terms and the Privacy Policy
- A complete subprocessor table naming every third party, what personal data each receives, its processing region, and the transfer mechanism relied on
- Breach-notification commitment, concrete retention periods, and the right to complain to a supervisory authority
TRADEMARK.md,LICENSING.md, a DCO sign-off requirement inCONTRIBUTING.md, and a safe-harbour clause inSECURITY.md
Accessibility and discovery
- Skip-to-content link in
AppShell, satisfying WCAG 2.4.1 Bypass Blocks (Level A), which had no implementation anywhere in the app Personentity in JSON-LD with a stable@id,sameAs,jobTitle, andknowsAbout, plus a rootWebSitenode and@idgraph linking- A claims contract test suite asserting cross-file agreement between copy and the server
🔧 Improved
- ATS checker pages rebuilt from monolithic files into domain-driven modules (
components/tool,components/hero,components/guide) - Navbar decomposed into
LogoPill/DesktopNav/ActionsPill/MobileMenu, withuseMountedanduseScrolledhooks - Features, how-it-works, security, compare, contact, and FAQ pages modularised into composable sections with decoupled datasets
- Changelog and GitHub services broken out of monolithic files into
services/githubandservices/changelog - Navbar now links Features, How It Works, and Compare — previously none had a header link from anywhere
check-design-tokensnow fails the build when a token mapped in no@themeblock is used as a utility, rather than only warning- Portfolio model stated identically everywhere: Signal and Atelier free with a badge, Nimbus and Cipher paid, all qualified as opening at launch
- JSON-LD offers consolidated onto
/pricing, withofferCountand price bounds derived from one array rather than hardcoded beside it AccordionTriggeraccepts a configurable heading level, so FAQ questions sit at the correct depth per page
🐛 Fixed
Crashes and correctness
- The root 404 boundary was a copy of the error boundary: its primary button called an undefined
reset(), throwing aTypeErroron every unmatched URL outside the marketing group - Account deletion removed R2 objects before the database transaction, so a failed transaction left an intact account whose images had silently vanished
- Deleting an account left the user's published portfolio served from cache
- Account deletion dropped the local subscription record without cancelling at the payment provider, which would have left users charged for an account that no longer existed; deletion is now blocked while a subscription would renew
- Unguarded
ev.touches[0]threw when the touch list was empty - A
Suspenseboundary on/pricingwrapped a component awaiting nothing, rendering a second copy of a large client tree that never displayed
Rendering and accessibility
text-muted-foregroundwas mapped into no@themeblock, so 36 usages inapps/siteand 98 inapps/studioemitted no CSS and rendered uncolouredLegalSectionsrendered a secondmainlandmark insideAppShell's, giving/privacyand/termstwo main regions- The
/faqpage had noh2elements in its own content, leaving every question an orphanedh3beneath the pageh1; the footer emitted anh2 → h4skip on every page - The templates hero fan selected the first three catalog entries — all portfolios — cropping landscape screenshots into a portrait paper frame
manifest.jsondeclared the standard icons as maskable, which Android crops to a safe zone and would clip on home screens
Discovery
llms.txtadvertised three/compareroutes that hard-404 and omitted three that exist, and listed every resume template ID without itsresume-prefix, breaking all seven linksFAQPagestructured data was duplicated verbatim between/faqand/ats-checker, and sevenOffernodes shipped into the<head>of every route including/privacyand/termshreflangemitted onlyen-US, region-locking an India-based service with a global English-speaking audiencenoIndexpages emitted a canonical URL, and the 404 boundaries pointed theirs at/404and/roadmap/404— routes that do not exist- Homepage
HowToused an invalidHowToSupplytype forestimatedCost, and two of four steps carried neitherpositionnorurl
Claims
- "LinkedIn import is processed client-side in your browser for total privacy" — it POSTs to the server and forwards to a third-party model. A privacy statement that was the exact inverse of the architecture.
- The Student Ambassador page described a points economy in specific numbers (+10 per invite, 1,500 points for a voucher, an "automated node validator" issuing badges instantly). None of it existed; the server implements apply, review, and status only.
- Invented metrics removed or captioned: "99.9% parse rate", "342 stars" on a repository that does not exist, "+38% ATS Impact", and an apex-domain portfolio URL the product cannot issue
✅ Verification
| Gate | Result |
|---|---|
tsc --noEmit |
Clean — all 6 apps + packages/ui |
| ESLint | Clean |
| Prettier | Clean |
| Server tests | 294 / 294 (48 files) |
| Site contract tests | 42 / 42 (was 30) |
check:design |
Passing |
| Builds | All 6 apps; site prerenders 98 static pages |
| CI on #197 | 11 / 11 checks green |
Rendered HTML was spot-checked rather than assumed: no hreflang, Person present, zero Offer nodes on /privacy and seven on /pricing with derived counts, no duplicate FAQPage on /ats-checker, and the 404 emitting noindex with no canonical.
Every new contract test was verified against a deliberately reintroduced bug. One passed on broken input and was rewritten.
Full changelog: Release-v3.24.1...Release-v3.24.2