/** * 항목 조회 — **개념 안의 목록**(③)과 **항목 하나의 상세**(④). * * ── 이 파일이 도메인을 알지 않는다 ───────────────────────────────────────────── * 어느 축이 있고 무엇을 가리키는지는 **커널 카탈로그가 선언**한다(`TWIN_AXES`·`TWIN_RELATIONS`). * 그래서 야드의 도크도어나 에너지의 계량기가 늘어도 여기 손댈 것이 없다(ADR-0031). 이 파일에 * 도메인 이름이 한 번도 나오지 않는 것이 그 증거다. * * ── 알리지 않고 자르지 않는다 ────────────────────────────────────────────────────── * 목록은 항상 **총 건수**와 함께 온다. 그리고 어떻게 셌는지(`basis`)를 밝힌다 — 행이면 DB 가 * 페이징했고, 문서면 서버가 문서를 통째로 읽어 잘라 냈다. 후자는 규모에서 한계가 되므로 그 사실이 * 화면에 드러나야 이주 압력이 살아 있다. */ export declare class TwinModelItemQuery { twinModelEntities(instanceId: string, axis: string, context: ResolverContext, search?: string, offset?: number, limit?: number, /** * 어느 시각의 사실인가 — **관측 축에만 뜻이 있다.** * * 선언 축은 시간축이 없다(그 시점의 선언은 구조 리비전이 답한다). 그래서 문서 축에 이 값을 주면 * 쓰지 않는다 — 무시했다는 사실은 응답의 `basis` 가 말한다(`document`). */ untilTime?: string): Promise; /** * 행에서 **내부 배관을 걷어낸다** — 사용자가 볼 것은 현장의 사실이지 우리 스키마가 아니다. * * 손으로 목록을 두지 않는다. 관계와 그 조인 컬럼이 무엇인지는 **엔티티 메타데이터**가 알고, * 표로 두면 컬럼이 늘 때마다 여기를 고쳐야 하며 잊으면 그대로 새어 나간다 — 실제로 * `domainId`·`instanceRowId` 같은 내부 UUID 가 화면까지 갔다. * * 식별자도 뺀다: 항목 자신의 id 는 이미 `id`/`itemId` 로 나가므로 두 번 보일 이유가 없다. */ private strip; /** * **자재는 자기 GS1 품목 참조를 안다** — 읽기 경계에서 이어 붙인다. * * 정본은 `productionSpec.binding` 하나다(커널이 EPC↔자재를 그 표로 잇는다). 그런데 그 사실은 * **자재마다의 속성**이다: 이 자재가 GS1 품목 몇 번인가, 그래서 개체로 추적되는가(= 계보를 비교할 * 수 있는가). 자재 목록에 그것이 없으면 자재는 자기 정체를 모르고, 사용자는 그 사실을 딴 축에서 * 찾아야 한다. * * 그래서 **저장은 한 곳(binding), 표시는 읽는 자리에서 이어 붙임** — 이름표와 같은 방식이다. * 값을 복제해 두면 두 곳이 어긋나고, 어긋난 쪽을 아무도 모른다. */ private withBinding; /** * **오더가 무엇을 만드나** — GS1 품목 참조를 자재로 다시 계산해 붙인다. * * 커널의 오더는 품목을 GS1 으로 말한다(`urn:epc:idpat:sgtin:0614141.078101.*`). 사람에게 그 문자열은 * 아무 뜻이 없고, 그 품목의 이름은 **자재 선언**이 갖고 있다. 둘을 잇는 것은 `productionSpec.binding` * (자재 키 → 품목 참조)이므로 **역방향으로 다시 계산한다.** * * 정본은 그대로 둔다: `gtin` 은 커널이 말한 값이고, 여기서 더하는 것은 **자재 키 하나**다(그 이름은 * 이름표가 붙인다 — 값을 복제하지 않는다). 다시 계산하지 못하면 아무것도 더하지 않는다: 짐작으로 이으면 * "이 오더는 저것을 만든다" 는 거짓이 되고, 그건 모르는 것보다 나쁘다. */ private withOrderMaterial; /** 행 하나 → 목록 항목. 컬럼 이름을 화면이 알지 않아도 되게 `id` + 나머지로 낸다. */ private rowItem; twinModelItem(instanceId: string, axis: string, itemId: string, context: ResolverContext): Promise; /** * **id → 이름**, 모든 축을 한 표로. * * ── 왜 이 표가 필요한가 ────────────────────────────────────────────────────── * 행은 다른 것을 **id 로** 가리킨다(사람의 `personnelClassIds`, 설비의 `homeLocationId`, 공정의 * `locationType`). 그 id 의 이름은 **가리켜진 축의 행**에 있으므로, 화면이 그것을 알려면 축을 * 하나씩 더 읽어야 한다 — 그래서 지금까지 표면마다 그냥 id 를 찍었다(`cutter-op`, `cut-station`). * 표면을 하나씩 고치는 것은 끝이 없다: 새 화면은 처음부터 다시 id 를 찍는다. * * 그래서 **서버가 붙인다.** 서버는 이미 모델을 손에 들고 있고, 어느 축이 있는지는 커널 카탈로그가 * 선언한다(`TWIN_AXES`) — 도메인이 늘어도 이 함수는 그대로다. * * 값은 그 항목이 **자기 이름이라고 말한 것**이다(`name`·`label`·`description`). 그중 어떤 것은 * i18n 키이므로(등급의 `description`) 번역은 화면의 일로 남긴다. 이름이 없으면 표에 넣지 않는다 — * 없는 것을 지어내지 않고, 그 경우 화면은 id 를 그대로 보인다. */ private nameIndex; /** * 이 응답이 **실제로 가리킨 것만** 골라 낸다. * * 모델 전체 표를 그대로 실으면 자리가 10만인 현장에서 목록 한 페이지에 10만 줄짜리 이름표가 * 따라온다. 나온 값에 걸리는 것만 싣는다 — 규모에서 성립하는 유일한 방식이다. */ private namesFor; /** 등급 id → 표시명 키. 인원·설비·자산·품목 등급을 한 표로 — 어느 자원이든 같은 방식으로 요구된다. */ private classLabels; /** * 관측이 본 이 항목 — 커널이 실행 중일 때만. **실행 중이 아니면 `null` 이지 빈 객체가 아니다** * (관측이 없는 것과 비교하지 못한 것은 다르다). */ /** * 이 공정의 **생산 능력** — 공정 축 항목에만 붙는다. * * 구간은 **앞으로 24시간**이다. 표준의 약정·가용은 *앞으로 쓸* 용량이므로 지난 구간을 두고 말하면 * 뜻이 없고, 이 화면에는 사용자가 고른 창이 없다. 그래서 하루를 쓰고 **그 사실을 값과 함께 낸다** * (화면이 라벨로 말한다) — 어느 구간의 값인지 모르면 능력은 읽을 수 없다. * * **수요를 지어내지 않는다.** 여기서 내는 값(상한·약정·달성불가·가용·제약하는 축)은 전부 공급 쪽이다 — * 자원 수·사이클·가동률에서 나온다. 수요는 `ok`·병목·하루 상한에만 쓰이고 그것들은 내지 않으므로, * 계산에 넘기는 수요 `1` 은 결과에 새지 않는다(성과 화면은 사용자가 걸어 둔 목표를 쓴다 — 그 화면은 * "목표를 낼 수 있나" 에 답하고 여기서는 "얼마나 더 할 수 있나" 에 답한다). * * 안 실행 중이면 붙이지 않는다 — 능력은 지금 자원의 사실에서 나오고, 없는 것을 지어내지 않는다. */ private capabilityOfOperation; /** * 이 항목을 트윈이 **관측한 값** — 그리고 **무엇을 근거로** 아는지. * * 봉투를 푸는 것을 빠뜨려서(`unwrapState`) 문서 축의 관측 열이 통째로 비어 있던 자리다(사람을 열면 * 트윈이 아는 것이 전부 `—` 였다). * * 근거를 값과 함께 낸다 — 목록이 오래 해 온 그대로다(§twinModelItemList). 라이브(권위)와 저널 * 폴드(파생)는 **같은 모양의 객체**라서, 근거가 없으면 다시 계산한 값을 "지금 이렇다" 로 읽는다. 근거를 * 실을 자리가 없던 동안에는 멈춘 트윈의 저널을 아예 계산하지 않고 `—` 로 두는 편이 정직했다. 이제 * 자리가 있으니 계산한다 — 멈춘 트윈에도 마지막으로 알던 사실이 있고, 그것을 감출 이유는 없다. * * 다시 계산할 것이 없으면(모델도 저널도 없다) `null` 이다 — **없는 것과 비교하지 못한 것은 다르다.** */ private observedOf; /** * 이어진 것 — **양방향.** 선언된 관계(`TWIN_RELATIONS`)만 따라간다. * * 관계를 코드가 알지 않으므로 도메인이 늘어도 여기 손댈 것이 없다. 대신 **선언에 없는 관계는 * 그리지 않는다** — 지도에 없는 길을 그리는 것보다 없다고 두는 것이 정직하다. * * 들어오는 쪽(누가 나를 가리키나)은 그 축의 항목을 살펴야 안다. 규모 규율상 **깊이 1 · 방향별 * 상한**이고, 넘치면 몇이 더 있는지 말한다(목록으로 보낼 수 있게). */ private linksOf; /** * 선언 필드 경로 → 값들. `inputs[].material` 처럼 **배열을 지나는 경로**를 다룬다. * 배열 표기(`[]`)가 관계 선언의 문법이므로 그것을 따르는 것이 곧 선언을 존중하는 것이다. */ private fieldValue; /** * 행에서 관계 값을 꺼낸다 — FK 는 객체(관계 미로딩이면 없음)이고 문서 필드명과 컬럼명이 다를 수 있다. * * 여기서 컬럼 이름을 **축마다 표로 두지 않는다.** 후보를 순서대로 보는 편이 축이 늘 때 고칠 것이 * 없다: 관계 필드 이름 그대로 · 그 이름의 FK 객체의 id 컬럼. */ private relationValueOfRow; }