@things-factory/figure-service 10.1.6 → 10.1.7
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/dist-server/service/figure/figure-query.js +8 -1
- package/dist-server/service/figure/figure-query.js.map +1 -1
- package/dist-server/service/figure/figure-type.d.ts +2 -0
- package/dist-server/service/figure/figure-type.js +8 -0
- package/dist-server/service/figure/figure-type.js.map +1 -1
- package/dist-server/service/figure/figure.d.ts +17 -1
- package/dist-server/service/figure/figure.js +6 -1
- package/dist-server/service/figure/figure.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/server/service/figure/catalog-db.test.ts +162 -0
- package/server/service/figure/figure-query.ts +8 -1
- package/server/service/figure/figure-type.ts +10 -0
- package/server/service/figure/figure.ts +22 -2
|
@@ -24,7 +24,14 @@ let FigureQuery = class FigureQuery {
|
|
|
24
24
|
params,
|
|
25
25
|
domain,
|
|
26
26
|
alias: 'figure',
|
|
27
|
-
|
|
27
|
+
/*
|
|
28
|
+
`tags` 도 찾을 수 있어야 한다 — 태그의 값은 붙이는 데 있지 않고 **찾는 데** 있다.
|
|
29
|
+
|
|
30
|
+
`simple-json` 이라 칸에는 `["반출","자동"]` 이 통째로 들어 있고, LIKE 는 그 글자를
|
|
31
|
+
본다. 「반출」로 찾으면 걸린다. 정확히 그 태그만 걸리는 것은 아니지만(이름에 「반출」이
|
|
32
|
+
든 도형도 걸린다) 찾기로는 그것이 오히려 낫다.
|
|
33
|
+
*/
|
|
34
|
+
searchables: ['type', 'name', 'description', 'category', 'tags']
|
|
28
35
|
});
|
|
29
36
|
const [items, total] = await queryBuilder.getManyAndCount();
|
|
30
37
|
return { items, total };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-query.js","sourceRoot":"","sources":["../../../server/service/figure/figure-query.ts"],"names":[],"mappings":";;;;AAAA,qCAA4B;AAC5B,+CAAyE;AAEzE,iDAAuG;AAEvG,2CAAoC;AACpC,2DAAmD;AACnD,qDAAgD;AAChD,qDAA+D;AAGxD,IAAM,WAAW,GAAjB,MAAM,WAAW;IAGhB,AAAN,KAAK,CAAC,MAAM,CAAY,EAAU,EAAS,OAAwB;QACjE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEhC,6CAA6C;QAC7C,OAAO,MAAM,IAAA,qBAAa,EAAC,kBAAM,CAAC,CAAC,OAAO,CAAC;YACzC,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAA,YAAE,EAAC,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE;SAChF,CAAC,CAAA;IACJ,CAAC;IAIK,AAAN,KAAK,CAAC,OAAO,CAAS,MAAiB,EAAS,OAAwB;QACtE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEhC,MAAM,YAAY,GAAG,IAAA,qCAA6B,EAAC;YACjD,UAAU,EAAE,IAAA,qBAAa,EAAC,kBAAM,CAAC;YACjC,MAAM;YACN,MAAM;YACN,KAAK,EAAE,QAAQ;YACf,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"figure-query.js","sourceRoot":"","sources":["../../../server/service/figure/figure-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\nimport { Args, Arg, Ctx, Directive, Query, Resolver } from 'type-graphql'\n\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\n\nimport { Figure } from './figure.js'\nimport { FigureHistory } from './figure-history.js'\nimport { inspectSource } from './figure-gate.js'\nimport { FigureInspection, FigureList } from './figure-type.js'\n\n@Resolver(Figure)\nexport class FigureQuery {\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => Figure, { nullable: true, description: 'Finds a single figure by its ID.' })\n async figure(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Figure> {\n const { domain } = context.state\n\n // 부모 도메인의 Figure 도 보인다 — Board 와 같은 범위 규칙이다.\n return await getRepository(Figure).findOne({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id }\n })\n }\n\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => FigureList, { description: 'Lists figures. Sortable by score, triangles, name, updatedAt.' })\n async figures(@Args() params: ListParam, @Ctx() context: ResolverContext): Promise<FigureList> {\n const { domain } = context.state\n\n const queryBuilder = getQueryBuilderFromListParams({\n repository: getRepository(Figure),\n params,\n domain,\n alias: 'figure',\n /*\n `tags` 도 찾을 수 있어야 한다 — 태그의 값은 붙이는 데 있지 않고 **찾는 데** 있다.\n\n `simple-json` 이라 칸에는 `[\"반출\",\"자동\"]` 이 통째로 들어 있고, LIKE 는 그 글자를\n 본다. 「반출」로 찾으면 걸린다. 정확히 그 태그만 걸리는 것은 아니지만(이름에 「반출」이\n 든 도형도 걸린다) 찾기로는 그것이 오히려 낫다.\n */\n searchables: ['type', 'name', 'description', 'category', 'tags']\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n /**\n * 등록된 타입 이름 목록.\n *\n * 저작 화면이 **새 타입 이름이 이미 쓰이는지** 물어보는 데 쓴다. `type` 은 저장되는\n * 식별자라 만든 뒤에 고칠 수 없으므로, 만들기 전에 알려 줘야 한다.\n *\n * `state` 로 걸러지지 않는다 — `draft` 인 Figure 의 이름도 이미 점유된 것이다.\n */\n /**\n * 발행된 판들 — 최근 것부터.\n *\n * 저작 중 저장은 여기 없다. 판본은 발행에서만 생기므로(`releaseFigure`), 이 목록이 곧\n * 「이 도형이 몇 번 약속되었나」다.\n */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [FigureHistory], { description: 'Released versions of a figure, newest first.' })\n async figureVersions(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<FigureHistory[]> {\n const { domain } = context.state\n\n return await getRepository(FigureHistory).find({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, originalId: id },\n relations: ['updater'],\n order: { version: 'DESC' },\n take: 10\n })\n }\n\n /**\n * 지금 소비처가 쓰는 판.\n *\n * 도형의 현재 정본은 저작 중일 수 있다(초안). 배치된 것이 보는 것은 **마지막으로 발행된 판**이고,\n * 그것을 이 자리가 답한다.\n */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => FigureHistory, { nullable: true, description: 'The most recently released version of a figure.' })\n async figureReleased(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<FigureHistory> {\n const { domain } = context.state\n\n return await getRepository(FigureHistory).findOne({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, originalId: id },\n order: { version: 'DESC' }\n })\n }\n\n /**\n * 발행해도 되나 — **누르기 전에** 묻는 자리.\n *\n * 판정은 `figure-gate.ts` 가 하고 이 자리는 정본을 꺼내 넘긴다. 같은 판정을 `releaseFigure` 도\n * 부른다 — 화면이 물어 보고 통과했더라도 그 사이에 정본이 바뀌었을 수 있으므로, 막는 것은 언제나\n * 뮤테이션이다. 이 질의는 **이유를 미리 보여 주기 위한 것**이고 허가증이 아니다.\n */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => FigureInspection, { description: 'Whether a figure may be released, with the reasons.' })\n async inspectFigure(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<FigureInspection> {\n const { domain } = context.state\n\n const figure = await getRepository(Figure).findOne({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id },\n select: { id: true, source: true }\n })\n\n if (!figure) {\n throw new Error(`Figure ${id} 를 찾을 수 없다`)\n }\n\n return inspectSource(figure.source)\n }\n\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [String], { description: 'All figure type names in scope — used to check name collisions before create.' })\n async figureTypeNames(@Ctx() context: ResolverContext): Promise<string[]> {\n const { domain } = context.state\n\n const rows = await getRepository(Figure).find({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) } },\n select: { type: true }\n })\n\n return rows.map(r => r.type).filter(Boolean)\n }\n}\n"]}
|
|
@@ -10,6 +10,7 @@ export declare class NewFigure {
|
|
|
10
10
|
name: string;
|
|
11
11
|
description?: string;
|
|
12
12
|
category?: string;
|
|
13
|
+
tags?: string[];
|
|
13
14
|
source: string;
|
|
14
15
|
properties?: string;
|
|
15
16
|
state?: 'draft' | 'released';
|
|
@@ -25,6 +26,7 @@ export declare class FigurePatch {
|
|
|
25
26
|
name?: string;
|
|
26
27
|
description?: string;
|
|
27
28
|
category?: string;
|
|
29
|
+
tags?: string[];
|
|
28
30
|
source?: string;
|
|
29
31
|
properties?: string;
|
|
30
32
|
thumbnail?: string;
|
|
@@ -29,6 +29,10 @@ tslib_1.__decorate([
|
|
|
29
29
|
(0, type_graphql_1.Field)({ nullable: true, description: 'Classification code used to group figures in the palette.' }),
|
|
30
30
|
tslib_1.__metadata("design:type", String)
|
|
31
31
|
], NewFigure.prototype, "category", void 0);
|
|
32
|
+
tslib_1.__decorate([
|
|
33
|
+
(0, type_graphql_1.Field)(type => [String], { nullable: true, description: 'Free-form tags. A figure may carry several.' }),
|
|
34
|
+
tslib_1.__metadata("design:type", Array)
|
|
35
|
+
], NewFigure.prototype, "tags", void 0);
|
|
32
36
|
tslib_1.__decorate([
|
|
33
37
|
(0, type_graphql_1.Field)({ description: 'The canonical FigureSource JSON.' }),
|
|
34
38
|
tslib_1.__metadata("design:type", String)
|
|
@@ -69,6 +73,10 @@ tslib_1.__decorate([
|
|
|
69
73
|
(0, type_graphql_1.Field)({ nullable: true, description: 'The new classification code.' }),
|
|
70
74
|
tslib_1.__metadata("design:type", String)
|
|
71
75
|
], FigurePatch.prototype, "category", void 0);
|
|
76
|
+
tslib_1.__decorate([
|
|
77
|
+
(0, type_graphql_1.Field)(type => [String], { nullable: true, description: 'The new tags. An empty list clears them; omitting the field leaves them.' }),
|
|
78
|
+
tslib_1.__metadata("design:type", Array)
|
|
79
|
+
], FigurePatch.prototype, "tags", void 0);
|
|
72
80
|
tslib_1.__decorate([
|
|
73
81
|
(0, type_graphql_1.Field)({ nullable: true, description: 'The new FigureSource JSON.' }),
|
|
74
82
|
tslib_1.__metadata("design:type", String)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-type.js","sourceRoot":"","sources":["../../../server/service/figure/figure-type.ts"],"names":[],"mappings":";;;;AAAA,+CAAgE;AAEhE,2CAAoC;AAEpC;;;;;GAKG;AAEI,IAAM,SAAS,GAAf,MAAM,SAAS;
|
|
1
|
+
{"version":3,"file":"figure-type.js","sourceRoot":"","sources":["../../../server/service/figure/figure-type.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, InputType, Int, ObjectType } from 'type-graphql'\n\nimport { Figure } from './figure.js'\n\n/**\n * 새 Figure.\n *\n * `score`·`triangles`·`groups` 는 **받지 않는다.** 서버가 `source` 에서 계산한다 —\n * 받으면 거짓이 들어오고 목록이 실물과 다른 것을 보여 준다.\n */\n@InputType({ description: 'Input for creating a new figure.' })\nexport class NewFigure {\n @Field({ description: 'Component type name. Immutable once created, unique per domain.' })\n type: string\n\n @Field({ description: 'Display name shown to authors.' })\n name: string\n\n @Field({ nullable: true, description: 'A detailed description for the figure.' })\n description?: string\n\n @Field({ nullable: true, description: 'Classification code used to group figures in the palette.' })\n category?: string\n\n @Field(type => [String], { nullable: true, description: 'Free-form tags. A figure may carry several.' })\n tags?: string[]\n\n @Field({ description: 'The canonical FigureSource JSON.' })\n source: string\n\n @Field({ nullable: true, description: 'JSON definition of the master-data fields an instance carries.' })\n properties?: string\n\n @Field({ nullable: true, description: \"Lifecycle state — defaults to 'draft'.\" })\n state?: 'draft' | 'released'\n\n @Field({ nullable: true, description: 'A base64 encoded thumbnail image.' })\n thumbnail?: string\n}\n\n/**\n * 수정.\n *\n * `type` 이 없다. **저장되는 식별자라 고칠 수 없다** — 바꾸면 이미 배치된 보드가\n * 타입을 못 찾아 오류 없이 빈 화면이 된다. 고칠 수 있는 이름은 `name` 뿐이다.\n */\n@InputType({ description: 'Input for updating an existing figure. The `type` field is absent by design — it is a stored identifier.' })\nexport class FigurePatch {\n @Field({ nullable: true, description: 'The new display name.' })\n name?: string\n\n @Field({ nullable: true, description: 'The new description.' })\n description?: string\n\n @Field({ nullable: true, description: 'The new classification code.' })\n category?: string\n\n /*\n 빈 배열과 안 준 것을 가른다. `undefined` 는 「건드리지 않는다」, `[]` 는 「전부 지운다」다.\n 둘을 뭉개면 태그를 다 지우려는 저작자가 지울 방법을 잃는다.\n */\n @Field(type => [String], { nullable: true, description: 'The new tags. An empty list clears them; omitting the field leaves them.' })\n tags?: string[]\n\n @Field({ nullable: true, description: 'The new FigureSource JSON.' })\n source?: string\n\n @Field({ nullable: true, description: 'The new master-data field definition.' })\n properties?: string\n\n /*\n `state` 는 여기 없다 — **상태는 저장이 정하지 않는다.**\n\n 발행은 `releaseFigure` 가 한다. 저장으로 상태를 바꿀 수 있게 두면 발행된 판을 덮어쓰면서 같은\n 판 번호로 판본을 또 뜨게 되고(유니크 충돌), 무엇이 약속된 판인지도 흐려진다. board 도 같다.\n */\n\n @Field({ nullable: true, description: 'A base64 encoded thumbnail image.' })\n thumbnail?: string\n}\n\n@ObjectType({ description: 'A paginated list of figures.' })\nexport class FigureList {\n @Field(type => [Figure], { description: 'The figures on this page.' })\n items: Figure[]\n\n @Field(type => Int, { description: 'Total number of figures matching the query.' })\n total: number\n}\n\n/**\n * 검증 결과 한 줄.\n *\n * 정본 형식의 검증은 `@hatiolab/figure-model` 이 두 단계로 나눈다 — `errors` 는\n * 막고, `violations` 는 알린다. 그 경계를 서버가 다시 정하지 않는다.\n */\n@ObjectType({ description: 'One validation finding from figure-model.' })\nexport class FigureFinding {\n @Field({ description: 'Stable code from figure-model (ERROR_CODES / VIOLATION_CODES).' })\n code: string\n\n @Field({ description: 'Human-readable message.' })\n message: string\n\n @Field({ nullable: true, description: 'Path within the source that the finding points at.' })\n at?: string\n}\n\n/**\n * 저장 결과.\n *\n * `violations` 가 있어도 저장은 된다 — 막는 것과 알리는 것을 가른다. 화면이\n * 이것을 그대로 보여 줘야 한다. 조용히 버리면 저작자가 모른다.\n */\n@ObjectType({ description: 'Result of saving a figure, carrying non-blocking violations.' })\nexport class FigureSaveResult {\n @Field(type => Figure, { description: 'The saved figure.' })\n figure: Figure\n\n @Field(type => [FigureFinding], { description: 'Non-blocking findings. The save succeeded despite these.' })\n violations: FigureFinding[]\n}\n\n/**\n * 발행 판정 한 줄.\n *\n * `FigureFinding` 과 칸이 겹치지만 **`blocking` 이 하나 더 있다.** 저장 쪽 발견은 정의상 막지 않는\n * 것들이라 그 칸이 필요 없었다. 발행 판정은 막는 것과 알리는 것을 함께 내므로, 어느 쪽인지를 값이\n * 스스로 말해야 한다 — 코드를 보고 화면이 다시 분류하면 규칙이 두 벌이 된다.\n */\n@ObjectType({ description: 'One finding from the release gate.' })\nexport class FigureGateFinding {\n @Field({ description: 'Stable code — figure-model validation codes, or sizing-splits / sizing-loose.' })\n code: string\n\n @Field({ description: 'Human-readable message.' })\n message: string\n\n @Field({ nullable: true, description: 'Why this is a problem — what a person sees when it happens.' })\n why?: string\n\n @Field({ nullable: true, description: 'What to change, naming the part and the value.' })\n how?: string\n\n @Field({ nullable: true, description: 'Where it points: part names that came apart, or a path in the source.' })\n at?: string\n\n @Field({ description: 'True when this finding blocks the release.' })\n blocking: boolean\n}\n\n/**\n * 발행 판정.\n *\n * 화면이 **발행을 누르기 전에** 물어보는 자리다. 눌러 보고 거절당하는 것으로 알게 되면, 무엇을\n * 고쳐야 하는지 모른 채 단추만 두드리게 된다.\n */\n@ObjectType({ description: 'Whether a figure may be released, and why not.' })\nexport class FigureInspection {\n @Field({ description: 'True when at least one finding blocks the release.' })\n blocked: boolean\n\n @Field(type => [FigureGateFinding], { description: 'Findings, blocking and advisory together.' })\n findings: FigureGateFinding[]\n}\n"]}
|
|
@@ -45,8 +45,24 @@ export declare class Figure {
|
|
|
45
45
|
type?: string;
|
|
46
46
|
name?: string;
|
|
47
47
|
description?: string;
|
|
48
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* 분류 하나. **팔레트에서 묶어 보이는 기준이다.**
|
|
50
|
+
*
|
|
51
|
+
* 도형 하나에 하나뿐이다 — 팔레트는 목록을 한 벌로 나눠 보여 주므로, 한 도형이 두 묶음에
|
|
52
|
+
* 동시에 있으면 저작자가 같은 것을 두 번 만난다.
|
|
53
|
+
*/
|
|
49
54
|
category?: string;
|
|
55
|
+
/**
|
|
56
|
+
* 태그. **여럿 붙는다.**
|
|
57
|
+
*
|
|
58
|
+
* 분류와 다른 일을 한다. 분류는 「이것이 무엇인가」를 한 번 정하는 것이고, 태그는 「어디에
|
|
59
|
+
* 걸리는가」를 여러 갈래로 적는 것이다 — 컨베이어이면서 반출 구역의 것일 수 있다. 그래서
|
|
60
|
+
* 분류로는 못 하는 찾기가 된다.
|
|
61
|
+
*
|
|
62
|
+
* `simple-json` 으로 담는다. 사내 선례가 그것이고(`ops-master` · `organization` ·
|
|
63
|
+
* `personalization`), 드라이버마다 배열 타입이 다른 것을 피한다.
|
|
64
|
+
*/
|
|
65
|
+
tags?: string[];
|
|
50
66
|
state?: 'draft' | 'released';
|
|
51
67
|
/**
|
|
52
68
|
* `FigureSource` JSON.
|
|
@@ -79,9 +79,14 @@ tslib_1.__decorate([
|
|
|
79
79
|
], Figure.prototype, "description", void 0);
|
|
80
80
|
tslib_1.__decorate([
|
|
81
81
|
(0, typeorm_1.Column)({ nullable: true }),
|
|
82
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'Classification code used to group figures in the palette.' }),
|
|
82
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Classification code used to group figures in the palette. One per figure.' }),
|
|
83
83
|
tslib_1.__metadata("design:type", String)
|
|
84
84
|
], Figure.prototype, "category", void 0);
|
|
85
|
+
tslib_1.__decorate([
|
|
86
|
+
(0, typeorm_1.Column)('simple-json', { nullable: true, default: null }),
|
|
87
|
+
(0, type_graphql_1.Field)(type => [String], { nullable: true, description: 'Free-form tags. A figure may carry several.' }),
|
|
88
|
+
tslib_1.__metadata("design:type", Array)
|
|
89
|
+
], Figure.prototype, "tags", void 0);
|
|
85
90
|
tslib_1.__decorate([
|
|
86
91
|
(0, typeorm_1.Column)({ nullable: true, default: 'draft' }),
|
|
87
92
|
(0, type_graphql_1.Field)({ nullable: true, description: "Lifecycle state — 'draft' figures do not appear in the board palette." }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure.js","sourceRoot":"","sources":["../../../server/service/figure/figure.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Column,\n CreateDateColumn,\n DeleteDateColumn,\n Entity,\n Index,\n ManyToOne,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn\n} from 'typeorm'\nimport { Field, Float, ID, Int, ObjectType } from 'type-graphql'\n\nimport { User } from '@things-factory/auth-base'\nimport { Domain, longTextColumn } from '@things-factory/shell'\n\n/**\n * Figure — 저작된 3D 컴포넌트 한 종류.\n *\n * `Board` 를 준용한다. 다른 점만 주석으로 적는다.\n *\n * ## 무엇을 담나 — `FigureSource` 다, 씬 모델이 아니다\n *\n * 정본 형식은 `@hatiolab/figure-model` 이 정한다(`FigureSource`). 씬 컴포넌트 트리를\n * 담지 않는다. 담으면 저작도구가 씬 편집기가 되고, 부품 이름·상태 슬롯·애니메이션\n * 자리가 형식에 없어 따로 관리해야 한다.\n *\n * 청사진(`FigureBlueprint`)은 **저장하지 않는다.** 정본에서 파생되는 캐시이므로\n * 소비하는 쪽이 `compile()` 로 만든다. 저장하면 정본과 갈린다.\n *\n * 그래서 `baseWidth`·`anchor`·`statusSlots`·`parts`·`animations` 같은 것을 컬럼으로\n * 두지 않는다 — 전부 `source` 안에 이미 있는 자리다. 두 벌이면 갈린다.\n *\n * 설계: `docs/design/figure-modules.md` §2\n */\n@Entity()\n@Index('ix_figure_1', (figure: Figure) => [figure.domain, figure.type], {\n unique: true,\n where: '\"deleted_at\" IS NULL'\n})\n@Index('ix_figure_2', (figure: Figure) => [figure.domain, figure.category])\n@ObjectType({ description: 'An authored 3D component type — the canonical FigureSource plus its metadata.' })\nexport class Figure {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { nullable: true, description: 'Unique identifier for the figure.' })\n readonly id?: string\n\n /**\n * 발행된 판의 번호 — **발행할 때만 올라간다.**\n *\n * 저장 횟수가 아니다. 저작 중에는 몇 번을 고쳐 저장하든 그대로이고, `draft` 가 `released` 가\n * 되는 순간에만 하나 오른다. 소비처가 「몇 번째 판을 쓰고 있나」를 이 값으로 말한다.\n *\n * 한 번도 발행되지 않았으면 **0** 이다. 1 로 시작하면 아직 아무에게도 약속하지 않은 초안이\n * 첫 판인 것처럼 보인다.\n */\n @Column({ nullable: true, default: 0 })\n @Field(type => Int, {\n nullable: true,\n description: 'Published version. Raised when the figure is released, not when it is saved. 0 means never released.'\n })\n version?: number = 0\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'The domain this figure belongs to.' })\n domain?: Domain\n\n @RelationId((figure: Figure) => figure.domain)\n domainId?: string\n\n /**\n * 컴포넌트 타입 이름. **저장되는 식별자다.**\n *\n * 배치된 보드가 이 이름으로 타입을 찾는다. 바꾸면 그 보드는 타입을 못 찾아\n * **오류 없이 빈 화면**이 된다. 그래서 만들 때 정하고 잠근다 — 고칠 수 있는 것은\n * 표시 이름(`name`)뿐이다. 수정 리졸버가 이 필드를 받지 않는다.\n *\n * `Board.type`(main/sub/popup)과 뜻이 전혀 다르다. 혼동하지 않는다.\n */\n @Column()\n @Field({ description: 'Component type name. A stored identifier — unique per domain and immutable once created.' })\n type?: string\n\n @Column()\n @Field({ description: 'Display name shown to authors. Safe to rename.' })\n name?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'A detailed description for the figure.' })\n description?: string\n\n /** 분류 코드. 팔레트에서 묶어 보이는 기준. */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Classification code used to group figures in the palette.' })\n category?: string\n\n @Column({ nullable: true, default: 'draft' })\n @Field({ nullable: true, description: \"Lifecycle state — 'draft' figures do not appear in the board palette.\" })\n state?: 'draft' | 'released'\n\n /**\n * `FigureSource` JSON.\n *\n * `Board.model` 자리이지만 이름을 바꿨다 — 「씬 모델이 아니다」를 필드 이름이\n * 드러내야 한다.\n */\n @Column({ nullable: true, ...longTextColumn() })\n @Field({ nullable: true, description: 'The canonical FigureSource JSON authored by the modeller.' })\n source?: string\n\n // ── 파생값 — 저장하는 이유가 하나뿐이다 ──────────────────────────────────\n //\n // 셋 다 `source` 에서 계산된다. 그런데도 컬럼으로 두는 이유는 **목록 화면이\n // 정렬·필터를 해야** 하기 때문이다. JSON 을 파싱해 정렬할 수는 없다.\n //\n // 저장할 때 `figure-model` 로 계산해 채운다. **클라이언트가 준 값을 받지 않는다** —\n // 받으면 거짓이 들어오고, 목록이 실물과 다른 것을 보여 준다.\n\n /** 재활용 점수 0~100. `scoreOf()` 가 계산한다. */\n @Column({ type: 'float', nullable: true })\n @Field(type => Float, { nullable: true, description: 'Reuse score 0-100, computed from source on save.' })\n score?: number\n\n /** 삼각형 수. `costOf()` 가 계산한다. */\n @Column({ nullable: true })\n @Field(type => Int, { nullable: true, description: 'Triangle count, computed from source on save.' })\n triangles?: number\n\n /** 재질 묶음 수 — 인스턴스당 draw call 의 근거. */\n @Column({ nullable: true })\n @Field(type => Int, { nullable: true, description: 'Material group count — the basis of per-instance draw calls.' })\n groups?: number\n\n /** 기준정보 항목 정의. Figure 를 배치할 때 인스턴스가 채우는 자리. */\n @Column({ nullable: true, ...longTextColumn() })\n @Field({ nullable: true, description: 'JSON definition of the master-data fields an instance of this figure carries.' })\n properties?: string\n\n @Column({ nullable: true, ...longTextColumn() })\n @Field({ nullable: true, description: 'A base64 encoded thumbnail image of the figure.' })\n thumbnail?: string\n\n /**\n * 썸네일이 **썸네일로서** 마지막으로 갱신된 시각. `updatedAt` 과는 별개 도메인이다 —\n * 이름·설명만 고쳤을 때는 갱신되지 않는다. `Board` 와 같은 방식.\n */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Timestamp of the last thumbnail generation. Separate lifecycle from updatedAt.' })\n thumbnailUpdatedAt?: Date\n\n @Column({ type: 'float', nullable: true, default: 0 })\n @Field(type => Float, { nullable: true, description: 'Sort order within a listing.' })\n sortOrder?: number\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'Creation timestamp.' })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true, description: 'Last update timestamp.' })\n updatedAt?: Date\n\n @DeleteDateColumn()\n @Field({ nullable: true, description: 'Soft-delete timestamp.' })\n deletedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'The user who created this figure.' })\n creator?: User\n\n @RelationId((figure: Figure) => figure.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'The user who last updated this figure.' })\n updater?: User\n\n @RelationId((figure: Figure) => figure.updater)\n updaterId?: string\n}\n"]}
|
|
1
|
+
{"version":3,"file":"figure.js","sourceRoot":"","sources":["../../../server/service/figure/figure.ts"],"names":[],"mappings":";;;;AAAA,qCAUgB;AAChB,+CAAgE;AAEhE,yDAAgD;AAChD,iDAA8D;AAE9D;;;;;;;;;;;;;;;;;;GAkBG;AAQI,IAAM,MAAM,GAAZ,MAAM,MAAM;IAAZ;QAKL;;;;;;;;WAQG;QAMH,YAAO,GAAY,CAAC,CAAA;IA0ItB,CAAC;CAAA,CAAA;AA7JY,wBAAM;AAGR;IAFR,IAAA,gCAAsB,EAAC,MAAM,CAAC;IAC9B,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,mCAAmC,EAAE,CAAC;;kCACpE;AAgBpB;IALC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACtC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE;QAClB,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,sGAAsG;KACpH,CAAC;;uCACkB;AAIpB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,CAAC;IACzB,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,oCAAoC,EAAE,CAAC;sCACpF,cAAM;sCAAA;AAGf;IADC,IAAA,oBAAU,EAAC,CAAC,MAAc,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;;wCAC7B;AAajB;IAFC,IAAA,gBAAM,GAAE;IACR,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,0FAA0F,EAAE,CAAC;;oCACtG;AAIb;IAFC,IAAA,gBAAM,GAAE;IACR,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,gDAAgD,EAAE,CAAC;;oCAC5D;AAIb;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,wCAAwC,EAAE,CAAC;;2CAC7D;AAUpB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,2EAA2E,EAAE,CAAC;;wCACnG;AAejB;IAFC,IAAA,gBAAM,EAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACxD,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,6CAA6C,EAAE,CAAC;;oCACzF;AAIf;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAC5C,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,uEAAuE,EAAE,CAAC;;qCACpF;AAU5B;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAA,sBAAc,GAAE,EAAE,CAAC;IAC/C,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,2DAA2D,EAAE,CAAC;;sCACrF;AAaf;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACzC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,oBAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC;;qCAC5F;AAKd;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,+CAA+C,EAAE,CAAC;;yCACnF;AAKlB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,8DAA8D,EAAE,CAAC;;sCACrG;AAKf;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAA,sBAAc,GAAE,EAAE,CAAC;IAC/C,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,+EAA+E,EAAE,CAAC;;0CACrG;AAInB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAA,sBAAc,GAAE,EAAE,CAAC;IAC/C,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,iDAAiD,EAAE,CAAC;;yCACxE;AAQlB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,gFAAgF,EAAE,CAAC;sCACpG,IAAI;kDAAA;AAIzB;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACrD,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,oBAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,8BAA8B,EAAE,CAAC;;yCACpE;AAIlB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,qBAAqB,EAAE,CAAC;sCAClD,IAAI;yCAAA;AAIhB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,wBAAwB,EAAE,CAAC;sCACrD,IAAI;yCAAA;AAIhB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,wBAAwB,EAAE,CAAC;sCACrD,IAAI;yCAAA;AAIhB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC3C,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,mCAAmC,EAAE,CAAC;sCAChF,gBAAI;uCAAA;AAGd;IADC,IAAA,oBAAU,EAAC,CAAC,MAAc,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;;yCAC7B;AAIlB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC3C,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,wCAAwC,EAAE,CAAC;sCACrF,gBAAI;uCAAA;AAGd;IADC,IAAA,oBAAU,EAAC,CAAC,MAAc,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;;yCAC7B;iBA5JP,MAAM;IAPlB,IAAA,gBAAM,GAAE;IACR,IAAA,eAAK,EAAC,aAAa,EAAE,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE;QACtE,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,sBAAsB;KAC9B,CAAC;IACD,IAAA,eAAK,EAAC,aAAa,EAAE,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1E,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,+EAA+E,EAAE,CAAC;GAChG,MAAM,CA6JlB","sourcesContent":["import {\n Column,\n CreateDateColumn,\n DeleteDateColumn,\n Entity,\n Index,\n ManyToOne,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn\n} from 'typeorm'\nimport { Field, Float, ID, Int, ObjectType } from 'type-graphql'\n\nimport { User } from '@things-factory/auth-base'\nimport { Domain, longTextColumn } from '@things-factory/shell'\n\n/**\n * Figure — 저작된 3D 컴포넌트 한 종류.\n *\n * `Board` 를 준용한다. 다른 점만 주석으로 적는다.\n *\n * ## 무엇을 담나 — `FigureSource` 다, 씬 모델이 아니다\n *\n * 정본 형식은 `@hatiolab/figure-model` 이 정한다(`FigureSource`). 씬 컴포넌트 트리를\n * 담지 않는다. 담으면 저작도구가 씬 편집기가 되고, 부품 이름·상태 슬롯·애니메이션\n * 자리가 형식에 없어 따로 관리해야 한다.\n *\n * 청사진(`FigureBlueprint`)은 **저장하지 않는다.** 정본에서 파생되는 캐시이므로\n * 소비하는 쪽이 `compile()` 로 만든다. 저장하면 정본과 갈린다.\n *\n * 그래서 `baseWidth`·`anchor`·`statusSlots`·`parts`·`animations` 같은 것을 컬럼으로\n * 두지 않는다 — 전부 `source` 안에 이미 있는 자리다. 두 벌이면 갈린다.\n *\n * 설계: `docs/design/figure-modules.md` §2\n */\n@Entity()\n@Index('ix_figure_1', (figure: Figure) => [figure.domain, figure.type], {\n unique: true,\n where: '\"deleted_at\" IS NULL'\n})\n@Index('ix_figure_2', (figure: Figure) => [figure.domain, figure.category])\n@ObjectType({ description: 'An authored 3D component type — the canonical FigureSource plus its metadata.' })\nexport class Figure {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { nullable: true, description: 'Unique identifier for the figure.' })\n readonly id?: string\n\n /**\n * 발행된 판의 번호 — **발행할 때만 올라간다.**\n *\n * 저장 횟수가 아니다. 저작 중에는 몇 번을 고쳐 저장하든 그대로이고, `draft` 가 `released` 가\n * 되는 순간에만 하나 오른다. 소비처가 「몇 번째 판을 쓰고 있나」를 이 값으로 말한다.\n *\n * 한 번도 발행되지 않았으면 **0** 이다. 1 로 시작하면 아직 아무에게도 약속하지 않은 초안이\n * 첫 판인 것처럼 보인다.\n */\n @Column({ nullable: true, default: 0 })\n @Field(type => Int, {\n nullable: true,\n description: 'Published version. Raised when the figure is released, not when it is saved. 0 means never released.'\n })\n version?: number = 0\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'The domain this figure belongs to.' })\n domain?: Domain\n\n @RelationId((figure: Figure) => figure.domain)\n domainId?: string\n\n /**\n * 컴포넌트 타입 이름. **저장되는 식별자다.**\n *\n * 배치된 보드가 이 이름으로 타입을 찾는다. 바꾸면 그 보드는 타입을 못 찾아\n * **오류 없이 빈 화면**이 된다. 그래서 만들 때 정하고 잠근다 — 고칠 수 있는 것은\n * 표시 이름(`name`)뿐이다. 수정 리졸버가 이 필드를 받지 않는다.\n *\n * `Board.type`(main/sub/popup)과 뜻이 전혀 다르다. 혼동하지 않는다.\n */\n @Column()\n @Field({ description: 'Component type name. A stored identifier — unique per domain and immutable once created.' })\n type?: string\n\n @Column()\n @Field({ description: 'Display name shown to authors. Safe to rename.' })\n name?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'A detailed description for the figure.' })\n description?: string\n\n /**\n * 분류 하나. **팔레트에서 묶어 보이는 기준이다.**\n *\n * 도형 하나에 하나뿐이다 — 팔레트는 목록을 한 벌로 나눠 보여 주므로, 한 도형이 두 묶음에\n * 동시에 있으면 저작자가 같은 것을 두 번 만난다.\n */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Classification code used to group figures in the palette. One per figure.' })\n category?: string\n\n /**\n * 태그. **여럿 붙는다.**\n *\n * 분류와 다른 일을 한다. 분류는 「이것이 무엇인가」를 한 번 정하는 것이고, 태그는 「어디에\n * 걸리는가」를 여러 갈래로 적는 것이다 — 컨베이어이면서 반출 구역의 것일 수 있다. 그래서\n * 분류로는 못 하는 찾기가 된다.\n *\n * `simple-json` 으로 담는다. 사내 선례가 그것이고(`ops-master` · `organization` ·\n * `personalization`), 드라이버마다 배열 타입이 다른 것을 피한다.\n */\n /* `simple-json` 과 `default: null` 은 사내 선례 그대로다 — board-template · attachment 가 같은 모양이다. */\n @Column('simple-json', { nullable: true, default: null })\n @Field(type => [String], { nullable: true, description: 'Free-form tags. A figure may carry several.' })\n tags?: string[]\n\n @Column({ nullable: true, default: 'draft' })\n @Field({ nullable: true, description: \"Lifecycle state — 'draft' figures do not appear in the board palette.\" })\n state?: 'draft' | 'released'\n\n /**\n * `FigureSource` JSON.\n *\n * `Board.model` 자리이지만 이름을 바꿨다 — 「씬 모델이 아니다」를 필드 이름이\n * 드러내야 한다.\n */\n @Column({ nullable: true, ...longTextColumn() })\n @Field({ nullable: true, description: 'The canonical FigureSource JSON authored by the modeller.' })\n source?: string\n\n // ── 파생값 — 저장하는 이유가 하나뿐이다 ──────────────────────────────────\n //\n // 셋 다 `source` 에서 계산된다. 그런데도 컬럼으로 두는 이유는 **목록 화면이\n // 정렬·필터를 해야** 하기 때문이다. JSON 을 파싱해 정렬할 수는 없다.\n //\n // 저장할 때 `figure-model` 로 계산해 채운다. **클라이언트가 준 값을 받지 않는다** —\n // 받으면 거짓이 들어오고, 목록이 실물과 다른 것을 보여 준다.\n\n /** 재활용 점수 0~100. `scoreOf()` 가 계산한다. */\n @Column({ type: 'float', nullable: true })\n @Field(type => Float, { nullable: true, description: 'Reuse score 0-100, computed from source on save.' })\n score?: number\n\n /** 삼각형 수. `costOf()` 가 계산한다. */\n @Column({ nullable: true })\n @Field(type => Int, { nullable: true, description: 'Triangle count, computed from source on save.' })\n triangles?: number\n\n /** 재질 묶음 수 — 인스턴스당 draw call 의 근거. */\n @Column({ nullable: true })\n @Field(type => Int, { nullable: true, description: 'Material group count — the basis of per-instance draw calls.' })\n groups?: number\n\n /** 기준정보 항목 정의. Figure 를 배치할 때 인스턴스가 채우는 자리. */\n @Column({ nullable: true, ...longTextColumn() })\n @Field({ nullable: true, description: 'JSON definition of the master-data fields an instance of this figure carries.' })\n properties?: string\n\n @Column({ nullable: true, ...longTextColumn() })\n @Field({ nullable: true, description: 'A base64 encoded thumbnail image of the figure.' })\n thumbnail?: string\n\n /**\n * 썸네일이 **썸네일로서** 마지막으로 갱신된 시각. `updatedAt` 과는 별개 도메인이다 —\n * 이름·설명만 고쳤을 때는 갱신되지 않는다. `Board` 와 같은 방식.\n */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Timestamp of the last thumbnail generation. Separate lifecycle from updatedAt.' })\n thumbnailUpdatedAt?: Date\n\n @Column({ type: 'float', nullable: true, default: 0 })\n @Field(type => Float, { nullable: true, description: 'Sort order within a listing.' })\n sortOrder?: number\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'Creation timestamp.' })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true, description: 'Last update timestamp.' })\n updatedAt?: Date\n\n @DeleteDateColumn()\n @Field({ nullable: true, description: 'Soft-delete timestamp.' })\n deletedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'The user who created this figure.' })\n creator?: User\n\n @RelationId((figure: Figure) => figure.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'The user who last updated this figure.' })\n updater?: User\n\n @RelationId((figure: Figure) => figure.updater)\n updaterId?: string\n}\n"]}
|