Loading module
Resolving locale, route permissions, and workspace projection.
ICPI Extraction Prep Map
Status: ACTIVE
Sprint: Extraction Prep Sprint 44
Scope: current ICPI code, data, route, and dependency boundary while hosted inside services/svc-tenders
Purpose
This document defines the current extraction-readiness truth for ICPI.
It is not a service-split plan by itself.
It records:
- what is clearly ICPI-owned
- what is shared Kvary backbone dependency
- what is only temporarily hosted inside
svc-tenders
- what still blocks a clean extraction package
Method
-
VERIFIED: directly confirmed in code, migrations, route wiring, or runtime docs.
-
INFERRED: strongly suggested by code shape, but not fully proven end-to-end.
-
UNVERIFIED: not strong enough to treat as fact.
READ 2026-03-28T23:42:21.903Z
READ 2026-03-29T04:52:41.869Z
CORE STRICT SAFE DELETE AFTER RERUN REPORT
PUBLIC | DRAFT | v1.0.0
READ 2026-03-29T03:13:33.020Z
REAL: durable backend behavior exists.
MIXED: real behavior exists, but boundary or hosting is mixed.
UI-FIRST: primarily UI/client-owned consumption.
SHELL: mostly shell/bootstrap/support assembly rather than domain ownership.
MISSING: no real surface found.
Boundary Verdict
VERIFIED: ICPI is a real backend capability, not a mock or placeholder.
VERIFIED: ICPI already has one of the cleanest route and persistence boundaries in svc-tenders.
VERIFIED: ICPI is still temporarily hosted inside svc-tenders; that hosting is not proof that svc-tenders is the right long-term owner.
VERIFIED: the strongest existing extraction seam is the gateway proxy in services/api, because it already supports ICPI_SERVICE_URL.
VERIFIED: the main blockers are not data-shape blockers. They are temporary hosting blockers:
- mixed root type hosting
- shell parser/auth helper dependence
- validation/schema colocation in mixed files
- monolith-local bootstrap composition
VERIFIED: no ICPI-specific Kafka, outbox, or KES/event-backbone dependency was found.
A. Current ICPI Ownership Map
| Element | Evidence | Confidence / State | Shape | Ownership verdict | Notes |
| --- | --- | --- | --- | --- | --- |
| services/svc-tenders/src/icpi/repository.ts | dedicated ICPI repository class over icpi_price_points | VERIFIED / REAL | REAL | ICPI-owned, temporarily hosted in svc-tenders | Strongest current code owner for ICPI persistence |
| services/svc-tenders/src/routes/registerIcpiRoutes.ts | dedicated route module for /icpi/* | VERIFIED / REAL | REAL | ICPI-owned HTTP surface, temporarily hosted in svc-tenders | Public reads plus service-auth-gated upsert |
| services/svc-tenders/src/routes/support/icpiRouteSupport.ts | ICPI-specific support builder narrowing shell helpers | VERIFIED / SHELL | SHELL | temporary-hosted-in-svc-tenders | Adapter layer, not ICPI domain logic |
| services/svc-icpi/migrations/0007_icpi_price_points.sql | creates icpi_price_points | VERIFIED / REAL | REAL | ICPI-owned persistence | Single clean table family |
| services/svc-icpi/migrations/0008_icpi_latest_lookup_index.sql | latest lookup index | VERIFIED / REAL | REAL | ICPI-owned persistence | Lookup optimization stays with ICPI table family |
| services/svc-tenders/src/server.ts ICPI wiring | direct IcpiRepository instantiation and registerIcpiRoutes(...) call | VERIFIED / SHELL | SHELL | temporary-hosted-in-svc-tenders | Hosting seam, not long-term domain owner |
| ICPI type exports in services/svc-tenders/src/repository.ts | IcpiQuarter, IcpiPricePoint, UpsertIcpiPriceInput, IcpiListOptions, IcpiSuggestion | VERIFIED / MIXED | MIXED | ambiguous temporary hosting | Type surface is still rooted in the mixed repository file |
| ICPI compatibility delegation in services/svc-tenders/src/repository.ts | thin pass-through methods to IcpiRepository | VERIFIED / MIXED | MIXED | temporary-hosted-in-svc-tenders | Not a real ownership signal; mostly compatibility residue |
| services/api/src/routes/icpi.ts | dedicated gateway proxy with ICPI_SERVICE_URL ?? TENDERS_SERVICE_URL | VERIFIED / REAL | REAL | shared-Kvary-owned | Best current extraction seam |
| apps/web/src/portal/api.ts ICPI client helpers | fetchIcpiPrices, fetchIcpiSuggestions, fetchIcpiLatestPrice | VERIFIED / UI-FIRST | UI-FIRST | shared/web consumer | Uses gateway contract, not direct DB/service coupling |
| apps/web/src/app/[locale]/(portal)/icpi/page.tsx and country alias page | dedicated ICPI portal page | VERIFIED / UI-FIRST | UI-FIRST | web consumer, not backend owner | Confirms product-distinct UI surface exists |
| ICPI upsert UI consumer | no web consumer found for /icpi/upsert | VERIFIED / MISSING | MISSING | no verified UI owner | Current ingest path appears service/admin-facing only |
| ICPI Kafka/topic usage | no ICPI topic or outbox trigger found | VERIFIED / MISSING | MISSING | none | This is a major reason ICPI is extraction-friendly |
| ICPI upload/storage dependency | no ICPI upload/storage surface found | VERIFIED / MISSING | MISSING | none | No MinIO/evidence/storage blocker here |
B. What Is Clearly ICPI-Owned
These are the minimum surfaces that already behave like an ICPI domain:
- HTTP routes under
/icpi/* in svc-tenders
- the
IcpiRepository persistence module
- the
icpi_price_points table and lookup indexes
- ICPI query, suggestion, latest-price, estimate, and upsert flows
These should be treated as the real ICPI boundary even though they still run inside the svc-tenders process today.
C. What Is Shared Kvary Backbone, Not ICPI-Owned
These dependencies are real, but they are not reasons to keep ICPI inside svc-tenders forever:
- gateway proxying in
services/api
- JWT/principal resolution through shared auth flow
svc-auth /auth/me principal resolution behind requireServiceAuth
- general parser/auth helper behavior currently hosted in the
svc-tenders shell
These are acceptable shared backbone concerns after extraction, but ICPI should consume them through contracts or copied/re-homed helpers rather than through direct svc-tenders shell wiring.
D. What Is Only Temporarily Hosted In svc-tenders
- ICPI route registration inside
services/svc-tenders/src/server.ts
- ICPI support assembly that narrows shell helpers
- ICPI type exports currently rooted in
services/svc-tenders/src/repository.ts
- ICPI validation schema currently rooted in the mixed
services/svc-tenders/src/validation.ts
- root-repository compatibility delegation to
IcpiRepository
None of these are strong ownership evidence for svc-tenders.
They are hosting and compatibility residue.
E. Minimum Credible ICPI Extraction Package
Code/modules that must move
services/svc-tenders/src/icpi/repository.ts
services/svc-tenders/src/routes/registerIcpiRoutes.ts
services/svc-tenders/src/routes/support/icpiRouteSupport.ts
- ICPI-specific validation from
services/svc-tenders/src/validation.ts
- ICPI-specific types now exported from
services/svc-tenders/src/repository.ts
Persistence pieces that must move
icpi_price_points
- ICPI lookup indexes from migrations
0007 and 0008
Contracts/types that must move or be shared
IcpiQuarter
IcpiPricePoint
UpsertIcpiPriceInput
IcpiListOptions
IcpiSuggestion
Best extraction-ready destination:
- an ICPI-owned module/package inside the monorepo first
- then, if needed later, a shared API-contract package for gateway/web reuse
Support/helpers that must be copied or re-homed
- shell parser helpers currently passed through
buildIcpiRouteSupport(...)
- service-auth middleware contract currently passed through
requireServiceAuth
These do not need to stay in svc-tenders.
They either need:
- local copies in a future ICPI runtime, or
- a truthful shared HTTP helper home
Auth integration points that may remain shared
- JWT verification rules
- principal resolution via shared auth service
- gateway auth middleware in
services/api
These are acceptable shared Kvary backbone dependencies after extraction.
Gateway/API contracts that should remain
services/api/src/routes/icpi.ts
ICPI_SERVICE_URL
This is the safest existing external seam and should remain the public entry point even after ICPI leaves svc-tenders.
F. Extraction Blockers
| Blocker | Severity | Why it blocks clean extraction | How to remove it | Type |
| --- | --- | --- | --- | --- |
| ICPI types still export from mixed services/svc-tenders/src/repository.ts | MEDIUM | Route, repository, and monorepo callers still import ICPI contracts from a non-ICPI file | move ICPI contracts into an ICPI-owned module/package and update call sites | code-only |
| ICPI upsert validation lives in mixed services/svc-tenders/src/validation.ts | MEDIUM | Extraction would otherwise keep a mixed validation dependency edge | split ICPI schema into an ICPI-owned validation module | code-only |
| ICPI support builder still depends on shell-owned parser/auth helpers | MEDIUM | A future ICPI runtime cannot depend on svc-tenders/src/server.ts helper functions | copy or re-home parser/auth helpers behind a smaller interface | code-only |
| ICPI route hosting still happens in services/svc-tenders/src/server.ts | LOW | The runtime host is still the monolith even though the route boundary is clean | create an ICPI-local bootstrap module/package first, then point gateway at it later | code+infra |
| Web and service contracts are duplicated rather than shared | MEDIUM | apps/web/src/portal/api.ts defines its own ICPI shapes, which creates future drift risk | promote ICPI API contracts into a shared package or generated contract layer | code+docs |
| Gateway still falls back from ICPI_SERVICE_URL to TENDERS_SERVICE_URL | LOW | This is a good seam, but it still encodes temporary hosting | keep the route, but make dedicated ICPI_SERVICE_URL the expected deployment target when extraction begins | code+infra |
G. Recommended Extraction Approach
- code boundary first
- ICPI package/module boundary next
- API/runtime boundary after that
- DB split only when operationally needed
- persistence is already isolated enough
- gateway indirection already exists
- no Kafka/outbox untangling is required
- the remaining blockers are mostly type/support/hosting blockers
H. Practical Readiness Verdict
- Code boundary readiness:
HIGH
- API extraction readiness:
HIGH
- DB-boundary-first readiness:
LOW
- Full standalone runtime readiness today:
MEDIUM
ICPI is ready for real extraction preparation now because the hard part is no longer domain ambiguity.
The remaining work is mostly about removing temporary monolith hosting edges without inventing architecture that does not yet exist.