feat: 전사 공유 일정(주간 캘린더) 기능 추가
상단 nav 독립 메뉴 '일정' — 주간 타임라인(간트형) 캘린더. 카테고리=레인, 일정=막대(다중일 지원), 우측 상세 패널, 일정/카테고리 CRUD. 백엔드(Schedule 모듈): - ScheduleCategory/ScheduleEvent 엔티티 + 참석자(다대다) + 작성자 - 카테고리/일정 CRUD, 기간 겹침 조회, 참석자 풀(전사 사용자) - 기본 카테고리 12종 onModuleInit 멱등 시드 - 인증 사용자 누구나 관리(전역 일정, 글로벌 관리자 개념 없음) - 운영 마이그레이션(AddSchedule) 추가, @nestjs/schedule 임포트는 CronModule 로 alias 프론트: - /schedule 라우트 + 사이드바 nav 항목 - 주간 네비(이전/다음/오늘), 유형 필터·카테고리 관리 드롭다운 - 타임라인/상세 패널/일정 모달/카테고리 모달(hue 슬라이더)/참석자 멀티셀렉트 - schedule.store + useSchedule + scheduleDate 유틸 런타임 검증: dev 부팅·시드(12건)·라우트 매핑 정상, 인증 게이트(401), 일정 생성/조회/수정/삭제 + 참석자/전직원/다중일 스모크 전부 정상. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
// 전사 공유 일정(캘린더) — 카테고리/일정/참석자 테이블 추가.
|
||||
// 운영(migrationsRun)에서만 실행되며, dev 는 synchronize 로 자동 반영된다.
|
||||
// (기본 카테고리 시드는 ScheduleService.onModuleInit 가 멱등 처리하므로 여기서 넣지 않는다.)
|
||||
export class AddSchedule1782300000000 implements MigrationInterface {
|
||||
name = 'AddSchedule1782300000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// 카테고리(레인)
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "schedule_categories" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "label" character varying NOT NULL, "color" character varying NOT NULL, "sort_order" integer NOT NULL DEFAULT '0', "created_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_schedule_categories" PRIMARY KEY ("id"))`,
|
||||
);
|
||||
|
||||
// 일정(이벤트)
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "schedule_events" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "title" character varying NOT NULL, "start_date" date NOT NULL, "end_date" date NOT NULL, "time" character varying NOT NULL DEFAULT '', "place" character varying, "description" text, "all_hands" boolean NOT NULL DEFAULT false, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), "category_id" uuid, "created_by" uuid, CONSTRAINT "PK_schedule_events" PRIMARY KEY ("id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_schedule_events_dates" ON "schedule_events" ("start_date", "end_date")`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_schedule_events_category" ON "schedule_events" ("category_id")`,
|
||||
);
|
||||
|
||||
// 참석자(다대다 조인)
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "schedule_event_attendees" ("event_id" uuid NOT NULL, "user_id" uuid NOT NULL, CONSTRAINT "PK_schedule_event_attendees" PRIMARY KEY ("event_id", "user_id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_schedule_event_attendees_event" ON "schedule_event_attendees" ("event_id")`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_schedule_event_attendees_user" ON "schedule_event_attendees" ("user_id")`,
|
||||
);
|
||||
|
||||
// FK
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "schedule_events" ADD CONSTRAINT "FK_schedule_events_category" FOREIGN KEY ("category_id") REFERENCES "schedule_categories"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "schedule_events" ADD CONSTRAINT "FK_schedule_events_created_by" FOREIGN KEY ("created_by") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "schedule_event_attendees" ADD CONSTRAINT "FK_schedule_event_attendees_event" FOREIGN KEY ("event_id") REFERENCES "schedule_events"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "schedule_event_attendees" ADD CONSTRAINT "FK_schedule_event_attendees_user" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "schedule_event_attendees" DROP CONSTRAINT "FK_schedule_event_attendees_user"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "schedule_event_attendees" DROP CONSTRAINT "FK_schedule_event_attendees_event"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "schedule_events" DROP CONSTRAINT "FK_schedule_events_created_by"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "schedule_events" DROP CONSTRAINT "FK_schedule_events_category"`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "schedule_event_attendees"`);
|
||||
await queryRunner.query(`DROP TABLE "schedule_events"`);
|
||||
await queryRunner.query(`DROP TABLE "schedule_categories"`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user