Add Phase 4b: instructor blocked dates, store closures, and substitute instructors
- New tables: instructor_blocked_date, store_closure (migration 0034) - substitute_instructor_id column added to lesson_session - Session generation skips blocked instructor dates and store closure periods - Substitute assignment validates sub is not blocked and has no conflicting slot - Routes: POST/GET/DELETE /instructors/:id/blocked-dates, POST/GET/DELETE /store-closures - 15 new integration tests covering blocked dates, store closures, and sub validation
This commit is contained in:
21
packages/backend/src/db/migrations/0034_blocked_dates.sql
Normal file
21
packages/backend/src/db/migrations/0034_blocked_dates.sql
Normal file
@@ -0,0 +1,21 @@
|
||||
-- Phase 4b: Instructor blocked dates, store closures, and substitute instructor on sessions
|
||||
|
||||
ALTER TABLE "lesson_session"
|
||||
ADD COLUMN "substitute_instructor_id" uuid REFERENCES "instructor"("id");
|
||||
|
||||
CREATE TABLE "instructor_blocked_date" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
"instructor_id" uuid NOT NULL REFERENCES "instructor"("id"),
|
||||
"start_date" date NOT NULL,
|
||||
"end_date" date NOT NULL,
|
||||
"reason" varchar(255),
|
||||
"created_at" timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE "store_closure" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
"name" varchar(255) NOT NULL,
|
||||
"start_date" date NOT NULL,
|
||||
"end_date" date NOT NULL,
|
||||
"created_at" timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
@@ -239,6 +239,13 @@
|
||||
"when": 1774930000000,
|
||||
"tag": "0033_lesson_plans",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 34,
|
||||
"version": "7",
|
||||
"when": 1774940000000,
|
||||
"tag": "0034_blocked_dates",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -115,11 +115,31 @@ export const lessonSessions = pgTable('lesson_session', {
|
||||
nextLessonGoals: text('next_lesson_goals'),
|
||||
topicsCovered: text('topics_covered').array(),
|
||||
makeupForSessionId: uuid('makeup_for_session_id'),
|
||||
substituteInstructorId: uuid('substitute_instructor_id').references(() => instructors.id),
|
||||
notesCompletedAt: timestamp('notes_completed_at', { withTimezone: true }),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
|
||||
})
|
||||
|
||||
export const instructorBlockedDates = pgTable('instructor_blocked_date', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
instructorId: uuid('instructor_id')
|
||||
.notNull()
|
||||
.references(() => instructors.id),
|
||||
startDate: date('start_date').notNull(),
|
||||
endDate: date('end_date').notNull(),
|
||||
reason: varchar('reason', { length: 255 }),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
||||
})
|
||||
|
||||
export const storeClosures = pgTable('store_closure', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
name: varchar('name', { length: 255 }).notNull(),
|
||||
startDate: date('start_date').notNull(),
|
||||
endDate: date('end_date').notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
||||
})
|
||||
|
||||
export const gradingScales = pgTable('grading_scale', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
name: varchar('name', { length: 255 }).notNull(),
|
||||
@@ -210,6 +230,10 @@ export type Enrollment = typeof enrollments.$inferSelect
|
||||
export type EnrollmentInsert = typeof enrollments.$inferInsert
|
||||
export type LessonSession = typeof lessonSessions.$inferSelect
|
||||
export type LessonSessionInsert = typeof lessonSessions.$inferInsert
|
||||
export type InstructorBlockedDate = typeof instructorBlockedDates.$inferSelect
|
||||
export type InstructorBlockedDateInsert = typeof instructorBlockedDates.$inferInsert
|
||||
export type StoreClosure = typeof storeClosures.$inferSelect
|
||||
export type StoreClosureInsert = typeof storeClosures.$inferInsert
|
||||
export type GradingScale = typeof gradingScales.$inferSelect
|
||||
export type GradingScaleInsert = typeof gradingScales.$inferInsert
|
||||
export type GradingScaleLevel = typeof gradingScaleLevels.$inferSelect
|
||||
|
||||
Reference in New Issue
Block a user