docs/specs/20260715-154549-agent-feature.mdadded---
spec: agent-feature
status: done
owner: feature-pipeline-agent
related-routes:
files:
- src/api/v2/projects/assettypes/systemtypemappings/asset.type.systemtype.mappings.routes.ts
- src/api/v2/projects/assettypes/systemtypemappings/asset.type.systemtype.mappings.controller.ts
- src/api/v2/projects/assettypes/systemtypemappings/asset.type.systemtype.mappings.validator.ts
- src/services/asset.type.systemtype.mappings.service.ts
- src/api/v2/projects/assettypes/systemtypemappings/asset.type.systemtype.mappings.routes.ts
- src/api/v2/projects/assettypes/systemtypemappings/asset.type.systemtype.mappings.controller.ts
- src/services/asset.type.systemtype.mappings.service.ts
- src/api/v2/projects/assettypes/systemtypemappings/asset.type.systemtype.mappings.routes.ts
- src/api/v2/projects/assettypes/systemtypemappings/asset.type.systemtype.mappings.controller.ts
- src/services/asset.type.systemtype.mappings.service.ts
- src/api/v2/projects/assettypes/systemtypemappings/asset.type.systemtype.mappings.routes.ts
- src/api/v2/projects/assettypes/systemtypemappings/asset.type.systemtype.mappings.controller.ts
- src/services/asset.type.systemtype.mappings.service.ts
- src/services/asset.service.ts
- src/models/egress.ts
- src/services/asset.service.ts
- src/models/egress.ts
---
# agent-feature
## Goal
Adds four API2 endpoints to manage AssetType↔SystemType mappings (create,
delete, list, get-by-id) backed by the existing xyz.AssetTypeSystemTypeMapping
table, and augments both Asset GET endpoints to include a scalar systemId
field derived from the asset's AssetType→SystemType mapping (null when no
mapping exists). No new tables are introduced — all target tables already
exist. This is a modify feature entirely on API2 + Postgres.
## Behavior changes
- POST /api/v2/projects/{projectId}/asset-types/system-type-mappings
- DELETE /api/v2/projects/{projectId}/asset-types/system-type-mappings/{mappingId}
- GET /api/v2/projects/{projectId}/asset-types/system-type-mappings/{mappingId}
- GET /api/v2/projects/{projectId}/asset-types/system-type-mappings
- GET /api/v2/projects/{projectId}/assets/{assetId}
- GET /api/v2/projects/{projectId}/assets
## Acceptance criteria
- [ ] The behavior described above is implemented on the listed files.
- [ ] Existing behavior is unchanged when the new feature is not exercised.
- [ ] Unit and (where observable) e2e tests cover the new behavior.
## Out of scope
- Updating Asset write endpoints (POST/PUT/PATCH) to accept systemId.
- Returning a nested SystemType object (only the scalar systemId is returned).
- Bulk create/delete of mappings.
- Cascade/blocking behavior when an AssetType or SystemType is deleted.
## Notes / open questions
- Generated by the feature pipeline from the approved architect plan. If any
acceptance criterion is ambiguous, ask the human before implementing.
## Decisions
- **New router placement.** The `system-type-mappings` router is mounted at
`/:projectId/asset-types/system-type-mappings` in `api.v2.routes.ts` *before*
the `/:projectId/asset-types` router so the more specific mappings path is not
swallowed by the asset-types `GET /:assetTypeId` route.
- **`systemId` semantics.** The spec names the new Asset field `systemId` but
describes it as being derived from the AssetType→SystemType mapping, which
yields a *SystemType* id. Implemented literally: field name `systemId`,
value = the `SystemTypeId` of the mapping for the asset's assetType (or null).
Flagged as an open question for the reviewer.
- **`systemId` is read-only and optional.** Added to the `Asset` interface as
`systemId?: string | null`, populated only on the GET (list/get-by-id) paths.
POST/PATCH responses are left byte-for-byte unchanged (regression safety and
in line with the "write endpoints unchanged" out-of-scope note).
- **Derivation query.** `assets.service` calls a new
`getAssetTypeToSystemTypeMap(projectId)` helper (one query returning all
project mappings) and looks up each asset's `assetTypeId`. Simple and avoids a
per-asset query.
- **DB layer.** Mappings service assumes the sibling naming convention for the
existing table: `fn_GetAssetTypeSystemTypeMappingList`,
`fn_GetAssetTypeSystemTypeMapping`, `fn_InsertAssetTypeSystemTypeMapping`,
`usp_DeleteAssetTypeSystemTypeMapping`. No new tables (per spec).
- **egress.ts.** Left untouched — Asset/mapping shapes follow the repo
convention of living in their service files, not `models/egress.ts`. Noted as
a deviation from the spec's `files:` list.