@kms545487/contracts 0.1.0

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/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # @kms545487/contracts
2
+
3
+ 프론트엔드(Next.js)와 백엔드(NestJS)가 공유하는 **도메인 계약** 단일 소스. 도메인 타입·enum·요청 DTO 형상을 담습니다.
4
+
5
+ 빌드 시 `dist/`에 `.d.ts`(+빈 `.js`)를 emit합니다. 소비측은 `import type`으로만 가져가 런타임 의존이 없습니다.
6
+
7
+ ## 빌드
8
+
9
+ ```bash
10
+ npm install
11
+ npm run build # → dist/index.d.ts, dist/index.js
12
+ ```
13
+
14
+ ## 배포 (npm 레지스트리)
15
+
16
+ repo가 분리되어 있어 **원격/CI 빌드에서는 `file:../contracts`가 동작하지 않습니다** (옆에 contracts 폴더가 없음).
17
+ 따라서 이 패키지를 배포하고, 소비측은 **버전**으로 의존해야 합니다.
18
+
19
+ > ⚠️ `@taco` 스코프: 공개 npm에 올리려면 `@taco` 조직을 소유해야 합니다.
20
+ > 소유하지 않으면 (a) 본인 스코프(`@yourorg/contracts`)로 이름을 바꾸거나,
21
+ > (b) **GitHub Packages**(조직 스코프) 사용을 권장합니다.
22
+
23
+ ### 1) 배포
24
+
25
+ ```bash
26
+ cd contracts
27
+ npm version patch # 0.1.0 → 0.1.1 (변경 시마다)
28
+ npm publish --access public # prepublishOnly가 자동 build
29
+ ```
30
+
31
+ #### 2FA 오류(E403) 해결
32
+ npm은 publish에 2단계 인증을 요구합니다. 둘 중 하나:
33
+
34
+ - **일회성(OTP)**: 인증앱 6자리 코드로 즉시 publish
35
+ ```bash
36
+ npm publish --access public --otp=123456
37
+ ```
38
+ - **토큰(반복·CI 권장)**: npmjs.com → Access Tokens → **Granular/Automation token**
39
+ (publish 시 2FA bypass 가능)를 발급 → 환경변수로 주입 (이 폴더의 `.npmrc`가 `${NPM_TOKEN}` 사용)
40
+ ```bash
41
+ export NPM_TOKEN=npm_xxxxx
42
+ npm publish --access public
43
+ ```
44
+ CI에서는 `NPM_TOKEN`을 시크릿으로 등록하면 됩니다.
45
+
46
+ > 비공개로 두려면 `--access public` 대신 `publishConfig.access: "restricted"`(유료 플랜 필요).
47
+
48
+ ### 2) 소비측(frontend·backend) 의존 전환
49
+
50
+ ```jsonc
51
+ // package.json
52
+ { "dependencies": { "@kms545487/contracts": "^0.1.0" } } // file:../contracts → 버전
53
+ ```
54
+
55
+ ```bash
56
+ npm install # 레지스트리에서 설치 → CI 빌드 통과
57
+ ```
58
+
59
+ ### 로컬 개발 (미배포 변경분 사용)
60
+
61
+ 배포 전 로컬에서 최신 계약을 쓰려면 `npm link` 사용:
62
+
63
+ ```bash
64
+ cd contracts && npm run build && npm link
65
+ cd ../frontend && npm link @kms545487/contracts
66
+ cd ../backend && npm link @kms545487/contracts
67
+ ```
68
+
69
+ ## 구성
70
+
71
+ ```
72
+ src/
73
+ ├─ common.ts # ID, ISODate, Audited
74
+ ├─ account.ts # Account, AccountRole, WebIdCheckResult
75
+ ├─ people.ts # Student, Parent, ParentStudent, Instructor
76
+ ├─ catalog.ts # Subject, Course(hourlyRate)
77
+ ├─ enrollment.ts # Enrollment
78
+ ├─ session.ts # ClassSession, Attendance, SessionReport
79
+ ├─ finance.ts # Payment, Transaction, Expense(ApprovalStatus), InstructorPayout
80
+ ├─ counsel.ts # CounselForm, CounselRound
81
+ ├─ event.ts # AcademyEvent, EventType, EventPriority
82
+ └─ inputs.ts # Create*Input (요청 DTO 형상)
83
+ ```
@@ -0,0 +1,14 @@
1
+ import type { ID } from './common';
2
+ export type AccountRole = 'student' | 'parent' | 'instructor' | 'manager' | 'admin' | 'super_admin';
3
+ export type Account = {
4
+ id: ID;
5
+ webId: string;
6
+ name: string;
7
+ role: AccountRole;
8
+ };
9
+ export type WebIdCheckResult = {
10
+ webId: string;
11
+ exists: boolean;
12
+ name?: string;
13
+ role?: AccountRole;
14
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,14 @@
1
+ import type { ID } from './common';
2
+ export type Subject = {
3
+ id: ID;
4
+ code: string;
5
+ name: string;
6
+ };
7
+ export type Course = {
8
+ id: ID;
9
+ name: string;
10
+ subjectId: ID;
11
+ instructorId: ID;
12
+ price: number;
13
+ hourlyRate: number;
14
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ export type ID = number;
2
+ export type ISODate = string;
3
+ export type Audited = {
4
+ createdAt?: ISODate;
5
+ updatedAt?: ISODate;
6
+ };
package/dist/common.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,40 @@
1
+ import type { ID, ISODate } from './common';
2
+ export type CounselStatus = 'requested' | 'pending' | 'registered' | 'dropped';
3
+ export type CounselSource = 'internal_form' | 'naver_form' | 'google_form' | 'manual' | 'etc';
4
+ export type DesiredStartTime = 'immediately' | 'within_1_month' | 'within_2_3_months' | 'undecided';
5
+ export type LearningAtmosphere = 'self_directed' | 'normal' | 'needs_management';
6
+ export type StudentIntention = 'student_wants' | 'parent_only' | 'unknown';
7
+ export type CounselResult = 'positive' | 'neutral' | 'negative' | 'no_response' | 'registered';
8
+ export type CounselForm = {
9
+ id: ID;
10
+ applicantName: string;
11
+ applicantPhone?: string;
12
+ parentId?: ID;
13
+ studentId?: ID;
14
+ assignedStaffId?: ID;
15
+ status: CounselStatus;
16
+ source: CounselSource;
17
+ interestSubjectId?: ID;
18
+ interestCourseId?: ID;
19
+ academyExpectation?: string;
20
+ desiredStartTime?: DesiredStartTime;
21
+ learningAtmosphere?: LearningAtmosphere;
22
+ studentIntention?: StudentIntention;
23
+ weakness?: string;
24
+ nextContactAt?: ISODate;
25
+ createdAt: ISODate;
26
+ };
27
+ export type CounselRound = {
28
+ id: ID;
29
+ counselFormId: ID;
30
+ roundNo: number;
31
+ counselorId?: ID;
32
+ scheduledAt?: ISODate;
33
+ completedAt?: ISODate;
34
+ isCompleted: boolean;
35
+ summary?: string;
36
+ detail?: string;
37
+ result?: CounselResult;
38
+ nextAction?: string;
39
+ nextContactAt?: ISODate;
40
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ import type { ID, ISODate, Audited } from './common';
2
+ export type EnrollmentStatus = 'active' | 'paused' | 'completed' | 'canceled';
3
+ export type Enrollment = {
4
+ id: ID;
5
+ studentId: ID;
6
+ courseId: ID;
7
+ roadmapId?: ID;
8
+ status: EnrollmentStatus;
9
+ totalSessions?: number;
10
+ completedSessions?: number;
11
+ memo?: string;
12
+ enrolledAt: ISODate;
13
+ } & Audited;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ import type { ID, ISODate, Audited } from './common';
2
+ export type EventType = 'notice' | 'exam' | 'holiday' | 'closure' | 'event';
3
+ export type EventPriority = 'low' | 'normal' | 'high';
4
+ export type AcademyEvent = {
5
+ id: ID;
6
+ title: string;
7
+ type: EventType;
8
+ priority: EventPriority;
9
+ startDate: ISODate;
10
+ endDate: ISODate;
11
+ allDay?: boolean;
12
+ memo?: string;
13
+ } & Audited;
package/dist/event.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,51 @@
1
+ import type { ID, ISODate, Audited } from './common';
2
+ export type PaymentStatus = 'pending' | 'paid' | 'overdue' | 'refunded' | 'partial_refund';
3
+ export type PaymentMethod = 'card' | 'transfer' | 'cash' | 'point' | 'etc';
4
+ export type Payment = {
5
+ id: ID;
6
+ enrollmentId?: ID;
7
+ studentId: ID;
8
+ payerParentId?: ID;
9
+ amount: number;
10
+ paidAmount?: number;
11
+ status: PaymentStatus;
12
+ paymentMethod?: PaymentMethod;
13
+ dueAt?: ISODate;
14
+ paidAt?: ISODate;
15
+ memo?: string;
16
+ } & Audited;
17
+ export type TxDirection = 'in' | 'out';
18
+ export type Transaction = {
19
+ id: ID;
20
+ direction: TxDirection;
21
+ category: string;
22
+ label: string;
23
+ amount: number;
24
+ method?: string;
25
+ occurredAt: ISODate;
26
+ };
27
+ export type ApprovalStatus = 'requested' | 'approved' | 'rejected';
28
+ export type ExpenseCategory = 'supplies' | 'equipment' | 'books' | 'rent' | 'utility' | 'marketing' | 'meal' | 'etc';
29
+ export type Expense = {
30
+ id: ID;
31
+ category: ExpenseCategory;
32
+ title: string;
33
+ amount: number;
34
+ spentAt: ISODate;
35
+ vendor?: string;
36
+ memo?: string;
37
+ receiptUrl?: string;
38
+ status: ApprovalStatus;
39
+ } & Audited;
40
+ export type PayoutStatus = 'pending' | 'confirmed' | 'paid';
41
+ export type InstructorPayout = {
42
+ id: ID;
43
+ instructorId: ID;
44
+ periodStart: ISODate;
45
+ periodEnd: ISODate;
46
+ sessionCount?: number;
47
+ totalMinutes?: number;
48
+ amount: number;
49
+ status: PayoutStatus;
50
+ paidAt?: ISODate;
51
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,10 @@
1
+ export * from './common';
2
+ export * from './account';
3
+ export * from './people';
4
+ export * from './catalog';
5
+ export * from './enrollment';
6
+ export * from './session';
7
+ export * from './finance';
8
+ export * from './counsel';
9
+ export * from './event';
10
+ export * from './inputs';
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./common"), exports);
18
+ __exportStar(require("./account"), exports);
19
+ __exportStar(require("./people"), exports);
20
+ __exportStar(require("./catalog"), exports);
21
+ __exportStar(require("./enrollment"), exports);
22
+ __exportStar(require("./session"), exports);
23
+ __exportStar(require("./finance"), exports);
24
+ __exportStar(require("./counsel"), exports);
25
+ __exportStar(require("./event"), exports);
26
+ __exportStar(require("./inputs"), exports);
@@ -0,0 +1,58 @@
1
+ import type { ID, ISODate } from './common';
2
+ import type { StudentStatus, ResidenceType } from './people';
3
+ import type { PaymentMethod, ExpenseCategory } from './finance';
4
+ import type { EventType, EventPriority } from './event';
5
+ export type CreateStudentInput = {
6
+ name: string;
7
+ englishName?: string;
8
+ phone?: string;
9
+ grade?: number;
10
+ schoolName?: string;
11
+ residenceType?: ResidenceType;
12
+ status?: StudentStatus;
13
+ memo?: string;
14
+ webId?: string;
15
+ };
16
+ export type CreateEnrollmentInput = {
17
+ studentId: ID;
18
+ courseId: ID;
19
+ roadmapId?: ID;
20
+ totalSessions?: number;
21
+ memo?: string;
22
+ };
23
+ export type CreatePaymentInput = {
24
+ studentId: ID;
25
+ enrollmentId?: ID;
26
+ payerParentId?: ID;
27
+ amount: number;
28
+ paymentMethod?: PaymentMethod;
29
+ };
30
+ export type CreateExpenseInput = {
31
+ category: ExpenseCategory;
32
+ title: string;
33
+ amount: number;
34
+ spentAt: ISODate;
35
+ vendor?: string;
36
+ memo?: string;
37
+ receiptUrl?: string;
38
+ };
39
+ export type CreateSubjectInput = {
40
+ code: string;
41
+ name: string;
42
+ };
43
+ export type CreateCourseInput = {
44
+ name: string;
45
+ subjectId: ID;
46
+ instructorId: ID;
47
+ price: number;
48
+ hourlyRate: number;
49
+ };
50
+ export type CreateEventInput = {
51
+ title: string;
52
+ type: EventType;
53
+ priority?: EventPriority;
54
+ startDate: ISODate;
55
+ endDate: ISODate;
56
+ allDay?: boolean;
57
+ memo?: string;
58
+ };
package/dist/inputs.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,35 @@
1
+ import type { ID, Audited } from './common';
2
+ export type StudentStatus = 'lead' | 'active' | 'paused' | 'completed' | 'canceled';
3
+ export type ResidenceType = 'domestic' | 'overseas';
4
+ export type Student = {
5
+ id: ID;
6
+ name: string;
7
+ englishName?: string;
8
+ grade?: number;
9
+ phone?: string;
10
+ status: StudentStatus;
11
+ schoolName?: string;
12
+ residenceType?: ResidenceType;
13
+ memo?: string;
14
+ webId?: string;
15
+ } & Audited;
16
+ export type Parent = {
17
+ id: ID;
18
+ name: string;
19
+ phone: string;
20
+ kakaoAvailable: boolean;
21
+ webId?: string;
22
+ } & Audited;
23
+ export type ParentStudent = {
24
+ id: ID;
25
+ parentId: ID;
26
+ studentId: ID;
27
+ relation?: string;
28
+ isPayer: boolean;
29
+ isPrimary: boolean;
30
+ };
31
+ export type Instructor = {
32
+ id: ID;
33
+ name: string;
34
+ subjectName?: string;
35
+ };
package/dist/people.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,28 @@
1
+ import type { ID, ISODate } from './common';
2
+ export type SessionStatus = 'scheduled' | 'held' | 'canceled' | 'no_show' | 'makeup';
3
+ export type ClassSession = {
4
+ id: ID;
5
+ courseId: ID;
6
+ instructorId: ID;
7
+ sessionDate: ISODate;
8
+ durationMinutes: number;
9
+ status: SessionStatus;
10
+ topic?: string;
11
+ };
12
+ export type AttendanceStatus = 'present' | 'late' | 'absent' | 'excused';
13
+ export type Attendance = {
14
+ id: ID;
15
+ sessionId: ID;
16
+ studentId: ID;
17
+ status: AttendanceStatus;
18
+ };
19
+ export type ReportStatus = 'draft' | 'submitted' | 'sent';
20
+ export type SessionReport = {
21
+ id: ID;
22
+ sessionId: ID;
23
+ studentId: ID;
24
+ instructorId: ID;
25
+ content: string;
26
+ homework?: string;
27
+ status: ReportStatus;
28
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@kms545487/contracts",
3
+ "version": "0.1.0",
4
+ "description": "TACO 공유 도메인 계약(타입·enum·DTO). 프론트/백 단일 소스.",
5
+ "license": "UNLICENSED",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "sideEffects": false,
18
+ "scripts": {
19
+ "build": "tsc -p tsconfig.build.json",
20
+ "prepublishOnly": "npm run build",
21
+ "typecheck": "tsc --noEmit"
22
+ },
23
+ "devDependencies": {
24
+ "typescript": "^5.6.2"
25
+ },
26
+ "publishConfig": {
27
+ "access": "public"
28
+ }
29
+ }