@things-factory/worklist 10.1.28 → 10.1.31

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.
Files changed (80) hide show
  1. package/dist-client/pages/activity/activity-page.js +9 -18
  2. package/dist-client/pages/activity/activity-page.js.map +1 -1
  3. package/dist-client/pages/activity-approval/activity-approval-page.d.ts +14 -2
  4. package/dist-client/pages/activity-approval/activity-approval-page.js +120 -45
  5. package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
  6. package/dist-client/pages/activity-catalog/activity-catalog-page.d.ts +1 -0
  7. package/dist-client/pages/activity-catalog/activity-catalog-page.js +5 -0
  8. package/dist-client/pages/activity-catalog/activity-catalog-page.js.map +1 -1
  9. package/dist-client/pages/activity-instance/activity-instance-start-page.js +7 -7
  10. package/dist-client/pages/activity-instance/activity-instance-start-page.js.map +1 -1
  11. package/dist-client/pages/activity-thread/activity-thread-page.d.ts +1 -0
  12. package/dist-client/pages/activity-thread/activity-thread-page.js +5 -0
  13. package/dist-client/pages/activity-thread/activity-thread-page.js.map +1 -1
  14. package/dist-client/pages/activity-thread/activity-thread-view-page.d.ts +1 -0
  15. package/dist-client/pages/activity-thread/activity-thread-view-page.js +5 -0
  16. package/dist-client/pages/activity-thread/activity-thread-view-page.js.map +1 -1
  17. package/dist-client/pages/work-door/door-words.d.ts +41 -0
  18. package/dist-client/pages/work-door/door-words.js +54 -0
  19. package/dist-client/pages/work-door/door-words.js.map +1 -0
  20. package/dist-client/pages/work-door/work-doors-page.d.ts +37 -0
  21. package/dist-client/pages/work-door/work-doors-page.js +369 -0
  22. package/dist-client/pages/work-door/work-doors-page.js.map +1 -0
  23. package/dist-client/route.d.ts +1 -1
  24. package/dist-client/route.js +3 -0
  25. package/dist-client/route.js.map +1 -1
  26. package/dist-client/tsconfig.tsbuildinfo +1 -1
  27. package/dist-server/service/activity/index.d.ts +1 -1
  28. package/dist-server/service/activity-instance/index.d.ts +1 -1
  29. package/dist-server/service/activity-template/index.d.ts +1 -1
  30. package/dist-server/service/activity-thread/index.d.ts +1 -1
  31. package/dist-server/service/index.d.ts +3 -3
  32. package/dist-server/service/index.js +5 -2
  33. package/dist-server/service/index.js.map +1 -1
  34. package/dist-server/service/work-door/activity-lookup.d.ts +70 -0
  35. package/dist-server/service/work-door/activity-lookup.js +110 -0
  36. package/dist-server/service/work-door/activity-lookup.js.map +1 -0
  37. package/dist-server/service/work-door/approval-line-standing.d.ts +92 -0
  38. package/dist-server/service/work-door/approval-line-standing.js +47 -0
  39. package/dist-server/service/work-door/approval-line-standing.js.map +1 -0
  40. package/dist-server/service/work-door/index.d.ts +15 -0
  41. package/dist-server/service/work-door/index.js +20 -0
  42. package/dist-server/service/work-door/index.js.map +1 -0
  43. package/dist-server/service/work-door/pass-work-door.d.ts +74 -0
  44. package/dist-server/service/work-door/pass-work-door.js +45 -0
  45. package/dist-server/service/work-door/pass-work-door.js.map +1 -0
  46. package/dist-server/service/work-door/work-door-declaration.d.ts +114 -0
  47. package/dist-server/service/work-door/work-door-declaration.js +67 -0
  48. package/dist-server/service/work-door/work-door-declaration.js.map +1 -0
  49. package/dist-server/service/work-door/work-door-event.d.ts +20 -0
  50. package/dist-server/service/work-door/work-door-event.js +25 -0
  51. package/dist-server/service/work-door/work-door-event.js.map +1 -0
  52. package/dist-server/service/work-door/work-door-journal-service.d.ts +47 -0
  53. package/dist-server/service/work-door/work-door-journal-service.js +75 -0
  54. package/dist-server/service/work-door/work-door-journal-service.js.map +1 -0
  55. package/dist-server/service/work-door/work-door-journal.d.ts +30 -0
  56. package/dist-server/service/work-door/work-door-journal.js +94 -0
  57. package/dist-server/service/work-door/work-door-journal.js.map +1 -0
  58. package/dist-server/service/work-door/work-door-not-used.d.ts +39 -0
  59. package/dist-server/service/work-door/work-door-not-used.js +86 -0
  60. package/dist-server/service/work-door/work-door-not-used.js.map +1 -0
  61. package/dist-server/service/work-door/work-door-resolver.d.ts +29 -0
  62. package/dist-server/service/work-door/work-door-resolver.js +127 -0
  63. package/dist-server/service/work-door/work-door-resolver.js.map +1 -0
  64. package/dist-server/service/work-door/work-door-service.d.ts +29 -0
  65. package/dist-server/service/work-door/work-door-service.js +126 -0
  66. package/dist-server/service/work-door/work-door-service.js.map +1 -0
  67. package/dist-server/service/work-door/work-door-type.d.ts +49 -0
  68. package/dist-server/service/work-door/work-door-type.js +122 -0
  69. package/dist-server/service/work-door/work-door-type.js.map +1 -0
  70. package/dist-server/service/work-door/work-door.d.ts +138 -0
  71. package/dist-server/service/work-door/work-door.js +156 -0
  72. package/dist-server/service/work-door/work-door.js.map +1 -0
  73. package/dist-server/tsconfig.tsbuildinfo +1 -1
  74. package/package.json +10 -10
  75. package/tests/pass-work-door.test.ts +133 -0
  76. package/translations/en.json +39 -15
  77. package/translations/ja.json +39 -15
  78. package/translations/ko.json +39 -15
  79. package/translations/ms.json +39 -15
  80. package/translations/zh.json +39 -15
@@ -0,0 +1,39 @@
1
+ import { User } from '@things-factory/auth-base';
2
+ import { Domain } from '@things-factory/shell';
3
+ /**
4
+ * **이 공장은 이 업무를 안 쓴다** — 공장이 명시적으로 한 말.
5
+ *
6
+ * ═══════════════════════════════════════════════════════════════════════════
7
+ * ── 왜 이 표가 필요한가 (아키텍트 판정 2026-09-11) ─────────────────────────
8
+ * 미라텍은 지금 문 11개 가운데 0개가 서 있다. 그 화면을 처음 여는 관리자에게는 **결함 11개**로
9
+ * 보이는데, 그중 몇은 그 공장이 실제로 안 쓰는 업무일 수 있다.
10
+ *
11
+ * 안 쓰는 것을 말할 방법이 없으면 이 화면은 **영원히 잔소리하는 화면**이 된다. 그러면 사람들이
12
+ * 안 보고, 그때 진짜 빈 문 하나가 그 잔소리에 섞여 묻힌다.
13
+ *
14
+ * ── 자동으로 추론하지 않는다 ───────────────────────────────────────────────
15
+ * 「석 달 안 썼으니 안 쓰는 것」으로 정하면 **조용한 한 철에 참이 된다** — 여름에 폐기가 없던 공장이
16
+ * 가을에 폐기 승인을 잃는다. 그래서 사람이 말한 것만 여기 남는다.
17
+ *
18
+ * ── 왜 사유를 받나 ─────────────────────────────────────────────────────────
19
+ * 이 선언은 **승인 단계를 끄는 것**이다. 반년 뒤에 「왜 폐기 승인이 없나」를 묻는 사람이 나오고,
20
+ * 그때 사유가 없으면 누가 왜 껐는지 알 수 없다. 지운 사람과 시각은 표가 들고, 이유는 사람이 적는다.
21
+ *
22
+ * ── 왜 `Activity.state` 를 안 쓰나 ─────────────────────────────────────────
23
+ * 거기 있는 값은 `draft · released · deprecated` 이고 **양식의 생애**를 뜻한다. `deprecated` 는
24
+ * 「이 양식은 낡았다」이지 「우리 공장은 안 쓴다」가 아니다. 진짜 낱말을 틀린 뜻으로 쓰는 것이
25
+ * 새 표보다 나쁘다. 그리고 그 칸은 양식의 것이라 기동 설치가 덮을 수 있다.
26
+ * ═══════════════════════════════════════════════════════════════════════════
27
+ */
28
+ export declare class WorkDoorNotUsed {
29
+ readonly id: string;
30
+ domain?: Domain;
31
+ domainId?: string;
32
+ /** 어느 문인가 — 양식 이름(`Activity.name`)이다. 라벨은 바뀌지만 이 이름은 콜백의 키라 안 바뀐다. */
33
+ doorName: string;
34
+ /** 왜 안 쓰나. 비워 둘 수 없다(머리말). */
35
+ because: string;
36
+ declaredBy?: User;
37
+ createdAt?: Date;
38
+ updatedAt?: Date;
39
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkDoorNotUsed = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const typeorm_1 = require("typeorm");
6
+ const type_graphql_1 = require("type-graphql");
7
+ const auth_base_1 = require("@things-factory/auth-base");
8
+ const shell_1 = require("@things-factory/shell");
9
+ /**
10
+ * **이 공장은 이 업무를 안 쓴다** — 공장이 명시적으로 한 말.
11
+ *
12
+ * ═══════════════════════════════════════════════════════════════════════════
13
+ * ── 왜 이 표가 필요한가 (아키텍트 판정 2026-09-11) ─────────────────────────
14
+ * 미라텍은 지금 문 11개 가운데 0개가 서 있다. 그 화면을 처음 여는 관리자에게는 **결함 11개**로
15
+ * 보이는데, 그중 몇은 그 공장이 실제로 안 쓰는 업무일 수 있다.
16
+ *
17
+ * 안 쓰는 것을 말할 방법이 없으면 이 화면은 **영원히 잔소리하는 화면**이 된다. 그러면 사람들이
18
+ * 안 보고, 그때 진짜 빈 문 하나가 그 잔소리에 섞여 묻힌다.
19
+ *
20
+ * ── 자동으로 추론하지 않는다 ───────────────────────────────────────────────
21
+ * 「석 달 안 썼으니 안 쓰는 것」으로 정하면 **조용한 한 철에 참이 된다** — 여름에 폐기가 없던 공장이
22
+ * 가을에 폐기 승인을 잃는다. 그래서 사람이 말한 것만 여기 남는다.
23
+ *
24
+ * ── 왜 사유를 받나 ─────────────────────────────────────────────────────────
25
+ * 이 선언은 **승인 단계를 끄는 것**이다. 반년 뒤에 「왜 폐기 승인이 없나」를 묻는 사람이 나오고,
26
+ * 그때 사유가 없으면 누가 왜 껐는지 알 수 없다. 지운 사람과 시각은 표가 들고, 이유는 사람이 적는다.
27
+ *
28
+ * ── 왜 `Activity.state` 를 안 쓰나 ─────────────────────────────────────────
29
+ * 거기 있는 값은 `draft · released · deprecated` 이고 **양식의 생애**를 뜻한다. `deprecated` 는
30
+ * 「이 양식은 낡았다」이지 「우리 공장은 안 쓴다」가 아니다. 진짜 낱말을 틀린 뜻으로 쓰는 것이
31
+ * 새 표보다 나쁘다. 그리고 그 칸은 양식의 것이라 기동 설치가 덮을 수 있다.
32
+ * ═══════════════════════════════════════════════════════════════════════════
33
+ */
34
+ /*
35
+ * The table is named literally because this entity moved here from operato-plant, and the rows stay
36
+ * where they are: the naming strategy derives `work_door_not_useds` (snake_case, then pluralized),
37
+ * and a new module writing `work_door_not_used` would quietly create a second, empty table - every
38
+ * "we do not use this door" a factory had declared would come back as "empty" with no error anywhere.
39
+ */
40
+ let WorkDoorNotUsed = class WorkDoorNotUsed {
41
+ };
42
+ exports.WorkDoorNotUsed = WorkDoorNotUsed;
43
+ tslib_1.__decorate([
44
+ (0, typeorm_1.Column)({ primary: true, type: 'uuid', generated: 'uuid' }),
45
+ (0, type_graphql_1.Field)(type => type_graphql_1.ID),
46
+ tslib_1.__metadata("design:type", String)
47
+ ], WorkDoorNotUsed.prototype, "id", void 0);
48
+ tslib_1.__decorate([
49
+ (0, typeorm_1.ManyToOne)(type => shell_1.Domain),
50
+ tslib_1.__metadata("design:type", shell_1.Domain)
51
+ ], WorkDoorNotUsed.prototype, "domain", void 0);
52
+ tslib_1.__decorate([
53
+ (0, typeorm_1.RelationId)((row) => row.domain),
54
+ tslib_1.__metadata("design:type", String)
55
+ ], WorkDoorNotUsed.prototype, "domainId", void 0);
56
+ tslib_1.__decorate([
57
+ (0, typeorm_1.Column)(),
58
+ (0, type_graphql_1.Field)({ description: 'the form name, the same key the callback is found by' }),
59
+ tslib_1.__metadata("design:type", String)
60
+ ], WorkDoorNotUsed.prototype, "doorName", void 0);
61
+ tslib_1.__decorate([
62
+ (0, typeorm_1.Column)(),
63
+ (0, type_graphql_1.Field)({ description: 'why this plant does not use it — asked for, because somebody will ask later' }),
64
+ tslib_1.__metadata("design:type", String)
65
+ ], WorkDoorNotUsed.prototype, "because", void 0);
66
+ tslib_1.__decorate([
67
+ (0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
68
+ (0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true }),
69
+ tslib_1.__metadata("design:type", auth_base_1.User)
70
+ ], WorkDoorNotUsed.prototype, "declaredBy", void 0);
71
+ tslib_1.__decorate([
72
+ (0, typeorm_1.CreateDateColumn)(),
73
+ (0, type_graphql_1.Field)({ nullable: true }),
74
+ tslib_1.__metadata("design:type", Date)
75
+ ], WorkDoorNotUsed.prototype, "createdAt", void 0);
76
+ tslib_1.__decorate([
77
+ (0, typeorm_1.UpdateDateColumn)(),
78
+ (0, type_graphql_1.Field)({ nullable: true }),
79
+ tslib_1.__metadata("design:type", Date)
80
+ ], WorkDoorNotUsed.prototype, "updatedAt", void 0);
81
+ exports.WorkDoorNotUsed = WorkDoorNotUsed = tslib_1.__decorate([
82
+ (0, typeorm_1.Entity)('work_door_not_useds'),
83
+ (0, typeorm_1.Index)('ix_work_door_not_used_0', (row) => [row.domain, row.doorName], { unique: true }),
84
+ (0, type_graphql_1.ObjectType)({ description: 'A work door this plant has declared it does not use' })
85
+ ], WorkDoorNotUsed);
86
+ //# sourceMappingURL=work-door-not-used.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-door-not-used.js","sourceRoot":"","sources":["../../../server/service/work-door/work-door-not-used.ts"],"names":[],"mappings":";;;;AAAA,qCAA0G;AAC1G,+CAAoD;AAEpD,yDAAgD;AAChD,iDAA8C;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH;;;;;GAKG;AAII,IAAM,eAAe,GAArB,MAAM,eAAe;CAgC3B,CAAA;AAhCY,0CAAe;AAGjB;IAFR,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAC1D,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAE,CAAC;;2CACC;AAGnB;IADC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,CAAC;sCACjB,cAAM;+CAAA;AAGf;IADC,IAAA,oBAAU,EAAC,CAAC,GAAoB,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;;iDAChC;AAKjB;IAFC,IAAA,gBAAM,GAAE;IACR,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,sDAAsD,EAAE,CAAC;;iDAC/D;AAKhB;IAFC,IAAA,gBAAM,GAAE;IACR,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,6EAA6E,EAAE,CAAC;;gDACvF;AAIf;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,CAAC;sCAC3B,gBAAI;mDAAA;AAIjB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;sCACd,IAAI;kDAAA;AAIhB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;sCACd,IAAI;kDAAA;0BA/BL,eAAe;IAH3B,IAAA,gBAAM,EAAC,qBAAqB,CAAC;IAC7B,IAAA,eAAK,EAAC,yBAAyB,EAAE,CAAC,GAAoB,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACxG,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,qDAAqD,EAAE,CAAC;GACtE,eAAe,CAgC3B","sourcesContent":["import { Column, CreateDateColumn, Entity, Index, ManyToOne, RelationId, UpdateDateColumn } from 'typeorm'\nimport { Field, ID, ObjectType } from 'type-graphql'\n\nimport { User } from '@things-factory/auth-base'\nimport { Domain } from '@things-factory/shell'\n\n/**\n * **이 공장은 이 업무를 안 쓴다** — 공장이 명시적으로 한 말.\n *\n * ═══════════════════════════════════════════════════════════════════════════\n * ── 왜 이 표가 필요한가 (아키텍트 판정 2026-09-11) ─────────────────────────\n * 미라텍은 지금 문 11개 가운데 0개가 서 있다. 그 화면을 처음 여는 관리자에게는 **결함 11개**로\n * 보이는데, 그중 몇은 그 공장이 실제로 안 쓰는 업무일 수 있다.\n *\n * 안 쓰는 것을 말할 방법이 없으면 이 화면은 **영원히 잔소리하는 화면**이 된다. 그러면 사람들이\n * 안 보고, 그때 진짜 빈 문 하나가 그 잔소리에 섞여 묻힌다.\n *\n * ── 자동으로 추론하지 않는다 ───────────────────────────────────────────────\n * 「석 달 안 썼으니 안 쓰는 것」으로 정하면 **조용한 한 철에 참이 된다** — 여름에 폐기가 없던 공장이\n * 가을에 폐기 승인을 잃는다. 그래서 사람이 말한 것만 여기 남는다.\n *\n * ── 왜 사유를 받나 ─────────────────────────────────────────────────────────\n * 이 선언은 **승인 단계를 끄는 것**이다. 반년 뒤에 「왜 폐기 승인이 없나」를 묻는 사람이 나오고,\n * 그때 사유가 없으면 누가 왜 껐는지 알 수 없다. 지운 사람과 시각은 표가 들고, 이유는 사람이 적는다.\n *\n * ── 왜 `Activity.state` 를 안 쓰나 ─────────────────────────────────────────\n * 거기 있는 값은 `draft · released · deprecated` 이고 **양식의 생애**를 뜻한다. `deprecated` 는\n * 「이 양식은 낡았다」이지 「우리 공장은 안 쓴다」가 아니다. 진짜 낱말을 틀린 뜻으로 쓰는 것이\n * 새 표보다 나쁘다. 그리고 그 칸은 양식의 것이라 기동 설치가 덮을 수 있다.\n * ═══════════════════════════════════════════════════════════════════════════\n */\n/*\n * The table is named literally because this entity moved here from operato-plant, and the rows stay\n * where they are: the naming strategy derives `work_door_not_useds` (snake_case, then pluralized),\n * and a new module writing `work_door_not_used` would quietly create a second, empty table - every\n * \"we do not use this door\" a factory had declared would come back as \"empty\" with no error anywhere.\n */\n@Entity('work_door_not_useds')\n@Index('ix_work_door_not_used_0', (row: WorkDoorNotUsed) => [row.domain, row.doorName], { unique: true })\n@ObjectType({ description: 'A work door this plant has declared it does not use' })\nexport class WorkDoorNotUsed {\n @Column({ primary: true, type: 'uuid', generated: 'uuid' })\n @Field(type => ID)\n readonly id: string\n\n @ManyToOne(type => Domain)\n domain?: Domain\n\n @RelationId((row: WorkDoorNotUsed) => row.domain)\n domainId?: string\n\n /** 어느 문인가 — 양식 이름(`Activity.name`)이다. 라벨은 바뀌지만 이 이름은 콜백의 키라 안 바뀐다. */\n @Column()\n @Field({ description: 'the form name, the same key the callback is found by' })\n doorName: string\n\n /** 왜 안 쓰나. 비워 둘 수 없다(머리말). */\n @Column()\n @Field({ description: 'why this plant does not use it — asked for, because somebody will ask later' })\n because: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n declaredBy?: User\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n}\n"]}
@@ -0,0 +1,29 @@
1
+ import { WorkDoorsType } from './work-door-type.js';
2
+ /**
3
+ * 이 공장의 결재 문 현황을 묻는 자리.
4
+ *
5
+ * ── 왜 질의인가 ────────────────────────────────────────────────────────────
6
+ * 기동할 때 로그로 한 번 지나가는 사실이었다(`install-boot.ts`). 사람이 조치해야 하는 사실은
7
+ * **물어볼 수 있어야** 한다 — 지나간 로그를 찾아 올라가게 하면 아무도 안 본다.
8
+ *
9
+ * ── 부모까지 보는 것은 `activityNamedIn` 의 규칙을 그대로 쓴다 ─────────────
10
+ * 상신하는 쪽이 그 규칙으로 양식을 찾으므로, 보는 쪽이 다른 규칙으로 찾으면 **화면이 「없다」고 하는데
11
+ * 실제로는 서는** 상태가 생긴다. 같은 함수를 부른다.
12
+ */
13
+ export declare class WorkDoorResolver {
14
+ workDoors(context: ResolverContext): Promise<WorkDoorsType>;
15
+ /**
16
+ * **이 공장은 이 문을 안 쓴다**고 선언한다.
17
+ *
18
+ * ── 왜 사유를 받나 ──────────────────────────────────────────────────────
19
+ * 이 선언은 승인 단계를 끄는 것이다. 반년 뒤 「왜 폐기 승인이 없나」를 묻는 사람이 나오고, 그때
20
+ * 사유가 없으면 누가 왜 껐는지 알 수 없다. 사람과 시각은 표가 들고 이유는 사람이 적는다.
21
+ *
22
+ * ── 모르는 이름은 받지 않는다 ───────────────────────────────────────────
23
+ * 오타로 선언하면 그 줄은 아무 문에도 안 걸리고, 정작 끄려던 문은 계속 조치 대상으로 남는다.
24
+ * 끈 줄 알고 있는데 화면은 그대로다 — 화면이 그 오타를 말해 주지 않는다.
25
+ */
26
+ declareWorkDoorNotUsed(doorName: string, because: string, context: ResolverContext): Promise<WorkDoorsType>;
27
+ /** 다시 쓰기로 했다. 선언을 지운다 — 지우면 그 문은 다시 조치 대상으로 돌아온다. */
28
+ useWorkDoorAgain(doorName: string, context: ResolverContext): Promise<WorkDoorsType>;
29
+ }
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkDoorResolver = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const type_graphql_1 = require("type-graphql");
6
+ const shell_1 = require("@things-factory/shell");
7
+ const activity_js_1 = require("../activity/activity.js");
8
+ const shell_2 = require("@things-factory/shell");
9
+ const work_door_js_1 = require("./work-door.js");
10
+ const work_door_service_js_1 = require("./work-door-service.js");
11
+ const work_door_declaration_js_1 = require("./work-door-declaration.js");
12
+ const work_door_not_used_js_1 = require("./work-door-not-used.js");
13
+ const work_door_type_js_1 = require("./work-door-type.js");
14
+ const work_door_journal_js_1 = require("./work-door-journal.js");
15
+ const work_door_journal_service_js_1 = require("./work-door-journal-service.js");
16
+ /**
17
+ * 이 공장의 결재 문 현황을 묻는 자리.
18
+ *
19
+ * ── 왜 질의인가 ────────────────────────────────────────────────────────────
20
+ * 기동할 때 로그로 한 번 지나가는 사실이었다(`install-boot.ts`). 사람이 조치해야 하는 사실은
21
+ * **물어볼 수 있어야** 한다 — 지나간 로그를 찾아 올라가게 하면 아무도 안 본다.
22
+ *
23
+ * ── 부모까지 보는 것은 `activityNamedIn` 의 규칙을 그대로 쓴다 ─────────────
24
+ * 상신하는 쪽이 그 규칙으로 양식을 찾으므로, 보는 쪽이 다른 규칙으로 찾으면 **화면이 「없다」고 하는데
25
+ * 실제로는 서는** 상태가 생긴다. 같은 함수를 부른다.
26
+ */
27
+ let WorkDoorResolver = class WorkDoorResolver {
28
+ async workDoors(context) {
29
+ const manager = (0, shell_1.getRepository)(activity_js_1.Activity).manager;
30
+ const { domain } = context.state;
31
+ const doors = await (0, work_door_service_js_1.workDoorsFor)(manager, domain);
32
+ return {
33
+ doors: doors.map(work_door_type_js_1.toDoorType),
34
+ summary: (0, work_door_js_1.summarizeDoors)(doors),
35
+ todo: (0, work_door_js_1.doorsToFill)(doors),
36
+ seatsStanding: await (0, work_door_service_js_1.seatsStanding)(manager, domain),
37
+ seatsOffered: (0, work_door_service_js_1.seatsOffered)()
38
+ };
39
+ }
40
+ /**
41
+ * **이 공장은 이 문을 안 쓴다**고 선언한다.
42
+ *
43
+ * ── 왜 사유를 받나 ──────────────────────────────────────────────────────
44
+ * 이 선언은 승인 단계를 끄는 것이다. 반년 뒤 「왜 폐기 승인이 없나」를 묻는 사람이 나오고, 그때
45
+ * 사유가 없으면 누가 왜 껐는지 알 수 없다. 사람과 시각은 표가 들고 이유는 사람이 적는다.
46
+ *
47
+ * ── 모르는 이름은 받지 않는다 ───────────────────────────────────────────
48
+ * 오타로 선언하면 그 줄은 아무 문에도 안 걸리고, 정작 끄려던 문은 계속 조치 대상으로 남는다.
49
+ * 끈 줄 알고 있는데 화면은 그대로다 — 화면이 그 오타를 말해 주지 않는다.
50
+ */
51
+ async declareWorkDoorNotUsed(doorName, because, context) {
52
+ const { domain, user, tx } = context.state;
53
+ if (!(0, work_door_declaration_js_1.declaredDoor)(doorName)) {
54
+ throw new shell_2.Refusal('work-door-unknown', { name: doorName }, 'unknown task "{name}". use a task name from the status screen.');
55
+ }
56
+ if (!because?.trim()) {
57
+ throw new shell_2.Refusal('work-door-not-used-reason-missing', {}, 'enter why this task is not used.');
58
+ }
59
+ const repository = tx.getRepository(work_door_not_used_js_1.WorkDoorNotUsed);
60
+ const existing = await repository.findOne({ where: { domain: { id: domain.id }, doorName } });
61
+ await repository.save({
62
+ ...(existing ?? {}),
63
+ domain,
64
+ doorName,
65
+ because: because.trim(),
66
+ declaredBy: user
67
+ });
68
+ return await this.workDoors(context);
69
+ }
70
+ /** 다시 쓰기로 했다. 선언을 지운다 — 지우면 그 문은 다시 조치 대상으로 돌아온다. */
71
+ async useWorkDoorAgain(doorName, context) {
72
+ const { domain, user, tx } = context.state;
73
+ const repository = tx.getRepository(work_door_not_used_js_1.WorkDoorNotUsed);
74
+ const existing = await repository.findOne({ where: { domain: { id: domain.id }, doorName }, relations: ['declaredBy'] });
75
+ /* 없는 것을 지우라는 것은 이미 쓰고 있다는 뜻이다. 오류로 막지 않고 지금 현황을 낸다. */
76
+ if (existing) {
77
+ /*
78
+ * **지우는 선언을 이력에 남긴다.** 왜 안 쓰기로 했고 누가 정했는지가 지우면 어디에도 없어진다
79
+ * (ADR-0064 ③, 2026-09-17). 다시 선언할 때 그 내용을 여기서 읽는다.
80
+ */
81
+ await (0, work_door_journal_service_js_1.noteWorkDoor)(tx, domain, {
82
+ kind: work_door_journal_js_1.WorkDoorEvent.NotUsedWithdrawn,
83
+ door: existing.doorName,
84
+ detail: (0, work_door_js_1.workDoorNotUsedBefore)(existing)
85
+ }, user);
86
+ await repository.remove(existing);
87
+ }
88
+ return await this.workDoors(context);
89
+ }
90
+ };
91
+ exports.WorkDoorResolver = WorkDoorResolver;
92
+ tslib_1.__decorate([
93
+ (0, type_graphql_1.Directive)('@privilege(category: "activity", privilege: "query", domainOwnerGranted: true)'),
94
+ (0, type_graphql_1.Query)(returns => work_door_type_js_1.WorkDoorsType, {
95
+ description: 'To see which approval steps this plant actually has standing, and which pass with nobody on them'
96
+ }),
97
+ tslib_1.__param(0, (0, type_graphql_1.Ctx)()),
98
+ tslib_1.__metadata("design:type", Function),
99
+ tslib_1.__metadata("design:paramtypes", [Object]),
100
+ tslib_1.__metadata("design:returntype", Promise)
101
+ ], WorkDoorResolver.prototype, "workDoors", null);
102
+ tslib_1.__decorate([
103
+ (0, type_graphql_1.Directive)('@privilege(category: "activity", privilege: "mutation", domainOwnerGranted: true)'),
104
+ (0, type_graphql_1.Directive)('@transaction'),
105
+ (0, type_graphql_1.Mutation)(returns => work_door_type_js_1.WorkDoorsType, { description: 'To declare that this plant does not use one work door' }),
106
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('doorName')),
107
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('because', { description: 'why — somebody will ask in six months' })),
108
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
109
+ tslib_1.__metadata("design:type", Function),
110
+ tslib_1.__metadata("design:paramtypes", [String, String, Object]),
111
+ tslib_1.__metadata("design:returntype", Promise)
112
+ ], WorkDoorResolver.prototype, "declareWorkDoorNotUsed", null);
113
+ tslib_1.__decorate([
114
+ (0, type_graphql_1.Directive)('@privilege(category: "activity", privilege: "mutation", domainOwnerGranted: true)'),
115
+ (0, type_graphql_1.Directive)('@transaction'),
116
+ (0, type_graphql_1.Mutation)(returns => work_door_type_js_1.WorkDoorsType, { description: 'To withdraw the declaration and use that door again' }),
117
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('doorName')),
118
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
119
+ tslib_1.__metadata("design:type", Function),
120
+ tslib_1.__metadata("design:paramtypes", [String, Object]),
121
+ tslib_1.__metadata("design:returntype", Promise)
122
+ ], WorkDoorResolver.prototype, "useWorkDoorAgain", null);
123
+ exports.WorkDoorResolver = WorkDoorResolver = tslib_1.__decorate([
124
+ (0, type_graphql_1.Resolver)(),
125
+ (0, type_graphql_1.UseMiddleware)(shell_2.SpeakRefusals)
126
+ ], WorkDoorResolver);
127
+ //# sourceMappingURL=work-door-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-door-resolver.js","sourceRoot":"","sources":["../../../server/service/work-door/work-door-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager } from 'typeorm'\n\nimport { Arg, Ctx, Directive, Mutation, Query, Resolver, UseMiddleware } from 'type-graphql'\n\nimport { Role } from '@things-factory/auth-base'\nimport { Domain, getRepository } from '@things-factory/shell'\nimport { Activity } from '../activity/activity.js'\n\nimport { Refusal, SpeakRefusals } from '@things-factory/shell'\n\nimport { activityNamedIn } from './activity-lookup.js'\nimport { doorsToFill, summarizeDoors, workDoorNotUsedBefore } from './work-door.js'\nimport { seatsOffered, seatsStanding, workDoorsFor } from './work-door-service.js'\nimport { declaredDoor } from './work-door-declaration.js'\nimport { WorkDoorNotUsed } from './work-door-not-used.js'\nimport { WorkDoorsType, toDoorType } from './work-door-type.js'\nimport { WorkDoorEvent } from './work-door-journal.js'\nimport { noteWorkDoor } from './work-door-journal-service.js'\n\n/**\n * 이 공장의 결재 문 현황을 묻는 자리.\n *\n * ── 왜 질의인가 ────────────────────────────────────────────────────────────\n * 기동할 때 로그로 한 번 지나가는 사실이었다(`install-boot.ts`). 사람이 조치해야 하는 사실은\n * **물어볼 수 있어야** 한다 — 지나간 로그를 찾아 올라가게 하면 아무도 안 본다.\n *\n * ── 부모까지 보는 것은 `activityNamedIn` 의 규칙을 그대로 쓴다 ─────────────\n * 상신하는 쪽이 그 규칙으로 양식을 찾으므로, 보는 쪽이 다른 규칙으로 찾으면 **화면이 「없다」고 하는데\n * 실제로는 서는** 상태가 생긴다. 같은 함수를 부른다.\n */\n@Resolver()\n@UseMiddleware(SpeakRefusals)\nexport class WorkDoorResolver {\n @Directive('@privilege(category: \"activity\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => WorkDoorsType, {\n description: 'To see which approval steps this plant actually has standing, and which pass with nobody on them'\n })\n async workDoors(@Ctx() context: ResolverContext): Promise<WorkDoorsType> {\n const manager = getRepository(Activity).manager\n const { domain } = context.state\n const doors = await workDoorsFor(manager, domain)\n\n return {\n doors: doors.map(toDoorType),\n summary: summarizeDoors(doors),\n todo: doorsToFill(doors),\n seatsStanding: await seatsStanding(manager, domain),\n seatsOffered: seatsOffered()\n }\n }\n\n /**\n * **이 공장은 이 문을 안 쓴다**고 선언한다.\n *\n * ── 왜 사유를 받나 ──────────────────────────────────────────────────────\n * 이 선언은 승인 단계를 끄는 것이다. 반년 뒤 「왜 폐기 승인이 없나」를 묻는 사람이 나오고, 그때\n * 사유가 없으면 누가 왜 껐는지 알 수 없다. 사람과 시각은 표가 들고 이유는 사람이 적는다.\n *\n * ── 모르는 이름은 받지 않는다 ───────────────────────────────────────────\n * 오타로 선언하면 그 줄은 아무 문에도 안 걸리고, 정작 끄려던 문은 계속 조치 대상으로 남는다.\n * 끈 줄 알고 있는데 화면은 그대로다 — 화면이 그 오타를 말해 주지 않는다.\n */\n @Directive('@privilege(category: \"activity\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => WorkDoorsType, { description: 'To declare that this plant does not use one work door' })\n async declareWorkDoorNotUsed(\n @Arg('doorName') doorName: string,\n @Arg('because', { description: 'why — somebody will ask in six months' }) because: string,\n @Ctx() context: ResolverContext\n ): Promise<WorkDoorsType> {\n const { domain, user, tx } = context.state\n\n if (!declaredDoor(doorName)) {\n throw new Refusal(\n 'work-door-unknown',\n { name: doorName },\n 'unknown task \"{name}\". use a task name from the status screen.'\n )\n }\n\n if (!because?.trim()) {\n throw new Refusal('work-door-not-used-reason-missing', {}, 'enter why this task is not used.')\n }\n\n const repository = tx.getRepository(WorkDoorNotUsed)\n const existing = await repository.findOne({ where: { domain: { id: domain.id }, doorName } })\n\n await repository.save({\n ...(existing ?? {}),\n domain,\n doorName,\n because: because.trim(),\n declaredBy: user\n } as any)\n\n return await this.workDoors(context)\n }\n\n /** 다시 쓰기로 했다. 선언을 지운다 — 지우면 그 문은 다시 조치 대상으로 돌아온다. */\n @Directive('@privilege(category: \"activity\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => WorkDoorsType, { description: 'To withdraw the declaration and use that door again' })\n async useWorkDoorAgain(@Arg('doorName') doorName: string, @Ctx() context: ResolverContext): Promise<WorkDoorsType> {\n const { domain, user, tx } = context.state\n const repository = tx.getRepository(WorkDoorNotUsed)\n const existing = await repository.findOne({ where: { domain: { id: domain.id }, doorName }, relations: ['declaredBy'] })\n\n /* 없는 것을 지우라는 것은 이미 쓰고 있다는 뜻이다. 오류로 막지 않고 지금 현황을 낸다. */\n if (existing) {\n /*\n * **지우는 선언을 이력에 남긴다.** 왜 안 쓰기로 했고 누가 정했는지가 지우면 어디에도 없어진다\n * (ADR-0064 ③, 2026-09-17). 다시 선언할 때 그 내용을 여기서 읽는다.\n */\n await noteWorkDoor(\n tx,\n domain,\n {\n kind: WorkDoorEvent.NotUsedWithdrawn,\n door: existing.doorName,\n detail: workDoorNotUsedBefore(existing)\n },\n user\n )\n\n await repository.remove(existing)\n }\n\n return await this.workDoors(context)\n }\n}\n\n"]}
@@ -0,0 +1,29 @@
1
+ import { EntityManager } from 'typeorm';
2
+ import { Domain } from '@things-factory/shell';
3
+ import { WorkDoor } from './work-door';
4
+ /**
5
+ * 이 공장의 문 열둘을 읽어 판정한다 — **한 벌.**
6
+ *
7
+ * ── 왜 resolver 밖에 두나 ──────────────────────────────────────────────────
8
+ * 이 판정을 묻는 자리가 둘이 됐다. 화면(`workDoors`)과 성숙도 표다. 각자 읽으면 둘이 다른 수를
9
+ * 말하게 되고, **어느 쪽이 맞는지 보는 사람이 알 길이 없다.** 성숙도 표는 이 제품이 스스로에 대해
10
+ * 하는 말이라 화면과 어긋나면 그 표 전체를 못 믿는다.
11
+ *
12
+ * ── 부모까지 보는 규칙은 상신하는 쪽의 것을 그대로 쓴다 ────────────────────
13
+ * 상신이 `activityNamedIn` 으로 양식을 찾으므로, 보는 쪽이 다른 규칙으로 찾으면 **「없다」고
14
+ * 말하는데 실제로는 서는** 상태가 생긴다.
15
+ */
16
+ export declare function workDoorsFor(manager: EntityManager, domain: Domain): Promise<WorkDoor[]>;
17
+ /**
18
+ * 이 제품이 내놓는 역할 자리 중 이 공장에 선 것이 몇인가.
19
+ *
20
+ * 결재선은 **역할을 가리킨다**(`[{type:'Role', value:<역할 id>}]`). 그러니 역할이 없는 공장에서는
21
+ * 결재선을 만들 수 없다 — 양식 화면까지 가서야 그걸 알게 된다. 문 현황과 함께 내서 화면이 순서를
22
+ * 말하게 한다.
23
+ *
24
+ * 공장이 스스로 만든 다른 역할은 안 센다. 이 수가 말하는 것은 「이 제품이 내놓은 자리」이고,
25
+ * 그 밖의 역할로 결재선을 짜는 것도 물론 된다.
26
+ */
27
+ export declare function seatsStanding(manager: EntityManager, domain: Domain): Promise<number>;
28
+ /** 이 설치본의 앱들이 내놓는 자리의 수 — 화면이 목록을 따로 들지 않게 여기서 센다. */
29
+ export declare function seatsOffered(): number;
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.workDoorsFor = workDoorsFor;
4
+ exports.seatsStanding = seatsStanding;
5
+ exports.seatsOffered = seatsOffered;
6
+ const auth_base_1 = require("@things-factory/auth-base");
7
+ const shell_1 = require("@things-factory/shell");
8
+ const activity_lookup_js_1 = require("./activity-lookup.js");
9
+ const approval_line_standing_js_1 = require("./approval-line-standing.js");
10
+ const work_door_declaration_js_1 = require("./work-door-declaration.js");
11
+ const work_door_1 = require("./work-door");
12
+ const work_door_not_used_1 = require("./work-door-not-used");
13
+ /**
14
+ * 이 공장의 문 열둘을 읽어 판정한다 — **한 벌.**
15
+ *
16
+ * ── 왜 resolver 밖에 두나 ──────────────────────────────────────────────────
17
+ * 이 판정을 묻는 자리가 둘이 됐다. 화면(`workDoors`)과 성숙도 표다. 각자 읽으면 둘이 다른 수를
18
+ * 말하게 되고, **어느 쪽이 맞는지 보는 사람이 알 길이 없다.** 성숙도 표는 이 제품이 스스로에 대해
19
+ * 하는 말이라 화면과 어긋나면 그 표 전체를 못 믿는다.
20
+ *
21
+ * ── 부모까지 보는 규칙은 상신하는 쪽의 것을 그대로 쓴다 ────────────────────
22
+ * 상신이 `activityNamedIn` 으로 양식을 찾으므로, 보는 쪽이 다른 규칙으로 찾으면 **「없다」고
23
+ * 말하는데 실제로는 서는** 상태가 생긴다.
24
+ */
25
+ async function workDoorsFor(manager, domain) {
26
+ /* 공장이 「안 쓴다」고 말한 것을 한 번에 읽는다. 문마다 읽으면 열두 번 묻는다. */
27
+ const declared = new Map((await manager.find(work_door_not_used_1.WorkDoorNotUsed, { where: { domain: { id: domain.id } } })).map(one => [
28
+ one.doorName,
29
+ one.because
30
+ ]));
31
+ const doors = [];
32
+ /*
33
+ * **포트 하나를 문 열일곱이 함께 쓴다.** 포트가 읽은 역할을 기억하므로 같은 역할을 여러 번 묻지
34
+ * 않는다 — 결재선 대부분이 공장장으로 끝난다. 이 판정 동안만 산다.
35
+ */
36
+ const reader = (0, activity_lookup_js_1.seatReader)(manager);
37
+ for (const door of (0, work_door_declaration_js_1.declaredDoors)()) {
38
+ const name = door.name;
39
+ const activity = await (0, activity_lookup_js_1.activityNamedIn)(manager, domain, name);
40
+ /*
41
+ * **결재선을 빌려 쓰는 문**은 따르는 문의 결재선으로 센다(§`LINE_FOLLOWS`). 자기 칸을 세면, 올리는
42
+ * 쪽은 발행 승인의 결재선으로 서는데 현황은 「결재자 없음」이라고 말한다.
43
+ */
44
+ const follows = door.lineFollows;
45
+ const lineOwner = follows ? await (0, activity_lookup_js_1.activityNamedIn)(manager, domain, follows) : activity;
46
+ doors.push((0, work_door_1.judgeDoor)({
47
+ name,
48
+ label: labelOf(door),
49
+ kind: door.kind,
50
+ notUsedBecause: declared.get(name),
51
+ follows: follows ? labelOfDoorNamed(follows) : undefined,
52
+ /* 상신하는 쪽과 **같은 함수**로 센다. 여기서 따로 세면 화면과 관문이 갈린다. */
53
+ approvalStanding: activity
54
+ ? await (0, approval_line_standing_js_1.judgeApprovalLine)(lineOwner?.approvalLine, reader)
55
+ : undefined,
56
+ installed: activity
57
+ ? {
58
+ approvalLine: lineOwner?.approvalLine,
59
+ assigneeRole: await roleNameOf(manager, activity.assigneeRoleId),
60
+ /*
61
+ * **빌려 온 것일 때만** 채운다. `Activity` 는 `domainId` 만 들고 있어 이름은 따로
62
+ * 읽는데, 자기 도메인이면 읽지도 않고 비운다 — 자기 이름을 채우면 화면이 모든 줄에
63
+ * 「우리 공장에서 정했습니다」를 달고, 「결재자 없음」 옆에서 그 말이 거짓이 된다.
64
+ */
65
+ borrowedFrom: activity.domainId === domain.id ? undefined : await subdomainOf(manager, activity.domainId)
66
+ }
67
+ : undefined
68
+ }));
69
+ }
70
+ return doors;
71
+ }
72
+ /**
73
+ * 그 역할의 이름. 없으면 없다 — 지어내지 않는다.
74
+ *
75
+ * 문마다 부르지 않고 배정 문에서만 부른다. 배정 문이 하나도 없는 지금은 한 번도 안 돈다.
76
+ */
77
+ async function roleNameOf(manager, roleId) {
78
+ if (!roleId) {
79
+ return undefined;
80
+ }
81
+ const found = await manager.findOne(auth_base_1.Role, { where: { id: roleId } });
82
+ return found?.name;
83
+ }
84
+ /**
85
+ * 부모 도메인의 이름. 못 읽으면 지어내지 않고 비운다 — 「본사」라고 적으면 없는 이름이 화면에 남는다.
86
+ *
87
+ * 원문 SQL 로 안 읽는다. 자리표시자 철자가 드라이버마다 달라(`?` · `$1`) sqlite 에서는 통과하고
88
+ * postgres 에서만 죽는다 — 그 부류는 여기서 절대 못 잡는다.
89
+ */
90
+ async function subdomainOf(manager, domainId) {
91
+ const found = await manager.findOne(shell_1.Domain, { where: { id: domainId } });
92
+ return found?.subdomain;
93
+ }
94
+ /**
95
+ * 이 제품이 내놓는 역할 자리 중 이 공장에 선 것이 몇인가.
96
+ *
97
+ * 결재선은 **역할을 가리킨다**(`[{type:'Role', value:<역할 id>}]`). 그러니 역할이 없는 공장에서는
98
+ * 결재선을 만들 수 없다 — 양식 화면까지 가서야 그걸 알게 된다. 문 현황과 함께 내서 화면이 순서를
99
+ * 말하게 한다.
100
+ *
101
+ * 공장이 스스로 만든 다른 역할은 안 센다. 이 수가 말하는 것은 「이 제품이 내놓은 자리」이고,
102
+ * 그 밖의 역할로 결재선을 짜는 것도 물론 된다.
103
+ */
104
+ async function seatsStanding(manager, domain) {
105
+ const offered = (0, work_door_declaration_js_1.offeredSeatNames)();
106
+ const here = await manager.find(auth_base_1.Role, { where: { domain: { id: domain.id } } });
107
+ const names = new Set(here.map(one => one.name));
108
+ return offered.filter(one => names.has(one)).length;
109
+ }
110
+ /** 이 설치본의 앱들이 내놓는 자리의 수 — 화면이 목록을 따로 들지 않게 여기서 센다. */
111
+ function seatsOffered() {
112
+ return (0, work_door_declaration_js_1.offeredSeatNames)().length;
113
+ }
114
+ /**
115
+ * 화면에 낼 이름. **선언은 키를 주고 글자는 각 모듈의 번역이 답한다** — 여기서 글자를 들고 있으면
116
+ * 한 제품의 낱말이 다른 제품 화면에 선다. 번역이 없으면 양식 이름을 그대로 보인다(키를 찍는 것보다
117
+ * 낫다 — 양식 이름은 적어도 사람이 찾을 수 있는 이름이다).
118
+ */
119
+ function labelOf(door) {
120
+ return door.labelKey || door.name;
121
+ }
122
+ function labelOfDoorNamed(name) {
123
+ const found = (0, work_door_declaration_js_1.declaredDoors)().find(one => one.name === name);
124
+ return found ? labelOf(found) : name;
125
+ }
126
+ //# sourceMappingURL=work-door-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-door-service.js","sourceRoot":"","sources":["../../../server/service/work-door/work-door-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager, In } from 'typeorm'\n\nimport { Role } from '@things-factory/auth-base'\nimport { Domain } from '@things-factory/shell'\n\nimport { activityNamedIn, seatReader } from './activity-lookup.js'\nimport { judgeApprovalLine } from './approval-line-standing.js'\nimport { declaredDoors, offeredSeatNames } from './work-door-declaration.js'\nimport { WorkDoor, judgeDoor } from './work-door'\nimport { WorkDoorNotUsed } from './work-door-not-used'\n\n/**\n * 이 공장의 문 열둘을 읽어 판정한다 — **한 벌.**\n *\n * ── 왜 resolver 밖에 두나 ──────────────────────────────────────────────────\n * 이 판정을 묻는 자리가 둘이 됐다. 화면(`workDoors`)과 성숙도 표다. 각자 읽으면 둘이 다른 수를\n * 말하게 되고, **어느 쪽이 맞는지 보는 사람이 알 길이 없다.** 성숙도 표는 이 제품이 스스로에 대해\n * 하는 말이라 화면과 어긋나면 그 표 전체를 못 믿는다.\n *\n * ── 부모까지 보는 규칙은 상신하는 쪽의 것을 그대로 쓴다 ────────────────────\n * 상신이 `activityNamedIn` 으로 양식을 찾으므로, 보는 쪽이 다른 규칙으로 찾으면 **「없다」고\n * 말하는데 실제로는 서는** 상태가 생긴다.\n */\nexport async function workDoorsFor(manager: EntityManager, domain: Domain): Promise<WorkDoor[]> {\n /* 공장이 「안 쓴다」고 말한 것을 한 번에 읽는다. 문마다 읽으면 열두 번 묻는다. */\n const declared = new Map(\n (await manager.find(WorkDoorNotUsed, { where: { domain: { id: domain.id } } })).map(one => [\n one.doorName,\n one.because\n ])\n )\n\n const doors: WorkDoor[] = []\n\n /*\n * **포트 하나를 문 열일곱이 함께 쓴다.** 포트가 읽은 역할을 기억하므로 같은 역할을 여러 번 묻지\n * 않는다 — 결재선 대부분이 공장장으로 끝난다. 이 판정 동안만 산다.\n */\n const reader = seatReader(manager)\n\n for (const door of declaredDoors()) {\n const name = door.name\n const activity = await activityNamedIn(manager, domain, name)\n /*\n * **결재선을 빌려 쓰는 문**은 따르는 문의 결재선으로 센다(§`LINE_FOLLOWS`). 자기 칸을 세면, 올리는\n * 쪽은 발행 승인의 결재선으로 서는데 현황은 「결재자 없음」이라고 말한다.\n */\n const follows = door.lineFollows\n const lineOwner = follows ? await activityNamedIn(manager, domain, follows) : activity\n\n doors.push(\n judgeDoor({\n name,\n label: labelOf(door),\n kind: door.kind,\n notUsedBecause: declared.get(name),\n follows: follows ? labelOfDoorNamed(follows) : undefined,\n /* 상신하는 쪽과 **같은 함수**로 센다. 여기서 따로 세면 화면과 관문이 갈린다. */\n approvalStanding: activity\n ? await judgeApprovalLine(lineOwner?.approvalLine as Parameters<typeof judgeApprovalLine>[0], reader)\n : undefined,\n installed: activity\n ? {\n approvalLine: lineOwner?.approvalLine as unknown[] | undefined,\n assigneeRole: await roleNameOf(manager, (activity as { assigneeRoleId?: string }).assigneeRoleId),\n /*\n * **빌려 온 것일 때만** 채운다. `Activity` 는 `domainId` 만 들고 있어 이름은 따로\n * 읽는데, 자기 도메인이면 읽지도 않고 비운다 — 자기 이름을 채우면 화면이 모든 줄에\n * 「우리 공장에서 정했습니다」를 달고, 「결재자 없음」 옆에서 그 말이 거짓이 된다.\n */\n borrowedFrom:\n activity.domainId === domain.id ? undefined : await subdomainOf(manager, activity.domainId)\n }\n : undefined\n })\n )\n }\n\n return doors\n}\n\n/**\n * 그 역할의 이름. 없으면 없다 — 지어내지 않는다.\n *\n * 문마다 부르지 않고 배정 문에서만 부른다. 배정 문이 하나도 없는 지금은 한 번도 안 돈다.\n */\nasync function roleNameOf(manager: EntityManager, roleId?: string): Promise<string | undefined> {\n if (!roleId) {\n return undefined\n }\n\n const found = await manager.findOne(Role, { where: { id: roleId } })\n\n return found?.name\n}\n\n/**\n * 부모 도메인의 이름. 못 읽으면 지어내지 않고 비운다 — 「본사」라고 적으면 없는 이름이 화면에 남는다.\n *\n * 원문 SQL 로 안 읽는다. 자리표시자 철자가 드라이버마다 달라(`?` · `$1`) sqlite 에서는 통과하고\n * postgres 에서만 죽는다 — 그 부류는 여기서 절대 못 잡는다.\n */\nasync function subdomainOf(manager: EntityManager, domainId: string): Promise<string | undefined> {\n const found = await manager.findOne(Domain, { where: { id: domainId } })\n\n return found?.subdomain\n}\n\n/**\n * 이 제품이 내놓는 역할 자리 중 이 공장에 선 것이 몇인가.\n *\n * 결재선은 **역할을 가리킨다**(`[{type:'Role', value:<역할 id>}]`). 그러니 역할이 없는 공장에서는\n * 결재선을 만들 수 없다 — 양식 화면까지 가서야 그걸 알게 된다. 문 현황과 함께 내서 화면이 순서를\n * 말하게 한다.\n *\n * 공장이 스스로 만든 다른 역할은 안 센다. 이 수가 말하는 것은 「이 제품이 내놓은 자리」이고,\n * 그 밖의 역할로 결재선을 짜는 것도 물론 된다.\n */\nexport async function seatsStanding(manager: EntityManager, domain: Domain): Promise<number> {\n const offered = offeredSeatNames()\n const here = await manager.find(Role, { where: { domain: { id: domain.id } } })\n const names = new Set(here.map(one => one.name))\n\n return offered.filter(one => names.has(one)).length\n}\n\n/** 이 설치본의 앱들이 내놓는 자리의 수 — 화면이 목록을 따로 들지 않게 여기서 센다. */\nexport function seatsOffered(): number {\n return offeredSeatNames().length\n}\n\n/**\n * 화면에 낼 이름. **선언은 키를 주고 글자는 각 모듈의 번역이 답한다** — 여기서 글자를 들고 있으면\n * 한 제품의 낱말이 다른 제품 화면에 선다. 번역이 없으면 양식 이름을 그대로 보인다(키를 찍는 것보다\n * 낫다 — 양식 이름은 적어도 사람이 찾을 수 있는 이름이다).\n */\nfunction labelOf(door: { labelKey: string; name: string }): string {\n return door.labelKey || door.name\n}\n\nfunction labelOfDoorNamed(name: string): string {\n const found = declaredDoors().find(one => one.name === name)\n\n return found ? labelOf(found) : name\n}\n"]}
@@ -0,0 +1,49 @@
1
+ import type { WorkDoor } from './work-door.js';
2
+ /**
3
+ * 「이 공장에서 어느 결재 문이 서 있나」를 화면에 낼 모양.
4
+ *
5
+ * 문자열 하나로 안 낸다 — 화면이 상태별로 다르게 그려야 하고, 그러려면 상태가 값이어야 한다.
6
+ * 문장만 주면 화면이 그 문장을 다시 뜯어 읽는다.
7
+ */
8
+ export declare enum DoorStandingValue {
9
+ /** 채워졌다. */
10
+ On = "on",
11
+ /** 양식은 섰는데 받을 사람이 없다. 조치 대상. */
12
+ Off = "off",
13
+ /** 양식이 아예 안 섰다 — 설정이 아니라 결함이다. 조치 대상. */
14
+ Missing = "missing",
15
+ /** 이 공장이 안 쓰기로 했다. 조치 대상이 아니다. */
16
+ NotUsed = "not-used"
17
+ }
18
+ /** 결재냐 배정이냐 — 비었을 때 결과가 반대라 화면이 갈라 그려야 한다. */
19
+ export declare enum DoorKindValue {
20
+ Approval = "approval",
21
+ Assignment = "assignment"
22
+ }
23
+ export declare class WorkDoorType {
24
+ name: string;
25
+ label: string;
26
+ kind: DoorKindValue;
27
+ standing: DoorStandingValue;
28
+ approvers: number;
29
+ from?: string;
30
+ because: string;
31
+ }
32
+ export declare class WorkDoorsType {
33
+ doors: WorkDoorType[];
34
+ summary: string;
35
+ todo: number;
36
+ /**
37
+ * 이 제품이 내놓는 역할 자리 중 **이 공장에 실제로 선 것.**
38
+ *
39
+ * ── 왜 문 목록에 자리 수가 붙나 ────────────────────────────────────────
40
+ * 문이 비었다는 말만 하면 사람은 양식 화면으로 간다. 그런데 **고를 역할이 없으면 그 화면의
41
+ * 결재선 칸이 빈 목록**이다. 헛걸음하고 돌아와서, 무엇이 잘못됐는지 모른 채 이 화면을 다시 본다.
42
+ *
43
+ * 두 수를 함께 내면 화면이 순서를 말할 수 있다 — 자리부터 세우고, 그다음에 결재선을 건다.
44
+ */
45
+ seatsStanding: number;
46
+ seatsOffered: number;
47
+ }
48
+ /** 판단의 모양을 화면의 모양으로. 열거형 철자는 `@Field` 가 정하므로 값으로 옮긴다. */
49
+ export declare function toDoorType(door: WorkDoor): WorkDoorType;