A REQUIRED resume is now actually enforced

FixDocsService
Shipped
September 3, 2026 at 10:50 PM UTC
Author
Kamo
Commit
a372f00

A review of my own commit found the enforcement it claimed. JobApplicationService carried the comment "a REQUIRED resume is enforced at that point by requireResumeSatisfied" — and requireResumeSatisfied did not exist. The only related method, resumeSatisfied, was called by nothing and exposed on no DTO, so the rule lived entirely in the client's submit button. The cause was the two-call shape. A resume attaches to an application through the application's own uid, so the row has to exist first; apply() created it and the client uploaded afterwards. Anyone POSTing the JSON endpoint directly, and any client whose upload leg failed — which ApplyDialog deliberately treats as non-fatal, because the answers really are stored — filed a complete-looking application against a posting whose HR team had marked the resume required. Now both halves are ONE request and one transaction. /listings/{uid}/apply has two mappings split on content type: the multipart one takes the answers as a `payload` part and the file as `file`, writes the row, stores the file against its fresh uid, and rolls the whole thing back if the file is required and missing or unstorable. The JSON one carries no file and therefore refuses outright when the posting requires one — which is what closes the direct-post hole rather than papering over it. Editing an existing application stays two calls, correctly: the row is already there, so a failed re-attach cannot orphan anything. storeResume is now shared by apply and attachResume, so the size ceiling, the format sniff and the name sanitising cannot drift between the two paths. Three tests pin it: a required resume with no file refuses and writes no row, an optional one may be omitted, and re-applying after a withdrawal is satisfied by the file already on the revived row rather than being asked for it twice. Also removes CareersAccess.canManage, which was called only by its own test. An API kept alive by a test is not an API.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing