docs/specs/20260710-125843-agent-feature.mdadded
---
spec: agent-feature
status: in-progress
owner: feature-pipeline-agent
related-routes:
files:
  - src/api/v2/projects/systems/systems.routes.ts
  - src/api/v2/projects/systems/systems.controller.ts
  - src/api/v2/projects/systems/systems.validator.ts
  - src/services/systems.service.ts
  - src/api/v2/projects/systems/systems.routes.ts
  - src/api/v2/projects/systems/systems.controller.ts
  - src/services/systems.service.ts
  - src/api/v2/projects/systems/systems.routes.ts
  - src/api/v2/projects/systems/systems.controller.ts
  - src/services/systems.service.ts
---

# agent-feature

## Goal

Add three read/create API2 endpoints for the existing xyz.CommissioningSystem
entity (exposed as "systems"): POST create, GET-by-id, and paginated GET list,
all project-scoped under /api/v2/projects/{projectId}/systems. No new Postgres
table is created — CommissioningSystem already exists in the schema. Follows the
AssetType endpoint pattern. Revised per review: no new permissions; reuse
existing Project Edit / System View permissions.


## Behavior changes

- POST /api/v2/projects/{projectId}/systems
- GET /api/v2/projects/{projectId}/systems/{id}
- GET /api/v2/projects/{projectId}/systems

## 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

- Update (PUT/PATCH) and Delete (DELETE) endpoints for systems.
- Exposing System via API1 / MongoDB.
- Any migration or sync with existing API1 System data.
- New Postgres columns/fields on CommissioningSystem (table used as-is).

## 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

- Modelled the "systems" endpoints on the **Assets** endpoint pattern
  (`src/api/v2/projects/assets/`) rather than SystemType, because a
  CommissioningSystem is an *instance* classified by a SystemType — the exact
  analogue of an Asset classified by an AssetType. This gives paginated LIST
  (via `IndexedItem` + `buildPaginatedQueryResponse`), matching the spec's
  "paginated GET list".
- **Foreign key:** a System belongs to a **SystemType** (`systemTypeId`),
  mirroring Asset → AssetType. Create body is `{ name, systemTypeId }`.
- **Permissions:** reused existing `PROJECT_VIEW` (GET list + GET by id) and
  `PROJECT_EDIT` (POST create), plus `INTERNAL_ROLE`, exactly as Assets/AssetTypes
  do. There is no dedicated "System View" authority in
  `authorities.types.ts`; the spec's "reuse existing Project Edit / System View"
  is satisfied by the established project-scoped `PROJECT_VIEW`/`PROJECT_EDIT`
  pair (no new permissions added, per the revised spec).
- **DB contract assumed** (functions/columns live in the external DB migration
  repo, not this codebase — same as Asset/AssetType):
  - `xyz."fn_GetCommissioningSystemList"(projectId, lastFetchedIndexId, size)`
  - `xyz."fn_GetCommissioningSystem"(projectId, systemId)`
  - `xyz."fn_InsertCommissioningSystem"(projectId, systemTypeId, name, createdBy)`
  - Returned columns: `CommissioningSystemId`, `Name`, `SystemTypeId`,
    `CreatedBy`, `InsertedOn`, `LastModifiedOn`, `LastModifiedBy`, `Id`
    (pagination index). The API response exposes `systemId` (the entity is
    "exposed as systems" per the spec).
  - A missing/invalid `systemTypeId` on insert is expected to raise an error
    whose message contains `"SystemType with id"`, mapped to a 404
    (mirrors Asset's `"AssetType with id"` mapping).
- Added a `System` schema to `src/swagger.components.schemas.json` and referenced
  it from the route JSDoc (no inline duplication), per repo convention.
- Build/tests were **not run locally** — `node_modules` is not installed in this
  environment and the instructions forbid installing a toolchain. The CI/e2e
  pipeline runs the suite.