@simplysm/sd-claude 14.0.84 → 14.0.86
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.
- package/claude/references/sd-simplysm14/README.md +7 -1
- package/claude/references/sd-simplysm14/manuals/client-app-structure.md +140 -0
- package/claude/references/sd-simplysm14/manuals/client-component.md +6 -5
- package/claude/references/sd-simplysm14/manuals/client-orm.md +62 -0
- package/claude/references/sd-simplysm14/manuals/client-service.md +96 -0
- package/claude/references/sd-simplysm14/manuals/client-shared-data.md +146 -0
- package/claude/references/sd-simplysm14/manuals/client-system-log.md +96 -0
- package/claude/references/sd-simplysm14/manuals/data-log.md +209 -0
- package/claude/references/sd-simplysm14/manuals/event.md +135 -0
- package/claude/rules/sd-design-rules.md +8 -0
- package/claude/sd-system-prompt.md +35 -14
- package/claude/skills/sd-config/SKILL.md +1 -0
- package/claude/skills/sd-demo/SKILL.md +1 -1
- package/claude/skills/sd-dev/SKILL.md +1 -1
- package/claude/skills/sd-docs/SKILL.md +1 -1
- package/claude/skills/sd-impl/SKILL.md +15 -10
- package/claude/skills/sd-impl/evals/fixtures/case-a-new-screen/.specs/260513120000_warehouse/spec.md +1 -1
- package/claude/skills/sd-impl/evals/fixtures/case-b-update-with-demo/.specs/260513120000_warehouse/spec.md +1 -1
- package/claude/skills/sd-impl/evals/fixtures/case-c-new-cross/.specs/260513120000_warehouse/spec.md +2 -2
- package/claude/skills/sd-impl/evals/fixtures/case-d-spec-modify/.specs/260513120000_warehouse/spec.md +1 -1
- package/claude/skills/sd-impl/evals/golden.jsonl +1 -1
- package/claude/skills/sd-manual/SKILL.md +51 -0
- package/claude/skills/sd-manual/evals/fixtures/new-manual/src/notification.ts +25 -0
- package/claude/skills/sd-manual/evals/fixtures/update-manual/.claude/references/sd-simplysm14/manuals/notification.md +14 -0
- package/claude/skills/sd-manual/evals/fixtures/update-manual/src/notification.ts +37 -0
- package/claude/skills/sd-manual/evals/golden.jsonl +2 -0
- package/claude/skills/sd-review/SKILL.md +3 -3
- package/claude/skills/sd-skill/SKILL.md +1 -1
- package/claude/skills/sd-spec/SKILL.md +65 -67
- package/claude/skills/sd-spec/evals/fixtures/case-a-split//355/232/214/354/235/230/353/241/235.md +20 -0
- package/claude/skills/sd-spec/evals/fixtures/case-b-detail/.specs/260513120000_warehouse/spec.md +95 -0
- package/claude/skills/sd-spec/evals/golden.jsonl +2 -0
- package/claude/skills/sd-spec/references/example-spec.md +14 -47
- package/claude/skills/sd-unpack/SKILL.md +1 -1
- package/claude/skills/sd-use/SKILL.md +1 -0
- package/package.json +1 -1
- package/claude/references/sd-simplysm14/manuals/client-setup.md +0 -154
|
@@ -85,11 +85,11 @@ flowchart LR
|
|
|
85
85
|
|
|
86
86
|
관련 섹션: [화면.재고 확인], [자동 처리.재고 스냅샷]
|
|
87
87
|
|
|
88
|
-
### 3.2
|
|
88
|
+
### 3.2 시스템 기반 [확정: 2026-04-01]
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
앱 운영을 떠받치는 기반 구조 — 메뉴 트리·화면 접근 권한·기능 모듈 구성 — 를 한 곳에서 정의·관리할 수 있어야 함.
|
|
91
91
|
|
|
92
|
-
관련 섹션: [
|
|
92
|
+
관련 섹션: [기반.앱 구조 정의]
|
|
93
93
|
|
|
94
94
|
## 4. 화면
|
|
95
95
|
|
|
@@ -409,41 +409,27 @@ Actor: 창고 관리자
|
|
|
409
409
|
- 대처: 관리자에게 알림 발송. 동일 일자에 재실행할 경우 (날짜, 박스) 유일성 제약으로 중복 생성을 방지
|
|
410
410
|
- 재시도 한계: 자동 재시도 없음 (다음 날 0시에 정상 동작)
|
|
411
411
|
|
|
412
|
-
## 6.
|
|
412
|
+
## 6. 공통·기반 기능
|
|
413
413
|
|
|
414
|
-
### 6.1
|
|
414
|
+
### 6.1 앱 구조 정의 [확정: 2026-04-01]
|
|
415
415
|
|
|
416
|
-
목적:
|
|
416
|
+
목적: 앱의 메뉴 트리·화면 접근 권한·기능 모듈 구성을 한 곳에서 정의
|
|
417
417
|
|
|
418
|
-
|
|
419
|
-
- 마스터 엔티티의 insert·update·delete 트랜잭션 commit 시점
|
|
420
|
-
- 적용 대상 모델: [모델.품목], [모델.Location]
|
|
421
|
-
- 적용 제외 모델 (트랜잭션 모델): [모델.재고], [모델.재고 스냅샷]
|
|
418
|
+
트리거·적용 범위: 앱 부팅 시 / admin·PDA 클라이언트별 (클라이언트마다 자기 메뉴 배열을 정의)
|
|
422
419
|
|
|
423
|
-
관련 섹션: [
|
|
420
|
+
관련 섹션: [기타.시스템 기반], [화면.품목 관리], [화면.Location 관리], [화면.입고 스캔], [화면.재고 확인]
|
|
424
421
|
|
|
425
|
-
|
|
422
|
+
참조 매뉴얼: client-app-structure.md
|
|
426
423
|
|
|
427
|
-
|
|
428
|
-
- [모델.DataLog] 에 1행 적재 (테이블명·키·변경 전·변경 후·작업자·시각)
|
|
424
|
+
### 6.2 마스터 변경 시 캐시 무효화 [확정: 2026-04-01]
|
|
429
425
|
|
|
430
|
-
|
|
426
|
+
목적: 마스터 변경이 전 클라이언트 조회에 지체 없이 반영되도록 보장
|
|
431
427
|
|
|
432
|
-
|
|
433
|
-
- 위험: 변경 이력 추적 누락
|
|
434
|
-
- 대처: 원본 마스터 트랜잭션은 정상 commit 유지하고, DataLog 적재 실패만 별도 큐에 적재한 뒤 관리자에게 알림
|
|
435
|
-
- 재시도 한계: 큐에서 지수 백오프로 5회까지 재시도 후 운영팀에 알림
|
|
428
|
+
트리거·적용 범위: [모델.품목]·[모델.Location] 의 insert·update·delete commit 시점 (부수효과) / 전체 클라이언트
|
|
436
429
|
|
|
437
|
-
|
|
430
|
+
관련 섹션: [프로세스.입고], [모델.품목], [모델.Location]
|
|
438
431
|
|
|
439
|
-
|
|
440
|
-
| --------------------- | ------------------------------- |
|
|
441
|
-
| [모델.DataLog.테이블명] | 변경 대상 모델명 (예: `품목`) |
|
|
442
|
-
| [모델.DataLog.키] | 변경 대상 ID |
|
|
443
|
-
| [모델.DataLog.변경 전] | 컬럼별 변경 전 값 (JSON) |
|
|
444
|
-
| [모델.DataLog.변경 후] | 컬럼별 변경 후 값 (JSON) |
|
|
445
|
-
| [모델.DataLog.작업자] | 세션 사용자 |
|
|
446
|
-
| [모델.DataLog.시각] | 변경 commit 시각 |
|
|
432
|
+
해당 마스터의 공유 캐시를 무효화하여 클라이언트가 다음 조회 시 최신 데이터를 재적재하도록 함.
|
|
447
433
|
|
|
448
434
|
## 7. 공통 정의
|
|
449
435
|
|
|
@@ -571,25 +557,6 @@ Actor: 창고 관리자
|
|
|
571
557
|
- 식별 키: ID (자동 부여)
|
|
572
558
|
- 비즈니스 키: (날짜, 박스) 조합이 유일
|
|
573
559
|
|
|
574
|
-
### 8.6 DataLog [확정: 2026-04-01]
|
|
575
|
-
|
|
576
|
-
필드:
|
|
577
|
-
|
|
578
|
-
| 필드 | 타입 | 필수 | 비고 |
|
|
579
|
-
| -------- | ---- | ---- | ------------------------------------- |
|
|
580
|
-
| ID | 숫자 | O | 자동 부여 |
|
|
581
|
-
| 테이블명 | 문자 | O | 변경 대상 모델명 (예: `품목`) |
|
|
582
|
-
| 키 | 숫자 | O | 변경 대상 ID |
|
|
583
|
-
| 변경 전 | JSON | X | 컬럼별 이전 값. insert 시 null |
|
|
584
|
-
| 변경 후 | JSON | X | 컬럼별 변경 후 값. delete 시 null |
|
|
585
|
-
| 작업자 | 문자 | O | 세션 사용자 |
|
|
586
|
-
| 시각 | 일시 | O | 변경 commit 시각 |
|
|
587
|
-
|
|
588
|
-
키/제약:
|
|
589
|
-
|
|
590
|
-
- 식별 키: ID (자동 부여)
|
|
591
|
-
- 인덱스: (테이블명, 키, 시각) — 특정 엔티티의 변경 이력 조회 용도
|
|
592
|
-
|
|
593
560
|
## 9. 외부 인터페이스
|
|
594
561
|
|
|
595
562
|
### 9.1 ERP 입고 통보 [확정: 2026-04-01]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sd-unpack
|
|
3
3
|
description: 메일·문서(eml/msg/pdf/docx/pptx/xlsx/xlsb, 레거시 doc/ppt/xls)를 첨부 포함 재귀적으로 풀어 평문 트리로 펼치기. Use when 위 형식 파일의 본문·첨부 전반을 훑어야 할 때 (분석·요약·정리·검토 등). 단순 단답 조회(특정 값/셀 확인)나 옆에 이미 펼친 `<basename>_<ext>/` 폴더가 있으면 호출 금지.
|
|
4
|
-
|
|
4
|
+
model: haiku
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# sd-unpack
|
package/package.json
CHANGED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
# 클라이언트 환경 셋업 매뉴얼
|
|
2
|
-
|
|
3
|
-
화면 작성 시점에는 거의 건드리지 않음. 새 앱 부트스트랩 시 또는 새 서비스/마스터 데이터를 추가할 때만 참조.
|
|
4
|
-
|
|
5
|
-
## AppServiceProvider
|
|
6
|
-
|
|
7
|
-
`@simplysm/service-client` 위에 앱이 만드는 root provider. 서비스·이벤트 프록시와 ORM(Object-Relational Mapping) 커넥터를 lazy 캐싱으로 노출.
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
@Injectable({ providedIn: "root" })
|
|
11
|
-
export class AppServiceProvider {
|
|
12
|
-
private readonly _sdServiceClientFactory = inject(SdServiceClientFactoryProvider);
|
|
13
|
-
|
|
14
|
-
private _orm?: OrmClientConnector;
|
|
15
|
-
private _user?: ServiceProxy<UserServiceType>;
|
|
16
|
-
private _authInfoEvent?: ClientEventProxy<typeof AuthInfoEvent>;
|
|
17
|
-
// ...
|
|
18
|
-
|
|
19
|
-
get client() {
|
|
20
|
-
return this._sdServiceClientFactory.get("MAIN");
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
get orm(): OrmClientConnector {
|
|
24
|
-
return (this._orm ??= createOrmClientConnector(this.client));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
get user(): ServiceProxy<UserServiceType> {
|
|
28
|
-
return (this._user ??= this.client.getService<UserServiceType>("User"));
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
get authInfoEvent(): ClientEventProxy<typeof AuthInfoEvent> {
|
|
32
|
-
return (this._authInfoEvent ??= this.client.getEvent<typeof AuthInfoEvent>("AuthInfo"));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async connectAsync() {
|
|
36
|
-
await this._sdServiceClientFactory.connectAsync("MAIN");
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
**약속**:
|
|
42
|
-
|
|
43
|
-
- `@Injectable({ providedIn: "root" })`.
|
|
44
|
-
- 서비스·이벤트는 `private _xxx?` 캐시 필드 + getter 로 노출. lazy 초기화는 `??=` 패턴 사용.
|
|
45
|
-
- 서비스: `client.getService<XxxServiceType>("XxxName")` 호출. 이벤트: `client.getEvent<typeof XxxEvent>("XxxName")` 호출.
|
|
46
|
-
- ORM 커넥터: `createOrmClientConnector(this.client)` 결과를 `orm` getter 로 노출.
|
|
47
|
-
- `connectAsync()` — 앱 부트스트랩 시점에 서버 연결 수행.
|
|
48
|
-
|
|
49
|
-
## AppOrmProvider
|
|
50
|
-
|
|
51
|
-
`AppServiceProvider.orm` 위에 앱별 DB(데이터베이스) 설정(DbContext·데이터베이스명·스키마명)을 고정해 둔 root provider.
|
|
52
|
-
|
|
53
|
-
```ts
|
|
54
|
-
@Injectable({ providedIn: "root" })
|
|
55
|
-
export class AppOrmProvider {
|
|
56
|
-
private readonly _appService = inject(AppServiceProvider);
|
|
57
|
-
|
|
58
|
-
connectAsync<R>(callback: (db: MainDbContext) => Promise<R>): Promise<R> {
|
|
59
|
-
return this._appService.orm.connect(
|
|
60
|
-
{
|
|
61
|
-
DbClass: MainDbContext,
|
|
62
|
-
connOpt: { configName: "MAIN" },
|
|
63
|
-
dbContextOpt: { database: "...", schema: "dbo" },
|
|
64
|
-
},
|
|
65
|
-
callback,
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
connectWithoutTransAsync<R>(callback: (db: MainDbContext) => Promise<R>): Promise<R> {
|
|
70
|
-
return this._appService.orm.connectWithoutTransaction(
|
|
71
|
-
{ /* 같은 옵션 */ },
|
|
72
|
-
callback,
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
**약속**:
|
|
79
|
-
|
|
80
|
-
- `@Injectable({ providedIn: "root" })`.
|
|
81
|
-
- DbContext 는 앱별로 정의 (예: `@adtek/db-main` 의 `MainDbContext`).
|
|
82
|
-
- 기본 메서드는 `connectAsync` (트랜잭션 포함). `connectWithoutTransAsync` 는 initialize 등 트랜잭션 안에서 동작하지 않는 작업 전용 헬퍼.
|
|
83
|
-
- 콜백의 반환값이 그대로 메서드의 반환값이 됨.
|
|
84
|
-
|
|
85
|
-
## AppSharedDataProvider
|
|
86
|
-
|
|
87
|
-
`@simplysm/angular` 의 `SdSharedDataProvider` 를 상속하여 화면에서 자주 참조하는 마스터 데이터(고객사·품목·로케이션 등)를 등록한 root provider.
|
|
88
|
-
|
|
89
|
-
```ts
|
|
90
|
-
export function useSharedSignal<K extends keyof TAppSharedData>(
|
|
91
|
-
name: K,
|
|
92
|
-
): SharedDataHandle<TAppSharedData[K]> {
|
|
93
|
-
const appSharedData = inject(AppSharedDataProvider);
|
|
94
|
-
return appSharedData.getHandle(name);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
@Injectable({ providedIn: "root" })
|
|
98
|
-
export class AppSharedDataProvider extends SdSharedDataProvider<TAppSharedData> {
|
|
99
|
-
private readonly _appOrm = inject(AppOrmProvider);
|
|
100
|
-
|
|
101
|
-
override initialize() {
|
|
102
|
-
this.register("고객사", {
|
|
103
|
-
serviceKey: "MAIN",
|
|
104
|
-
getter: async (changeKeys) => {
|
|
105
|
-
return this._appOrm.connectAsync(async (db) => {
|
|
106
|
-
let qr = db.customer().select((item) => ({
|
|
107
|
-
id: item.id,
|
|
108
|
-
code: item.code,
|
|
109
|
-
name: item.name,
|
|
110
|
-
isDeleted: item.isDeleted,
|
|
111
|
-
|
|
112
|
-
__valueKey: item.id,
|
|
113
|
-
__searchText: expr.concat(item.code, "|_|", item.name),
|
|
114
|
-
__isHidden: item.isDeleted,
|
|
115
|
-
}));
|
|
116
|
-
|
|
117
|
-
if (changeKeys) {
|
|
118
|
-
qr = qr.where((item) => [expr.in(item.id, changeKeys as number[])]);
|
|
119
|
-
}
|
|
120
|
-
return qr.execute();
|
|
121
|
-
});
|
|
122
|
-
},
|
|
123
|
-
orderBy: (item) => item.code,
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// ... 다른 마스터 데이터 등록 ...
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export type TAppSharedData = {
|
|
131
|
-
고객사: ISharedCustomer;
|
|
132
|
-
// ...
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
export interface ISharedCustomer extends SharedDataBase<number> {
|
|
136
|
-
id: number;
|
|
137
|
-
code: string;
|
|
138
|
-
name: string;
|
|
139
|
-
isDeleted: boolean;
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
**약속**:
|
|
144
|
-
|
|
145
|
-
- `@Injectable({ providedIn: "root" })` 사용, `SdSharedDataProvider<TAppSharedData>` 를 상속.
|
|
146
|
-
- 등록은 `override initialize()` 안에서 `this.register(name, opts)` 호출로 수행.
|
|
147
|
-
- 각 항목의 인터페이스는 `SharedDataBase<TKey>` 를 상속.
|
|
148
|
-
- getter 의 select 결과에 다음 매직 필드를 포함:
|
|
149
|
-
- `__valueKey` — 항목의 키.
|
|
150
|
-
- `__searchText` — 검색용 텍스트.
|
|
151
|
-
- `__isHidden` — 숨김 여부 (예: `isDeleted` 값으로 지정).
|
|
152
|
-
- `getter(changeKeys)` 의 `changeKeys` 인자가 주어지면 해당 키들만 다시 조회 (incremental refresh).
|
|
153
|
-
- `orderBy` 는 정렬 키를 반환하는 함수 (예: `(item) => item.code`).
|
|
154
|
-
- `useSharedSignal<K>(name)` 헬퍼 함수를 함께 export — 컴포넌트는 inject 없이 이름만으로 접근 가능.
|