Program Catalog — Service Reference
Module: backends/program-catalog · REST: 8085 (actuator/health only — no business REST
API) · gRPC: 50054, mTLS required · Schema: catalog
See Master Data Registry for the why behind the three-layer (core / configuration / adapter) model this service implements.
Purpose
The jurisdiction-agnostic master-data registry for “what a credential is of”: qualifications,
units of competency, skill sets, micro-credentials, identity documents, and licences — plus the
jurisdiction-specific configuration (frameworks, code sets, regulatory schemes) that gives a bare
code like ICT40120 local meaning. No REST business API — every consumer (Core Engine’s
issuance flow, Custodian Portal, Issuer Portal, Admin Console) reaches it exclusively through gRPC,
proxied by Core Engine.
Data model (catalog schema)
V2__seed_data.sql loads jurisdictions, frameworks, code sets, and a global/regional
identity-document catalog. A separate seeding path (TgaSeedDataService +
TgaCsvSeedLoader, ON CONFLICT DO NOTHING) loads real Australian training.gov.au (TGA)
qualifications, skill sets, and units of competency from bundled CSV exports
(DATA_AS_AT = 2026-09-07) — real seeded AU VET catalog, not placeholder data.
| Entity | Table | Notes |
|---|---|---|
| Jurisdiction | jurisdiction | AU, AU-QLD, NZ, … — DRAFT/ACTIVE/RETIRED |
| Qualification framework + levels | qualification_framework, framework_level | AQF, NZQCF, EQF, RQF, SCQF, NSQF, DQR, CNCP/RNCP, QFEmirates, ISCED 2011 |
| Catalog entry | catalog_entry | entry_type ∈ QUALIFICATION · UNIT · SKILL_SET · MICRO_CREDENTIAL · IDENTITY_DOCUMENT · LICENSE |
| Catalog entry version | catalog_entry_version | immutable once effective_from passes; exactly one row per entry has effective_to IS NULL |
| External reference | external_reference | polymorphic pointer to TGA/NZQA/etc. |
| Code set / value | code_set / code_value | single generic lookup mechanism — never a CHECK constraint |
| Regulatory scheme + field map | regulatory_scheme, scheme_field_map | e.g. AVETMISS_8.0; drives AvetmissExportService in Core Engine |
| Issuer scheme registration | issuer_scheme_registration | an issuer’s registration number + scope per jurisdiction |
| Catalog entry proposal | catalog_entry_proposal | queued mapping request — issuer or custodian originated |
| Skill / catalog-entry-skill | skill, catalog_entry_skill | flat skills taxonomy, attachable to any version |
gRPC surface (catalog.proto)
| Group | RPCs |
|---|---|
| Resolution (issuance-time) | ResolveCatalogEntry, GetCatalogEntryVersion, GetCodeValue |
| Jurisdictions & frameworks | CreateJurisdiction, ListJurisdictions, CreateQualificationFramework, ListFrameworks |
| Catalog entries | CreateCatalogEntry, SupersedeCatalogEntryVersion, ListCatalogEntries |
| Code sets, regulatory schemes | UpsertCodeValue, ListCodeValues, CreateRegulatoryScheme, ListRegulatorySchemes, AddSchemeFieldMap, ListSchemeFieldMaps |
| Issuer scheme registrations | RegisterIssuerScheme, GetIssuerSchemeRegistration, ListIssuerSchemeRegistrations, ReviewIssuerSchemeRegistration |
| Catalog entry proposals | SubmitCatalogEntryProposal, ListCatalogEntryProposals, GetCatalogEntryProposal, UpdateCatalogEntryProposal, ReviewCatalogEntryProposal |
| Skills taxonomy | RegisterSkill, ListSkills, SetCatalogEntrySkills, GetSkillsForCatalogEntry |
| Semantic search (pgvector) | ListCatalogEntriesMissingEmbedding, UpsertCatalogEntryEmbedding, SemanticSearchCatalogEntries |
ResolveCatalogEntry is the RPC Core Engine calls at issuance time to pin a credential to the
qualification/unit current on the day it was issued. SupersedeCatalogEntryVersion is the only
way a catalog entry version is ever superseded — it closes the current version and inserts the new
one in one transaction.
Catalog entry proposals are one unified queue for two originators: an issuer requesting a
brand-new credential type, or a custodian’s intake item with no catalog match. A
custodian-sourced proposal only ever carries source/jurisdiction/title; an admin fills in
entry_type/code/description/nominal_hours before approving. ReviewCatalogEntryProposal
either creates a NEW_ENTRY or resolves to an EXISTING_ENTRY, so issuer and custodian requests
can converge on the same catalog entry regardless of which raised it first.
Semantic search pushes embedding storage and search down to Postgres (pgvector), where
catalog_entry_version already lives — Core Engine remains the only service that calls an LLM;
the query text never reaches this service, only its already-computed vector.
Who calls this service
CatalogRegistryGrpcClient (Core Engine) is used by: IssuanceOrchestrator (resolve entry at
issue time, enforce scheme scope), CustodianIntakeService/CustodianEvidenceService/
CustodianPolicyService/CustodianExpiryResolver (catalog lookups for intake/attestation/expiry),
CatalogPortalController/CatalogAdminController (Issuer Portal and Admin Console UIs),
PublicVerificationController (resolving a verified credential’s catalog entry for display),
CatalogSemanticSearchService/CatalogEmbeddingBackfillScheduler (semantic search), and
AvetmissExportService/AvetmissFieldResolver (regulatory export field mapping).
Implementation status
Fully implemented against every RPC listed above — not stubs. The TGA CSV seed loader is real
production seed data. This service’s REST port (8085) serves only Spring Boot actuator endpoints —
there is no /api/v1/catalog/* REST controller in this module; every catalog write/read a
frontend performs goes through Core Engine’s REST controllers, which proxy to this service over
gRPC.
See Add a Jurisdiction for the data-only onboarding workflow this schema supports.