import { Field, Int, ObjectType } from 'type-graphql' import { TwinEvent } from './twin-event.js' /* * 저널 목록 반환형 — things-factory 표준 `{ items, total }`(AttributeSetList·DomainList 등과 동형). * * `total` 이 이 타입의 존재 이유다. 기존 `twinEvents` 는 배열만 돌려줘서 **화면이 자기가 전체를 받은 * 건지 잘린 건지 알 방법이 없었다** — 그래서 리스트가 알리지 않고 잘린 채로 "이게 전부" 처럼 보였다. * 총건수를 함께 주면 화면은 "48 / 12,904" 라고 정직하게 말할 수 있고, 사용자는 좁혀야 한다는 걸 안다. */ @ObjectType({ description: 'A page of twin journal events together with the total number of matching records.' }) export class TwinEventList { @Field(type => [TwinEvent], { description: 'The events on this page, ordered by the requested sorting (revision descending by default).' }) items: TwinEvent[] /* * 전체 수 — **상한을 넘으면 비운다.** * * 세는 데도 값이 든다(2026-08-22 실측: 저널 358만 행인 트윈에서 전량 세기 5.32초 · 상한 1만까지 * 0.04초). 그래서 상한까지만 세고, 넘으면 「모른다」로 둔다. 그때 상한값을 전체로 적으면 화면이 * 거짓을 말한다 — 없는 것과 모르는 것을 가르는 것이 이 필드의 규율이다. */ @Field(type => Int, { nullable: true, description: 'Total number of events matching the filters, ignoring pagination. Lets the caller show an honest "shown of total" count instead of silently truncating. NULL when the server stopped counting at countCap: the exact total is then unknown, and capped says so — do not render the cap as if it were the total.' }) total?: number @Field({ nullable: true, description: 'True when there are more matching events than countCap, so total could not be established. The caller should say "first N shown" and offer narrowing rather than implying it received everything.' }) capped?: boolean @Field(type => Int, { nullable: true, description: 'The counting limit the server applied. Reported so the screen can say how far the count is trustworthy instead of guessing.' }) countCap?: number /* * 다음 페이지 커서. 저널은 **머리에 계속 쌓이는 목록**이라 offset 으로 뒤를 읽으면 * 읽는 사이 들어온 이벤트만큼 밀려 본 행이 또 나오거나 못 본 행이 사라진다. * 이 값을 그대로 다음 요청의 `pagination.after` 로 돌려주면 그 문제가 없다. */ @Field({ nullable: true, description: 'Opaque cursor for the next page. Pass it back as pagination.after to continue exactly where this page ended, without the duplicate or skipped rows that offset paging produces on a journal that keeps growing at the head. Null when this page is the last one.' }) nextCursor?: string /* * **앞부분이 지워졌다** — 보관 기간 정리가 이 트윈의 오래된 사건을 지운 경우 (2026-08-27). * * 정리는 선언된 보관 기간(기본 7일)보다 오래된 사건을 지운다. 그러면 이 목록의 첫 페이지 뒤로 더 * 내려가도 어느 지점에서 기록이 끝난다. 화면이 그것을 말하지 않으면 사람은 「이 트윈은 그때부터 * 시작했다」로 읽는다. 없었던 것과 지워진 것은 다른 사실이다. * * 값은 저장하지 않고 조회할 때 구한다(남아 있는 가장 작은 리비전). 저장하면 실제 데이터와 어긋날 수 * 있고, 어긋나면 어느 쪽이 사실인지 알 수 없다. */ @Field(type => Int, { nullable: true, description: 'The oldest revision still stored for this twin. When it is greater than 1, older events were deleted by the journal retention policy: the screen must say the record starts here rather than implying the twin began at this point. NULL when the caller asked for more than one twin (the axis is per twin) or when nothing is stored.' }) oldestRevision?: number }