- Shipped
- September 3, 2026 at 10:00 PM UTC
- Author
- Kamo
- Commit
- 66fa8d5
Two entities, six enums and two repositories under com.kamo.z.shared.hr.careers, plus the three shared types the feature had to widen. JobPosting is three groups of columns worth telling apart: what the job IS (title, department, engagement shape, arrangement, description, location, pay), where it is in its LIFE (status, dates, headcount), and what its application FORM asks — twelve ask* columns, each an ApplicationFieldRequest. The location is deliberately duplicable and RESOLVED rather than copied. useCompanyAddress means "wherever the organization says it is" and is read at DTO time from the org's own address; copying it in on save would freeze it as it was that day, so an office move would leave every open posting pointing at the old building. Nothing would fail — the adverts would simply be wrong. The six override columns hold the alternative and are all optional, so a posting may name a city and nothing else. ApplicationFieldRequest is ONE enum for twelve questions rather than a boolean per question plus a separate resume enum. A boolean cannot say "ask, but do not insist", and the moment HR wants that for one field the boolean has to be widened anyway. The education questions are NOT among them: they are tied to requiredEducation, so a posting that demands a degree always asks where it came from and there is no switch that can contradict the requirement three fields above. JobApplication is one row per (posting, member), enforced by a unique constraint. Withdrawing sets WITHDRAWN and re-applying revives the same row rather than adding a second — so nobody can flood a posting, HR's applicant count is a count of people, and one person's interest in one job stays in one place. The applicant's name, email and phone are SNAPSHOTTED at submit: they are also live on Member, and that is the problem. A hiring record has to say who applied and how to reach them on the day they applied, and a member who later changes their preferred name must not silently rewrite an application HR is part-way through reading. The three widened types: - WorkLocationType gains FLEXIBLE. The member profile's work-location field and a posting's Arrangement are the same question asked at two moments, so they share one enum — a private copy on either side drifts the day the other gains a value. FLEXIBLE is distinct from HYBRID: hybrid is an employer-set split, flexible says there is no such split to state. Appended, so no stored ordinal moves — but TeamMember.location is @Enumerated(ORDINAL) and Hibernate froze a CHECK (0..2) when the enum had three values, which ddl-auto will not widen. The drop is in KamoInitializer's **************** - RoleRightType gains MANAGE_JOB_POSTINGS (302) and VIEW_JOB_LISTINGS (303), both standalone roots under HRS and deliberately NOT a VIEW/MANAGE pair. The first is a tab right in the shape of 182-186; the second is held by ordinary staff so they can read the internal board and apply. Pairing them would either hand every employee who can see the board the ability to rewrite the adverts on it, or make withdrawing HR's own grant close the board to everybody. RoleRightHierarchyTest's pinned counts move in this commit: values 287 -> 289, standalone 38 -> 40, roots 76 -> 78; children is unchanged. - ImageAssocType gains JOB_APPLICATION (id 19, ordinal 17) for the resume, scoped to the APPLICATION rather than the applicant — HR reading one application must see the file sent with THAT application, not the most recent thing the member uploaded anywhere. It gets its own StorageDomain rather than being folded into HR_RESOURCES, which is the tempting place and the wrong one: HR resources are a library the org curates and prunes, these are documents third parties send in and the line only grows while a board is open. Two coverage guards caught that last change and are the reason it is complete: StorageDomainCoverageTest refused an association no domain billed, and ClinicalDocumentReuseTest asserted PATIENT_CHART "must be last". The second was asserting a proxy — what actually has to hold is that its ordinal is still 16, so a value inserted BEFORE it is caught while a value appended after it is allowed, which is the one change the enum is explicitly designed for.