Vacancy Public Read Decision
Current Public Read Truth
The current public vacancy routes are:
GET /vacanciesGET /vacancies/:id
Those routes already depend on the preferred vacancy route-time repository:
services/svc-tenders/src/vacancy/readRepository.ts
That is the truthful preferred runtime dependency.
However, the public read truth inside that preferred repository is still mixed:
- projection-backed vacancy postings come from:
vacancy_postings_viewvacancy_posting_detail_view
- compatibility fallback still comes from:
- legacy
vacancies
- legacy
So the preferred route dependency is real, but the public discovery data source behind it is not yet fully converged onto vacancy-owned projection truth.
Exact Fallback Path
GET /vacancies
VacancyReadRepository.listAllVacancies():
- selects projected rows from
vacancy_postings_view - unions them with legacy rows from
vacancies - excludes legacy rows only when a projection-backed posting already exists for that identifier
This means the public list is intentionally mixed.
GET /vacancies/:id
VacancyReadRepository.findVacancyById():
- looks for the posting in
vacancy_posting_detail_view - if found, maps that projection into the legacy summary shape
- if not found, falls back to
vacancies
This means the public detail route is also intentionally mixed.
Compatibility Residue
Compatibility residue still involved in public vacancy discovery:
- legacy
vacanciestable - root repository vacancy compatibility methods in
services/svc-tenders/src/repository.ts VacancyCompatibilityReadRepository- web fallback to
VACANCY_CATALOG
Important asymmetry:
- owner/internal vacancy reads and vacancy application reads are already cleaner vacancy-owned truth
- public vacancy discovery is the conspicuous mixed surface
Web Fallback Truth
Current web vacancy consumption is also mixed:
apps/web/src/portal/api.tsprefers the backend/API vacancy routes- if list fetching fails, it falls back to
VACANCY_CATALOG - detail rendering is further enriched in
apps/web/src/features/domains/vacancyDetail.ts - that enrichment is presentation-layer truth, not canonical backend contract truth
So the web does not yet treat backend vacancy DTOs as the only vacancy detail/catalog source.
Decision
Recommended direction:
- keep
/vacanciesand/vacancies/:idas an explicit compatibility seam for early extraction
Not recommended as the next step:
- forcing projection-backed public-read convergence before runtime/bootstrap prep
Rationale
Why compatibility seam first is safer:
- vacancy postings, applications, and owner/internal reads are already a real backend core
- the API gateway seam is already extraction-ready through
VACANCIES_SERVICE_URL ?? TENDERS_SERVICE_URL - the mixed public read path is explicit and localised enough to carry forward honestly
- public-read convergence would be a broader behavior-sensitive cleanup across:
VacancyReadRepository- legacy
vacancies - web fallback and enrichment assumptions
- runtime/bootstrap prep can proceed without pretending that public discovery is already clean
What this decision does not mean:
- it does not mean public vacancy discovery is ready for a clean final cutover
- it does not mean legacy
vacanciesshould be treated as canonical long-term vacancy truth - it does not remove the need for later public-read convergence
Practical Next-Step Meaning
The safe next step is:
- prepare a vacancy runtime/bootstrap using the real vacancy core
- carry the current public list/detail compatibility behavior forward explicitly
- keep public discovery marked as compatibility-backed during early extraction
- plan a later cleanup sprint that converges
/vacanciesonto projection-backed truth before claiming public-read cleanliness