Skip to Content
ReferenceServicesProgram Catalog

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.

EntityTableNotes
JurisdictionjurisdictionAU, AU-QLD, NZ, … — DRAFT/ACTIVE/RETIRED
Qualification framework + levelsqualification_framework, framework_levelAQF, NZQCF, EQF, RQF, SCQF, NSQF, DQR, CNCP/RNCP, QFEmirates, ISCED 2011
Catalog entrycatalog_entryentry_type ∈ QUALIFICATION · UNIT · SKILL_SET · MICRO_CREDENTIAL · IDENTITY_DOCUMENT · LICENSE
Catalog entry versioncatalog_entry_versionimmutable once effective_from passes; exactly one row per entry has effective_to IS NULL
External referenceexternal_referencepolymorphic pointer to TGA/NZQA/etc.
Code set / valuecode_set / code_valuesingle generic lookup mechanism — never a CHECK constraint
Regulatory scheme + field mapregulatory_scheme, scheme_field_mape.g. AVETMISS_8.0; drives AvetmissExportService in Core Engine
Issuer scheme registrationissuer_scheme_registrationan issuer’s registration number + scope per jurisdiction
Catalog entry proposalcatalog_entry_proposalqueued mapping request — issuer or custodian originated
Skill / catalog-entry-skillskill, catalog_entry_skillflat skills taxonomy, attachable to any version

gRPC surface (catalog.proto)

GroupRPCs
Resolution (issuance-time)ResolveCatalogEntry, GetCatalogEntryVersion, GetCodeValue
Jurisdictions & frameworksCreateJurisdiction, ListJurisdictions, CreateQualificationFramework, ListFrameworks
Catalog entriesCreateCatalogEntry, SupersedeCatalogEntryVersion, ListCatalogEntries
Code sets, regulatory schemesUpsertCodeValue, ListCodeValues, CreateRegulatoryScheme, ListRegulatorySchemes, AddSchemeFieldMap, ListSchemeFieldMaps
Issuer scheme registrationsRegisterIssuerScheme, GetIssuerSchemeRegistration, ListIssuerSchemeRegistrations, ReviewIssuerSchemeRegistration
Catalog entry proposalsSubmitCatalogEntryProposal, ListCatalogEntryProposals, GetCatalogEntryProposal, UpdateCatalogEntryProposal, ReviewCatalogEntryProposal
Skills taxonomyRegisterSkill, 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.