# F-138 — Architect note (design) ## What F-138 — close the `GET /pricing/variants/:id` 404 race by seeding a default `pricing_variant_prices` row immediately after `CreateProductVariant` persists a variant. Pricing owns its table (F-153 precedent for cross-module table read; for cross-module **writes** the repo uses service injection — same pattern `cart` already uses on `pricing` in `build-app.ts`). ## Why `variants.create` only inserts `catalog_product_variants`; it never inserts `pricing_variant_prices`. Three call sites create variants (product autovariant, lazy GET, explicit POST) — all 404 on the pricing GET until an admin prices them. Customer/cart flows that read a price right after variant creation break. ## Approach 1. `PricingRepository` + `PricingService` gain `seedVariantPrice(variantId): Promise`. 2. `PgPricingRepository.seedVariantPrice`: `INSERT pricing_variant_prices(variant_id, net_unit_amount_cents, offer_cents, cost_cents, vat_rate) VALUES ($1, 0, NULL, NULL, 'general') ON CONFLICT (variant_id) DO NOTHING` — same column set as `setVariantPrice` (`currency`/`created_at`/`updated_at` come from DDL defaults). Idempotent + no injection (`variantId` is a UUID produced by `variants.create`). 3. `CreateProductVariant` ctor += `pricing: PricingService` (type-only import of pricing **public index** — R1 legal); after `variants.create` returns, best-effort `await this.pricing.seedVariantPrice(variant.id)` (try/catch: variant already persisted; seed failure must not fail creation). 4. `catalog.routes.ts`: `CatalogRoutesDeps += pricing`; wire `new CreateProductVariant(repository, variants, pricing)`. Single constructor → all 3 call sites seeded. 5. `build-app.ts`: hoist `const pricing = createPricingService(deps.pool)` above the `registerCatalogRoutes` block so it can be passed in; pricing routes + cart keep using it (unchanged). `createPricingService` already imported. ## Alternatives considered - (a) Raw SQL insert from `CreateProductVariant` via `deps.pool` — REJECTED: catalog app layer shouldn't own pricing table writes (layering; reviewer would flag). Service injection keeps ownership clean. - (b) Seed in `PgProductVariantRepository.create` — REJECTED: couples catalog infra to pricing schema; breaks single-responsibility. - (c) `PricingService` injection (CHOSEN) — matches the established `cart`→`pricing` cross-module write pattern; testable with a fake. ## Risks - build-app ordering: hoisting `pricing` const is a pure construction reorder — safe (`deps.pool` available, createPricingService has no side effects). - Seed failure: made best-effort so variant creation never regresses (AC3). - tsc `strict` + `noUncheckedIndexedAccess`: not relevant here (no array indexing in new code). ## Tests - `catalog/tests/variant-use-cases.test.ts` (unit, runnable): fakes for ProductRepository, ProductVariantRepository, PricingService — asserts seed-called, no-seed-when-product-missing, seed-failure-doesn't-break-creation. - `catalog.itest.ts` AC itest (skipIf !hasDb): POST variant → GET `/pricing/variants/:id` 200 + defaults. - No migration (variant_id UNIQUE/PK already).