export declare class TwinSpaceResolver { /** * 이 테넌트의 현장 목록. * * ── 세 번만 묻는다 (2026-08-13) ────────────────────────────────────────── * 예전에는 현장마다 표현 수를 세고 인스턴스를 조회했다 — 현장 13곳이면 **질의 27번**이고, 첫 * 호출이 2.4초였다(헤더가 뜰 때마다 이 목록을 읽는다). 규모가 커지면 그대로 자란다. * * 이제 세 번 묻고 메모리에서 맞춘다: 현장 · 표현(공간 id 만) · 인스턴스(필요한 컬럼만). * 표현은 **id 만 실어 온다**(`loadRelationIds`) — 설정 blob 을 읽어 세는 것은 낭비다. */ twinSpaces(context: ResolverContext): Promise; /** 단건 — 표현(+영역) 트리 포함. */ twinSpace(spaceId: string, context: ResolverContext): Promise; saveTwinSpace(spaceId: string, patch: any, context: ResolverContext): Promise; /** * 공간 삭제 — **이 공간의 트윈이 있으면 거절한다.** 그래서 트윈이 현장을 잃는 일은 없다. * * ── 왜 모양을 바꿨나 (2026-08-13) ──────────────────────────────────────── * 예전에는 `Boolean` 을 돌려주고 거절은 **한국어 문장을 냈다.** 두 가지가 틀렸다: * ① 서버가 화면의 말을 정했다 — 일본어·스페인어 사용자에게 한국어가 새어 나간다. * ② 오류를 낸 예외를 화면이 받지 않아 **아무 일도 없는 것처럼** 보였다. 사용자는 삭제를 눌렀고 * 화면은 그대로였다. 거절을 알리지 않고 하는 것은 실패보다 나쁘다. * 이제 `{ok, errorCode, errorParams}` 로 낸다 — 화면이 `twin.compose.del.` 로 말을 만든다. */ deleteTwinSpace(spaceId: string, context: ResolverContext): Promise; /** * 이미 있는 트윈을 이 현장으로 가져온다 — **소속 갱신**(이력 이전이 아니다). * * 저널·투영 행은 `instanceId` 로 매여 있어 트윈을 따라오고, 구역·표현은 공간의 것이라 남는다 * (근거·판정: `move-space.ts`). 그래서 이 뮤테이션이 쓰는 것은 두 곳뿐이다 — * 레지스트리의 `spaceId` 와 저장된 model 의 `spaceId`(커널·보드가 같은 공간을 가리켜야 한다). * 새 공간의 시간대로 `utcOffsetMinutes` 도 다시 파생한다(공간이 시간의 기준이다). * * `dryRun` 은 **같은 판정을 미리** 보여 준다 — 화면이 잃을 것을 먼저 말하고 사용자가 정한다. * 판정을 두 벌로 두면 미리보기와 실제가 어긋나므로 한 함수를 두 번 부른다. */ moveTwinToSpace(instanceId: string, spaceId: string, context: ResolverContext, dryRun?: boolean): Promise; /** * 트윈을 현장에서 뗀다 — **어느 현장에도 속하지 않음**으로 되돌린다. * * 더하기·옮기기만 있으면 잘못 넣은 것을 되돌릴 수 없다. 떼도 저널·로케이션·설비는 트윈에 남고 * (`instanceId` 로 매여 있다), 구역·표현은 옛 현장에 남는다. 잃는 것은 **볼 무대**다 — * 판정이 그것을 말한다(`judgeDetachTwinSpace`). `dryRun` 은 같은 판정을 미리 낸다. */ detachTwinFromSpace(instanceId: string, context: ResolverContext, dryRun?: boolean): Promise; /** * 공간 ↔ 트윈 ↔ 가시화 정합성 점검 — **사실을 모아 순수 판정에 넘긴다.** * * 세 축은 서로를 id 로만 가리키고 DB 가 그 참조를 지켜 주지 않는다. 트윈을 옮기거나 떼거나 원본을 * 다시 읽으면 아무 오류 없이 **가리킬 것이 없는 도형**과 **소속 없는 로케이션**이 남는다. 사람이 * 눈으로 대조하던 일을 기계가 한다(판정·근거: `space-integrity.ts`). * * `spaceId` 를 주면 그 현장만, 없으면 테넌트 전체를 본다. */ twinSpaceIntegrity(context: ResolverContext, spaceId?: string): Promise; /** * 기계적으로 고칠 수 있는 어긋남만 고친다 — **사람의 판단이 필요한 것은 손대지 않는다.** * * 지금 고치는 것은 하나다: **대표 표현 포인터**. 공간이 없는 표현 id 를 가리키고 있으면, 행의 * `isPrimary` 가 켜진 표현(없으면 첫 표현)으로 다시 가리키고, 표현이 없으면 비운다. 근거가 있고 * 답이 하나뿐인 부류라 자동으로 고쳐도 사실을 바꾸지 않는다. * * 폴리곤이 없는 구역·개체를 가리키는 것은 **고치지 않는다.** 그 도형을 지워야 하는지, 트윈을 다시 * 데려와야 하는지, 구역을 다시 그려야 하는지는 사람이 정할 일이다 — 기계가 고르면 사용자가 그린 * 도형이 오류 없이 사라진다. */ repairTwinSpaceIntegrity(context: ResolverContext, spaceId?: string): Promise; twinAreas(spaceId: string, context: ResolverContext): Promise; saveTwinArea(spaceId: string, areaId: string, patch: any, context: ResolverContext): Promise; deleteTwinArea(spaceId: string, areaId: string, context: ResolverContext): Promise; saveSpaceRepresentation(spaceId: string, rep: any, context: ResolverContext): Promise; deleteSpaceRepresentation(id: string, context: ResolverContext): Promise; setPrimaryRepresentation(spaceId: string, repId: string, context: ResolverContext): Promise; saveSpaceArea(representationId: string, area: any, context: ResolverContext): Promise; deleteSpaceArea(id: string, context: ResolverContext): Promise; }