@g1cloud/entity-modeler-next 5.0.0-alpha.1 → 5.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,65 @@
1
+ import { ModelId } from './types';
2
+ import { OpShape } from '../command/op';
3
+ /**
4
+ * 투영기 입력 — 이력 레코드의 lib-로컬 최소 형태(호스트 `OpHistoryRecord`의 부분집합).
5
+ * 호스트가 `{diagramId, seq}` 정렬로 조회해 넘긴다. lib는 호스트 타입에 의존하지 않으려 여기서 재선언한다.
6
+ */
7
+ export interface FieldAuditRecord {
8
+ /** diagram 내 단조 증가 좌표 — 타임라인 정렬 키(갭 허용, 연속성 가정 금지 §5.4). */
9
+ seq: number;
10
+ /** 서버 시각(감사 표시용 패스스루). */
11
+ ts?: string | number | Date;
12
+ /** op 출처(gui/agent/rest). 감사 "누가"의 현 해상도(경로 수준, §4 결정 2). */
13
+ origin?: string;
14
+ /**
15
+ * 개별 사용자 식별자(감사 "누가"의 per-user 해상도, §4 결정 2-(나)).
16
+ * 슬라이스 1/3c 레코드에는 없음(forward-only) — 있으면 그대로 타임라인에 패스스루한다(author-aware).
17
+ */
18
+ author?: string;
19
+ /** 편집 vs 복원 축(감사 표시). */
20
+ kind?: 'edit' | 'restore';
21
+ /** kind='restore'일 때 복원 대상 seq(패스스루). */
22
+ restoredFromSeq?: number;
23
+ /** ★필드 변경의 원천. edit=배치 그대로 / restore=합성 diff. */
24
+ ops: OpShape[];
25
+ }
26
+ /**
27
+ * 감사 대상 로케이터. 설정된 ref로 대상 종류(엔티티/속성/연산/인덱스/연관/연관end/그룹)가 결정된다.
28
+ * `field`를 주면 그 필드 단일 타임라인, 생략하면 대상의 모든 변경 필드.
29
+ */
30
+ export interface FieldAuditTarget {
31
+ entityRef?: ModelId;
32
+ attributeRef?: ModelId;
33
+ operationRef?: ModelId;
34
+ indexRef?: ModelId;
35
+ associationRef?: ModelId;
36
+ groupRef?: ModelId;
37
+ end?: 'end1' | 'end2';
38
+ /** 단일 필드로 좁힘(생략 시 전 필드). */
39
+ field?: string;
40
+ }
41
+ /** 타임라인 한 엔트리 — 한 필드가 한 seq에서 얻은 값(또는 tombstone). */
42
+ export interface FieldAuditEntry {
43
+ seq: number;
44
+ ts?: string | number | Date;
45
+ origin?: string;
46
+ author?: string;
47
+ kind?: 'edit' | 'restore';
48
+ restoredFromSeq?: number;
49
+ /** 바뀐 필드명. 멤버십은 'memberEntityRefs'. */
50
+ field: string;
51
+ /** 신규 값. null=필드 비움(clear). removed=true면 undefined. */
52
+ value: unknown;
53
+ /** 직전 엔트리에서 파생한 이전 값(§3.3-(가)). 최초 born·재-add는 없음. */
54
+ oldValue?: unknown;
55
+ /** 대상/필드가 이 seq에 소멸(remove/entity.remove/group.removeMember). */
56
+ removed?: boolean;
57
+ }
58
+ /**
59
+ * op 이력 스트림을 특정 대상의 per-field 변경 타임라인으로 투영한다(순수).
60
+ *
61
+ * @param records seq 오름차순 이력 레코드(방어적으로 seq 재정렬). 각 `ops`가 필드 변경 원천.
62
+ * @param target 대상 로케이터(+ 선택적 field 필터).
63
+ * @returns seq 순 필드 감사 엔트리 배열(edit·restore 혼합, born·update·tombstone·멤버십).
64
+ */
65
+ export declare function projectFieldAudit(records: readonly FieldAuditRecord[], target: FieldAuditTarget): FieldAuditEntry[];
@@ -3,6 +3,8 @@ export interface ResolvedEntity {
3
3
  entity: Entity;
4
4
  geo: Geo;
5
5
  collapsed: boolean;
6
+ /** 편집 잠금 (layout.locked 통과) — 캔버스 draggable·인스펙터 read-only 게이트 */
7
+ locked: boolean;
6
8
  /** 이 엔티티가 속한 그룹(있으면) — 캔버스가 parent 노드로 배치 */
7
9
  groupRef?: ModelId;
8
10
  /** 헤더 바 색상 등 (레이아웃 style 참조 통과 — swatch 변경 시 computed 무효화) */
@@ -23,6 +25,8 @@ export interface ResolvedGroup {
23
25
  geo: Geo;
24
26
  /** 그룹 배경 색상 등 (레이아웃 style 참조 통과 — swatch 변경 시 computed 무효화) */
25
27
  style?: Style;
28
+ /** 편집 잠금 (layout.locked 통과) — 그룹 draggable·논리수정 게이트 */
29
+ locked: boolean;
26
30
  }
27
31
  export interface ResolvedNoteConnection {
28
32
  noteRef: ModelId;
@@ -0,0 +1,21 @@
1
+ import { DiagramLayout, LogicalModel } from './types';
2
+ import { OpShape } from '../command/op';
3
+ /** 합성기 입력 — 정합한 완전 상태(logical + layout). 호스트는 v2 doc 서브트리를 그대로 넘긴다(rev/version은 무시). */
4
+ export interface DiagramSnapshotState {
5
+ logical: LogicalModel;
6
+ layout: DiagramLayout;
7
+ }
8
+ /**
9
+ * null≡undefined≡absent 정규화 deep-equal. 스칼라/배열(인덱스별)/객체(키 합집합)를 재귀 비교한다.
10
+ * (mongo가 optional 필드 clear를 null로 저장하는 것과 target의 absent를 동치로 본다.)
11
+ */
12
+ export declare function deepEqual(a: unknown, b: unknown): boolean;
13
+ /**
14
+ * current → target 복원 diff를 forward op으로 합성한다(순수, 감사 전용 — 실행 안 됨).
15
+ *
16
+ * 산출 순서(결정성): logical(entities → associations → groups; 각 remove → add → update/child) →
17
+ * layout(entityLayouts → associationLayouts → groupLayouts → notes). 각 컬렉션은 key 정렬.
18
+ *
19
+ * @returns OpShape[] — CAS 메타(rev 숫자·layout.version) 없는 어휘 형태(호스트 이력 레코드 `ops`에 그대로 기록).
20
+ */
21
+ export declare function synthesizeRestoreOps(current: DiagramSnapshotState, target: DiagramSnapshotState): OpShape[];
@@ -141,6 +141,17 @@ export interface Attribute {
141
141
  identifier: boolean;
142
142
  notNull: boolean;
143
143
  transient?: boolean;
144
+ /**
145
+ * Hibernate `@NaturalId` — 이 속성이 엔터티의 자연키(비즈니스 키)임을 표시. PK(@Id)와는 별개 개념
146
+ * (자연키는 정의상 대리키가 아닌 도메인 유일 식별자). 프로퍼티 어노테이션이라 컬럼 레벨(unique)이 아니라
147
+ * 속성 레벨. false는 undefined로 환원해 라운드트립 diff 방지. v1 레거시엔 없는 신규 옵션(forward).
148
+ */
149
+ naturalId?: boolean;
150
+ /**
151
+ * `@NaturalId(mutable = true)` — 자연키 값의 변경 허용. Hibernate 기본은 불변(mutable=false)이므로
152
+ * undefined/false면 불변(어노테이션 인자 생략). naturalId=false일 땐 무의미(직렬화 시 정리).
153
+ */
154
+ naturalIdMutable?: boolean;
144
155
  description?: MultiLangText;
145
156
  attributeGroup?: string;
146
157
  groupCode?: string;
@@ -340,6 +351,11 @@ export interface EntityLayout {
340
351
  entityRef: ModelId;
341
352
  geo: Geo;
342
353
  collapsed?: boolean;
354
+ /**
355
+ * 편집 잠금 — 이동·크기변경·논리수정·삭제를 차단(뷰 어포던스 계층). 논리 무관·layout LWW.
356
+ * op 인터프리터·undo·replay·복원은 무시한다(간접/시스템 쓰기는 잠금 대상 아님).
357
+ */
358
+ locked?: boolean;
343
359
  displayMode?: DisplayMode;
344
360
  /** 엔티티 헤더 바 색상 등 (style.properties.swatch = 토큰명) */
345
361
  style?: Style;
@@ -362,6 +378,8 @@ export interface GroupLayout {
362
378
  groupRef: ModelId;
363
379
  geo: Geo;
364
380
  style?: Style;
381
+ /** 편집 잠금 — 그룹 박스 이동·크기변경·그룹 논리수정·삭제 차단(EntityLayout.locked 거울). */
382
+ locked?: boolean;
365
383
  /**
366
384
  * 그룹 박스에 시각적으로 포함된 노트 멤버십(레거시 `groups[].notes`). 노트는 순수 레이아웃
367
385
  * 객체(논리 의미 없음)라 멤버십도 레이아웃에 둔다 — 엔티티 멤버십(LogicalGroup.memberEntityRefs)과 비대칭.
@@ -3,6 +3,7 @@ import { EditorState } from '../command/types';
3
3
  import { DiagramMeta } from '../adapter/diagramAdapter';
4
4
  import { OpConflict } from '../command/op';
5
5
  import { OpSyncTransport } from '../command/opSync';
6
+ import { FieldAuditRecord } from '../core/projectFieldAudit';
6
7
  import { ResolvedDiagram } from '../core/resolve';
7
8
  import { RoutingMode } from '../core/routing';
8
9
  import { ValidationIssue } from '../core/validation';
@@ -36,6 +37,22 @@ export type Selection = {
36
37
  ids: ModelId[];
37
38
  anchor: ModelId;
38
39
  } | null;
40
+ /**
41
+ * (나) 필드 감사 조회 transport — 호스트가 주입하는 이력 조회 함수. diagram의 op 이력 스트림을
42
+ * seq 순 `FieldAuditRecord[]`로 반환한다. `sinceSeq`를 주면 그 이후만(증분 fetch, 기본 전량).
43
+ * op emit의 `OpSyncTransport`와 대칭 — 쓰기는 op 배치, 읽기는 감사 레코드.
44
+ */
45
+ export type HistoryTransport = (sinceSeq?: number) => Promise<FieldAuditRecord[]>;
46
+ /** 복원 결과 — 호스트 restore 라우트 응답의 lib-로컬 최소 형태(ok + 실패 사유). */
47
+ export interface RestoreOutcome {
48
+ ok: boolean;
49
+ reason?: string;
50
+ }
51
+ /**
52
+ * 시점 복원 transport — 호스트가 주입하는 복원 함수(`restoreEntityDiagram` 라우트). toSeq 시점 상태로
53
+ * forward 보상 쓰기(diagram-wide). 성공 시 라이브 doc이 바뀌므로 controller가 reloadRequest로 재적재를 요청한다.
54
+ */
55
+ export type RestoreTransport = (toSeq: number) => Promise<RestoreOutcome>;
39
56
  export interface EditorController {
40
57
  state: EditorState;
41
58
  resolved: ComputedRef<ResolvedDiagram>;
@@ -57,6 +74,8 @@ export interface EditorController {
57
74
  canUndo: Ref<boolean>;
58
75
  canRedo: Ref<boolean>;
59
76
  dirty: Ref<boolean>;
77
+ /** 모델 변경 신호 — 명령 적용마다 단조 증가. 외부 관찰자(감사 패널 등)가 재조회 트리거로 watch(디바운스 권장). */
78
+ revision: Ref<number>;
60
79
  /**
61
80
  * 편집 가능 여부 — false(조회 모드)면 모든 모델 변경(추가·삭제·이동·편집·재정렬·연결·붙여넣기·
62
81
  * undo/redo·저장)이 차단된다. 선택·팬/줌·hover 강조·복사·export 같은 읽기성 동작은 유지.
@@ -87,6 +106,28 @@ export interface EditorController {
87
106
  * `loadDiagram`으로 재적재하면 해소된다(B-5). op-mode가 아니면 항상 null.
88
107
  */
89
108
  opConflict: Ref<OpConflict | null>;
109
+ /**
110
+ * (나) 필드 감사 조회 transport — 호스트가 이력 조회 라우트(`entityDiagramHistory.get`) fetch 래퍼를
111
+ * 주입(opTransport 미러). 감사 패널이 호출해 이력 레코드를 얻고 `projectEntityAudit`로 투영한다.
112
+ * 미주입(dev/test·비-op doc) 시 undefined → 감사 패널 비활성.
113
+ */
114
+ historyTransport?: HistoryTransport;
115
+ /** 감사 패널 사용 가능 여부 — op-mode + historyTransport 주입 양쪽 충족. */
116
+ historyAvailable: ComputedRef<boolean>;
117
+ /** 시점 복원 transport(호스트 주입) — 감사 패널 '이 시점으로 복원'이 호출. */
118
+ restoreTransport?: RestoreTransport;
119
+ /** 복원 사용 가능 여부 — op-mode + editable + restoreTransport 주입(조회 모드·비-op은 불가). */
120
+ restoreAvailable: ComputedRef<boolean>;
121
+ /**
122
+ * 특정 seq 시점으로 복원 요청 — restoreTransport 위임. 성공(ok) 시 reloadRequest를 올려 호스트 재적재를 유도한다.
123
+ * transport 미주입/실패 시 { ok:false } 반환(패널이 사유 표시). editable=false면 no-op({ ok:false }).
124
+ */
125
+ restoreToSeq(toSeq: number): Promise<RestoreOutcome>;
126
+ /**
127
+ * 재적재 요청 신호(단조 증가) — 복원처럼 라이브 doc이 서버에서 바뀐 뒤, 호스트가 이 값을 watch해
128
+ * 최신 doc을 refetch → loadDiagram으로 갈아끼운다(focusRequest nonce와 같은 신호 패턴).
129
+ */
130
+ reloadRequest: Ref<number>;
90
131
  /**
91
132
  * 프리즈 후(또는 외부 변경 감지 시) 재적재 경로 — 호스트가 `fromPersisted`로 파싱한 state/meta를 주입한다
92
133
  * (생성자와 대칭 시그니처). state를 in-place 교체하고 스택을 리셋하며, 마커(schemaVersion/opWriteEnabled/
@@ -167,6 +208,10 @@ export interface EditorController {
167
208
  setEntitySwatch(id: ModelId, token: string | null): void;
168
209
  /** 엔티티 접기/펼치기 — 접으면 헤더만 표시하고 속성/메서드 칸을 숨긴다 */
169
210
  setEntityCollapsed(id: ModelId, collapsed: boolean): void;
211
+ /** 엔티티 편집 잠금 토글 — 잠그면 이동·크기·논리수정·삭제 차단(잠금 해제는 항상 허용) */
212
+ setEntityLocked(id: ModelId, locked: boolean): void;
213
+ /** 엔티티 잠금 여부 조회 (레이아웃) */
214
+ isEntityLocked(id: ModelId): boolean;
170
215
  /** 활성 다이어그램 전체 엔티티 접기/펼치기 — 사전 상태 캡처 단일 커맨드(1 undo 스텝) */
171
216
  collapseAll(): void;
172
217
  expandAll(): void;
@@ -183,6 +228,12 @@ export interface EditorController {
183
228
  }): void;
184
229
  /** 그룹 필드 부분 수정 (name·description·packageName·excludeDDLGeneration) */
185
230
  updateGroup(groupId: ModelId, patch: Partial<LogicalGroup>): void;
231
+ /** 그룹 박스 색상 토큰 지정 (null이면 해제 → 기본 그룹 배경) */
232
+ setGroupSwatch(groupId: ModelId, token: string | null): void;
233
+ /** 그룹 편집 잠금 토글 — 잠그면 그룹 박스 이동·크기·그룹 논리수정·삭제 차단 */
234
+ setGroupLocked(groupId: ModelId, locked: boolean): void;
235
+ /** 그룹 잠금 여부 조회 (레이아웃) */
236
+ isGroupLocked(groupId: ModelId): boolean;
186
237
  /** 선택 엔티티들로 새 그룹 생성 (멤버 bbox에 박스 배치) */
187
238
  createGroup(entityIds: ModelId[], name?: string): ModelId | null;
188
239
  /** 빈 그룹 박스 생성 (이후 드래그로 엔티티 편입) */
@@ -326,6 +377,8 @@ export interface EditorController {
326
377
  height: number;
327
378
  }): void;
328
379
  setNoteMemo(noteId: ModelId, memo: string): void;
380
+ /** 노트 색상 토큰 지정 (null이면 해제 → 기본 노트 배경) */
381
+ setNoteSwatch(noteId: ModelId, token: string | null): void;
329
382
  /** 노트 → 대상(엔티티) 연결선 추가/삭제 + 꺾은점 편집 */
330
383
  addNoteConnection(noteId: ModelId, targetRef: ModelId): void;
331
384
  removeNoteConnection(noteId: ModelId, targetRef: ModelId): void;
@@ -358,6 +411,19 @@ export declare function createEditorController(initial?: EditorState, options?:
358
411
  * 어댑터가 활성(미주입 = dev/test → 어댑터 비활성, full-replace 저장 경로 유지).
359
412
  */
360
413
  opTransport?: OpSyncTransport;
414
+ /**
415
+ * (나) 필드 감사 조회 transport(`entityDiagramHistory.get` fetch 래퍼). 주입 + op-mode 시에만 감사
416
+ * 패널 활성(미주입 = dev/test·비-op doc → 패널 비활성). opTransport(쓰기)와 대칭인 읽기 채널.
417
+ */
418
+ historyTransport?: HistoryTransport;
419
+ /** 시점 복원 transport(`restoreEntityDiagram` 라우트). 주입 + op-mode + editable 시 감사 패널 '복원' 활성. */
420
+ restoreTransport?: RestoreTransport;
421
+ /**
422
+ * op 전송 실패(4xx/5xx/네트워크로 transport가 throw) 통지 — 진단용(opt-in). 하드 프리즈는 별도로
423
+ * 발생하며(opConflict.kind='missing'), 이 콜백은 소실될 원 에러를 호스트가 로깅/리포팅하도록 넘긴다.
424
+ * 미주입이어도 어댑터가 콘솔에 남긴다(정상 rev/layout 충돌은 이 경로가 아님 — throw만).
425
+ */
426
+ onOpError?: (err: unknown) => void;
361
427
  /**
362
428
  * 검증 컨텍스트 — 카탈로그/정책 의존 규칙을 깨우는 호스트 주입(미주입 시 해당 규칙 skip).
363
429
  * selectableDataTypes(CHK-TYPE-1)는 코어 상수(SELECTABLE_DATA_TYPES)라 dev/호스트가 즉시 주입 가능.