Catalog module
AI-powered product information management, semantic search, configurable taxonomy, supplier shortlisting. Absorbs the Stella Catalog feature set — taxonomy is configurable per tenant (UNSPSC, ETIM, NATO FSC, CPV, or custom).
- Source:
apps/catalog/ - Schema:
catalog - Project Tracker prefix:
CAT-* - Hosting: sub-zone behind Directory; production basePath is
/catalog/*(rewritten from the root zone).
1. Purpose
Catalog is the platform's product knowledge layer. It owns the catalogue entries (products, services, capabilities), the configurable industry taxonomy that classifies them, and the shortlisting / supplier-matching primitives that downstream procurement modules rely on. Two technical pillars set Catalog apart: pgvector for semantic-search embeddings and ltree for hierarchical taxonomy paths. AI-generated descriptions (via @constellation-platform/ai-core) are an explicit feature of the module rather than a layer concern.
2. Component diagram (C4 L3)
Call direction is strict: API Route → Tool → Service → Repository. Routes never call services or repositories directly; workflows and event handlers go through tools or services. See route-wrapping.
3. Schema
catalog — owned by Catalog. Postgres extensions required: pgvector (embeddings on catalog_entries), ltree (path-based taxonomy hierarchies), pg_trgm (fuzzy text matching). RLS is enforced on every tenant-scoped table via app.tenant_id. Cross-module reads of identity.* are read-only via raw SQL.
4. Entities
| Aggregate | Purpose |
|---|---|
catalog_entries | Products / services / capabilities. Lifecycle: DRAFT → PUBLISHED → ARCHIVED. Carries pgvector embeddings and AI-generated descriptions. |
catalog_taxonomy | Configurable taxonomy — LTREE path enables sub-tree queries. Per-tenant choice of UNSPSC / ETIM / NATO FSC / CPV / custom. |
shortlists | Curated subsets of catalogue entries — feeds Procurement RFQ flows. Lifecycle: DRAFT → PUBLISHED → ARCHIVED. |
shortlist_entries | Membership join between a shortlist and its catalogue entries. |
5. Domain events
Published from src/server/events/catalog.events.ts via the transactional outbox under the catalog.* namespace. Full payload schemas are in @constellation/contracts and indexed in the Domain events index.
catalog.entry.created, catalog.entry.updated, catalog.entry.deleted, catalog.entry.status_changed, catalog.taxonomy.created, catalog.taxonomy.updated, catalog.taxonomy.moved, catalog.taxonomy.deleted, catalog.shortlist.created, catalog.shortlist.updated, catalog.shortlist.deleted, catalog.shortlist.archived, catalog.shortlist.entry_added, catalog.shortlist.entry_removed.
6. Public API
The Catalog API reference is not yet wired into this site — adding Zod→OpenAPI to apps/catalog/ is tracked under INF-26. Illustrative routes:
POST /api/catalog-entries— create a draft catalogue entry; AI description and embedding are generated asynchronously.POST /api/search— semantic search across published entries (uses pgvector ANN over the embeddings column).POST /api/shortlists— create a shortlist from search results or a manual selection.
7. Layers + call direction
| Layer | Path | May import from |
|---|---|---|
| API Routes | src/app/api/ | Tools only |
| Tools | src/server/tools/ | Services, Policies, Events |
| Services | src/server/services/ | Repositories, Policies, @constellation-platform/{db,ai-core,ai-embeddings} |
| Repositories | src/server/repositories/ | @constellation-platform/db (Prisma + raw SQL for ltree / vector ops) |
| Policies | src/server/policies/ | @constellation-platform/auth-core |
| Workflows | src/server/workflows/ | Tools or Services (never repositories) |
| Events | src/server/events/ | @constellation-platform/events publish() + outbox |
Enforced at PR time by scripts/check-route-wrapping.ts — invoked via npm run check:routes, which scans apps/catalog/src/app/api and apps/directory/src/app/api. Every withAuth must be paired with withTenantAuth. Plus ESLint import boundaries.
8. Code entry points
- Tool:
apps/catalog/src/server/tools/catalog-entry.tools.ts— entry lifecycle operations. - Service:
apps/catalog/src/server/services/catalog-entry.service.ts— domain invariants and AI orchestration. - AI service:
apps/catalog/src/server/services/description-generator.service.ts— wraps@constellation-platform/ai-corewith budget + audit. - Repository:
apps/catalog/src/server/repositories/catalog-entry.repository.ts. - Events module:
apps/catalog/src/server/events/catalog.events.ts.
9. Known exceptions / pitfalls
pgvectorandltreeare required. Local dev brings them up viascripts/db-init.sql— verify with\dxin psql before running migrations.- AI calls always go through
@constellation-platform/ai-core. Don't import provider SDKs (@anthropic-ai/sdk,openai) directly anywhere outside the platform packages — that's how the budget and audit interceptors stay in the request path. Seeprovider-abstraction. - Embeddings are generated lazily. A new entry doesn't get an embedding inside the create transaction — there's a workflow that picks up entries with
embedding IS NULLand fills them in. Search for an entry that's seconds-old returns no result; that's expected. - Optional clearance / classification gating. Tenants that need defence-style access control enable per-entry classification + per-user clearance. Off by default; switching it on changes the search filter shape — see the catalog spec.
- Cross-module reads are read-only via raw SQL. Don't define Prisma cross-schema relations to
identity.*— use@constellation-platform/dbraw queries.
See also
- Catalog architecture (v3) — merged conceptual model, technology stack, platform alignment.
- Catalog product specification — Stella Catalog technical spec (data model, AI enrichment, syndication).
- Architecture overview — C4 L1 / L2 view of how Catalog sits inside the platform.
- Domain events index — full payload schemas for the events listed in §5.