@@ -162,10 +162,478 @@ async function seed() {
}
}
// --- Enable lessons module ---
await sql ` UPDATE module_config SET enabled = true WHERE slug = 'lessons' `
console . log ( ' Enabled lessons module' )
// --- Lesson seed data ---
await seedLessons ( sql )
console . log ( '\nMusic store seed complete!' )
await sql . end ( )
}
// Returns dates (YYYY-MM-DD) for every occurrence of `dayOfWeek` (0=Sun)
// starting from `startDate`, for `count` weeks.
function weeklyDates ( startDate : string , dayOfWeek : number , count : number ) : string [ ] {
const d = new Date ( startDate + 'T12:00:00Z' )
while ( d . getUTCDay ( ) !== dayOfWeek ) d . setUTCDate ( d . getUTCDate ( ) + 1 )
return Array . from ( { length : count } , ( _ , i ) = > {
const nd = new Date ( d )
nd . setUTCDate ( nd . getUTCDate ( ) + i * 7 )
return nd . toISOString ( ) . split ( 'T' ) [ 0 ]
} )
}
async function seedLessons ( sql : any ) {
console . log ( '\nSeeding lessons data...' )
// ── Grading scale ──────────────────────────────────────────────────────────
const [ existingScale ] = await sql ` SELECT id FROM grading_scale WHERE name = 'Standard Progress' `
let scaleId : string
if ( existingScale ) {
scaleId = existingScale . id
} else {
const [ scale ] = await sql `
INSERT INTO grading_scale (name, description, is_default, is_active)
VALUES ('Standard Progress', 'Four-level scale used across all instruments', true, true)
RETURNING id `
scaleId = scale . id
const levels = [
{ value : '1' , label : 'Introduced' , numericValue : 1 , colorHex : null , sortOrder : 1 } ,
{ value : '2' , label : 'Developing' , numericValue : 2 , colorHex : '#EAB308' , sortOrder : 2 } ,
{ value : '3' , label : 'Proficient' , numericValue : 3 , colorHex : '#3B82F6' , sortOrder : 3 } ,
{ value : '4' , label : 'Mastered' , numericValue : 4 , colorHex : '#22C55E' , sortOrder : 4 } ,
]
for ( const lv of levels ) {
await sql ` INSERT INTO grading_scale_level (grading_scale_id, value, label, numeric_value, color_hex, sort_order)
VALUES ( ${ scaleId } , ${ lv . value } , ${ lv . label } , ${ lv . numericValue } , ${ lv . colorHex } , ${ lv . sortOrder } ) `
}
console . log ( ' Grading scale: Standard Progress' )
}
// ── Instructors ────────────────────────────────────────────────────────────
const instructorDefs = [
{
displayName : 'Sarah Mitchell' ,
bio : 'Classical piano and violin instructor with 12 years of teaching experience. Suzuki-certified for violin.' ,
instruments : [ 'Piano' , 'Violin' ] ,
} ,
{
displayName : 'Marcus Webb' ,
bio : 'Guitarist and bassist specializing in rock, blues, and jazz. 8 years of studio and teaching experience.' ,
instruments : [ 'Guitar' , 'Bass' ] ,
} ,
{
displayName : 'Diana Reyes' ,
bio : 'Woodwind specialist with a music education degree. Teaches saxophone, clarinet, and flute at all levels.' ,
instruments : [ 'Saxophone' , 'Clarinet' , 'Flute' ] ,
} ,
]
const instrIds : Record < string , string > = { }
for ( const def of instructorDefs ) {
const [ existing ] = await sql ` SELECT id FROM instructor WHERE display_name = ${ def . displayName } `
if ( existing ) { instrIds [ def . displayName ] = existing . id ; continue }
const [ row ] = await sql `
INSERT INTO instructor (display_name, bio, instruments, is_active)
VALUES ( ${ def . displayName } , ${ def . bio } , ${ def . instruments } , true)
RETURNING id `
instrIds [ def . displayName ] = row . id
console . log ( ` Instructor: ${ def . displayName } ` )
}
// ── Lesson types ───────────────────────────────────────────────────────────
const lessonTypeDefs = [
{ name : '30-min Private Piano' , instrument : 'Piano' , durationMinutes : 30 , lessonFormat : 'private' , rateWeekly : '35.00' , rateMonthly : '120.00' , rateQuarterly : '330.00' } ,
{ name : '45-min Private Piano' , instrument : 'Piano' , durationMinutes : 45 , lessonFormat : 'private' , rateWeekly : '50.00' , rateMonthly : '175.00' , rateQuarterly : '480.00' } ,
{ name : '30-min Private Guitar' , instrument : 'Guitar' , durationMinutes : 30 , lessonFormat : 'private' , rateWeekly : '35.00' , rateMonthly : '120.00' , rateQuarterly : '330.00' } ,
{ name : '30-min Private Violin' , instrument : 'Violin' , durationMinutes : 30 , lessonFormat : 'private' , rateWeekly : '35.00' , rateMonthly : '120.00' , rateQuarterly : '330.00' } ,
{ name : '30-min Private Woodwind' , instrument : null , durationMinutes : 30 , lessonFormat : 'private' , rateWeekly : '35.00' , rateMonthly : '120.00' , rateQuarterly : '330.00' } ,
{ name : '45-min Group Guitar' , instrument : 'Guitar' , durationMinutes : 45 , lessonFormat : 'group' , rateWeekly : null , rateMonthly : '75.00' , rateQuarterly : '200.00' } ,
]
const ltIds : Record < string , string > = { }
for ( const lt of lessonTypeDefs ) {
const [ existing ] = await sql ` SELECT id FROM lesson_type WHERE name = ${ lt . name } `
if ( existing ) { ltIds [ lt . name ] = existing . id ; continue }
const [ row ] = await sql `
INSERT INTO lesson_type (name, instrument, duration_minutes, lesson_format, rate_weekly, rate_monthly, rate_quarterly, is_active)
VALUES ( ${ lt . name } , ${ lt . instrument } , ${ lt . durationMinutes } , ${ lt . lessonFormat } , ${ lt . rateWeekly } , ${ lt . rateMonthly } , ${ lt . rateQuarterly } , true)
RETURNING id `
ltIds [ lt . name ] = row . id
console . log ( ` Lesson type: ${ lt . name } ` )
}
// ── Schedule slots ─────────────────────────────────────────────────────────
// dayOfWeek: 0=Sun, 1=Mon, 2=Tue, 3=Wed, 4=Thu, 5=Fri, 6=Sat
const slotDefs = [
// Sarah Mitchell — Piano & Violin
{ key : 'sarah_mon_1530_piano30' , instructor : 'Sarah Mitchell' , lessonType : '30-min Private Piano' , dayOfWeek : 1 , startTime : '15:30' , room : 'Studio 1' , maxStudents : 1 , rateMonthly : null } ,
{ key : 'sarah_mon_1600_piano30' , instructor : 'Sarah Mitchell' , lessonType : '30-min Private Piano' , dayOfWeek : 1 , startTime : '16:00' , room : 'Studio 1' , maxStudents : 1 , rateMonthly : null } ,
{ key : 'sarah_mon_1700_piano45' , instructor : 'Sarah Mitchell' , lessonType : '45-min Private Piano' , dayOfWeek : 1 , startTime : '17:00' , room : 'Studio 1' , maxStudents : 1 , rateMonthly : null } ,
{ key : 'sarah_wed_1530_violin' , instructor : 'Sarah Mitchell' , lessonType : '30-min Private Violin' , dayOfWeek : 3 , startTime : '15:30' , room : 'Studio 1' , maxStudents : 1 , rateMonthly : null } ,
{ key : 'sarah_wed_1600_violin' , instructor : 'Sarah Mitchell' , lessonType : '30-min Private Violin' , dayOfWeek : 3 , startTime : '16:00' , room : 'Studio 1' , maxStudents : 1 , rateMonthly : null } ,
// Marcus Webb — Guitar (rate override: $115/mo, $400/qtr — slightly above default for experienced instructor)
{ key : 'marcus_tue_1500_guitar' , instructor : 'Marcus Webb' , lessonType : '30-min Private Guitar' , dayOfWeek : 2 , startTime : '15:00' , room : 'Studio 2' , maxStudents : 1 , rateMonthly : '115.00' } ,
{ key : 'marcus_tue_1600_guitar' , instructor : 'Marcus Webb' , lessonType : '30-min Private Guitar' , dayOfWeek : 2 , startTime : '16:00' , room : 'Studio 2' , maxStudents : 1 , rateMonthly : '115.00' } ,
{ key : 'marcus_thu_1600_group' , instructor : 'Marcus Webb' , lessonType : '45-min Group Guitar' , dayOfWeek : 4 , startTime : '16:00' , room : 'Studio 2' , maxStudents : 5 , rateMonthly : null } ,
{ key : 'marcus_sat_1000_guitar' , instructor : 'Marcus Webb' , lessonType : '30-min Private Guitar' , dayOfWeek : 6 , startTime : '10:00' , room : 'Studio 2' , maxStudents : 1 , rateMonthly : '115.00' } ,
// Diana Reyes — Woodwind
{ key : 'diana_mon_1630_woodwind' , instructor : 'Diana Reyes' , lessonType : '30-min Private Woodwind' , dayOfWeek : 1 , startTime : '16:30' , room : 'Studio 3' , maxStudents : 1 , rateMonthly : null } ,
{ key : 'diana_wed_1500_woodwind' , instructor : 'Diana Reyes' , lessonType : '30-min Private Woodwind' , dayOfWeek : 3 , startTime : '15:00' , room : 'Studio 3' , maxStudents : 1 , rateMonthly : null } ,
{ key : 'diana_fri_1600_woodwind' , instructor : 'Diana Reyes' , lessonType : '30-min Private Woodwind' , dayOfWeek : 5 , startTime : '16:00' , room : 'Studio 3' , maxStudents : 1 , rateMonthly : null } ,
]
const slotIds : Record < string , string > = { }
for ( const s of slotDefs ) {
const instrId = instrIds [ s . instructor ]
const ltId = ltIds [ s . lessonType ]
const [ existing ] = await sql `
SELECT id FROM schedule_slot
WHERE instructor_id = ${ instrId } AND day_of_week = ${ s . dayOfWeek } AND start_time = ${ s . startTime + ':00' } AND is_active = true `
if ( existing ) { slotIds [ s . key ] = existing . id ; continue }
const [ row ] = await sql `
INSERT INTO schedule_slot (instructor_id, lesson_type_id, day_of_week, start_time, room, max_students, rate_monthly, is_active)
VALUES ( ${ instrId } , ${ ltId } , ${ s . dayOfWeek } , ${ s . startTime } , ${ s . room } , ${ s . maxStudents } , ${ s . rateMonthly } , true)
RETURNING id `
slotIds [ s . key ] = row . id
console . log ( ` Slot: ${ s . instructor } — ${ s . lessonType } ( ${ [ 'Sun' , 'Mon' , 'Tue' , 'Wed' , 'Thu' , 'Fri' , 'Sat' ] [ s . dayOfWeek ] } ${ s . startTime } ) ` )
}
// ── Look up member IDs ─────────────────────────────────────────────────────
const memberRows = await sql ` SELECT m.id, m.first_name, m.last_name, m.account_id FROM member m `
const memberMap : Record < string , { id : string ; accountId : string } > = { }
for ( const m of memberRows ) memberMap [ ` ${ m . first_name } ${ m . last_name } ` ] = { id : m.id , accountId : m.account_id }
// ── Enrollments ────────────────────────────────────────────────────────────
// Each entry: member, slot key, start date (must match slot's day of week), rate, billingInterval, billingUnit
const enrollmentDefs = [
{
member : 'Tommy Smith' , slotKey : 'sarah_mon_1530_piano30' , startDate : '2026-01-05' ,
rate : '120.00' , billingInterval : 1 , billingUnit : 'month' ,
notes : 'Tommy is 8 years old, complete beginner. Parents prefer Monday after school.' ,
} ,
{
member : 'Jake Johnson' , slotKey : 'sarah_wed_1530_violin' , startDate : '2026-01-07' ,
rate : '120.00' , billingInterval : 1 , billingUnit : 'month' ,
notes : 'Jake (age 10) started Suzuki Book 1 last year at his school program.' ,
} ,
{
member : 'Emily Chen' , slotKey : 'marcus_tue_1500_guitar' , startDate : '2026-01-06' ,
rate : '115.00' , billingInterval : 1 , billingUnit : 'month' ,
notes : 'Emily plays some chords already — looking to improve technique and learn to read music.' ,
} ,
{
member : 'Mike Thompson' , slotKey : 'marcus_sat_1000_guitar' , startDate : '2026-02-07' ,
rate : '115.00' , billingInterval : 1 , billingUnit : 'month' ,
notes : 'Mike is an adult beginner. Prefers Saturday mornings.' ,
} ,
{
member : 'Carlos Garcia' , slotKey : 'diana_fri_1600_woodwind' , startDate : '2026-01-09' ,
rate : '120.00' , billingInterval : 1 , billingUnit : 'month' ,
notes : 'Carlos plays alto sax — returning student after a 2-year break.' ,
} ,
]
const enrollmentIds : Record < string , string > = { }
for ( const e of enrollmentDefs ) {
const m = memberMap [ e . member ]
if ( ! m ) { console . log ( ` ⚠ Member not found: ${ e . member } — skipping enrollment ` ) ; continue }
const slotId = slotIds [ e . slotKey ]
if ( ! slotId ) { console . log ( ` ⚠ Slot not found: ${ e . slotKey } — skipping enrollment ` ) ; continue }
const [ slot ] = await sql ` SELECT instructor_id FROM schedule_slot WHERE id = ${ slotId } `
const [ existing ] = await sql `
SELECT id FROM enrollment WHERE member_id = ${ m . id } AND schedule_slot_id = ${ slotId } `
if ( existing ) { enrollmentIds [ e . member ] = existing . id ; continue }
const [ row ] = await sql `
INSERT INTO enrollment (member_id, account_id, schedule_slot_id, instructor_id, status, start_date, rate, billing_interval, billing_unit, notes)
VALUES ( ${ m . id } , ${ m . accountId } , ${ slotId } , ${ slot . instructor_id } , 'active', ${ e . startDate } , ${ e . rate } , ${ e . billingInterval } , ${ e . billingUnit } , ${ e . notes } )
RETURNING id `
enrollmentIds [ e . member ] = row . id
console . log ( ` Enrollment: ${ e . member } ` )
}
// ── Lesson sessions ────────────────────────────────────────────────────────
// Generate past sessions (attended/missed) and a few upcoming (scheduled)
// Format: [date, status, instructorNotes?]
type SessionEntry = [ string , string , string ? ]
interface SessionSet {
enrollmentKey : string
slotKey : string
entries : SessionEntry [ ]
}
const today = '2026-03-30'
const sessionSets : SessionSet [ ] = [
{
enrollmentKey : 'Tommy Smith' ,
slotKey : 'sarah_mon_1530_piano30' ,
entries : [
// Past sessions — Monday 15:30
[ '2026-01-05' , 'attended' ] ,
[ '2026-01-12' , 'attended' ] ,
[ '2026-01-19' , 'attended' , 'Great progress on Clair de Lune beginner arrangement. Hand position improving.' ] ,
[ '2026-01-26' , 'missed' ] ,
[ '2026-02-02' , 'attended' ] ,
[ '2026-02-09' , 'attended' , 'Worked on legato technique. Introduced bass clef reading.' ] ,
[ '2026-02-16' , 'attended' ] ,
[ '2026-02-23' , 'attended' ] ,
[ '2026-03-02' , 'attended' , 'Tommy played "Ode to Joy" hands together for the first time — great milestone!' ] ,
[ '2026-03-09' , 'attended' ] ,
[ '2026-03-16' , 'attended' , 'Focusing on dynamics this month. Tommy responds well to storytelling analogies.' ] ,
[ '2026-03-23' , 'attended' ] ,
// Upcoming
[ '2026-03-30' , 'scheduled' ] ,
[ '2026-04-06' , 'scheduled' ] ,
[ '2026-04-13' , 'scheduled' ] ,
] ,
} ,
{
enrollmentKey : 'Jake Johnson' ,
slotKey : 'sarah_wed_1530_violin' ,
entries : [
[ '2026-01-07' , 'attended' ] ,
[ '2026-01-14' , 'attended' ] ,
[ '2026-01-21' , 'attended' , 'Jake shifted to Suzuki Book 1 Track 4. Bow hold still needs work.' ] ,
[ '2026-01-28' , 'attended' ] ,
[ '2026-02-04' , 'missed' ] ,
[ '2026-02-11' , 'attended' , 'Good session — bow hold much improved. Started Perpetual Motion.' ] ,
[ '2026-02-18' , 'attended' ] ,
[ '2026-02-25' , 'attended' ] ,
[ '2026-03-04' , 'attended' , 'Perpetual Motion up to speed. Introduced Allegretto.' ] ,
[ '2026-03-11' , 'attended' ] ,
[ '2026-03-18' , 'attended' , 'Jake performed Twinkle Variation A at slow tempo very cleanly.' ] ,
[ '2026-03-25' , 'attended' ] ,
[ '2026-04-01' , 'scheduled' ] ,
[ '2026-04-08' , 'scheduled' ] ,
[ '2026-04-15' , 'scheduled' ] ,
] ,
} ,
{
enrollmentKey : 'Emily Chen' ,
slotKey : 'marcus_tue_1500_guitar' ,
entries : [
[ '2026-01-06' , 'attended' ] ,
[ '2026-01-13' , 'attended' , 'Emily knows open chords (G, C, D, Em, Am). Introduced barre chords.' ] ,
[ '2026-01-20' , 'attended' ] ,
[ '2026-01-27' , 'attended' , 'F barre chord coming along. Introduced power chords and palm muting.' ] ,
[ '2026-02-03' , 'attended' ] ,
[ '2026-02-10' , 'attended' , 'Working through major scale patterns. Emily picks things up fast.' ] ,
[ '2026-02-17' , 'missed' ] ,
[ '2026-02-24' , 'attended' ] ,
[ '2026-03-03' , 'attended' , 'Started pentatonic minor scale. Playing along to simple backing track.' ] ,
[ '2026-03-10' , 'attended' ] ,
[ '2026-03-17' , 'attended' , 'Emily improvised a 4-bar phrase over a blues backing — sounded great!' ] ,
[ '2026-03-24' , 'attended' ] ,
[ '2026-03-31' , 'scheduled' ] ,
[ '2026-04-07' , 'scheduled' ] ,
[ '2026-04-14' , 'scheduled' ] ,
] ,
} ,
{
enrollmentKey : 'Mike Thompson' ,
slotKey : 'marcus_sat_1000_guitar' ,
entries : [
[ '2026-02-07' , 'attended' , 'First lesson — covered proper posture, right/left hand basics, and open E and A strings.' ] ,
[ '2026-02-14' , 'attended' ] ,
[ '2026-02-21' , 'attended' , 'Introduced G, C, Em chords. Switching between G and Em getting smoother.' ] ,
[ '2026-02-28' , 'attended' ] ,
[ '2026-03-07' , 'attended' , 'Added D chord. Working on "Knockin\' on Heaven\'s Door" intro pattern.' ] ,
[ '2026-03-14' , 'attended' ] ,
[ '2026-03-21' , 'attended' , 'Mike played the intro riff cleanly at tempo. Really motivated student.' ] ,
[ '2026-03-28' , 'attended' ] ,
[ '2026-04-04' , 'scheduled' ] ,
[ '2026-04-11' , 'scheduled' ] ,
[ '2026-04-18' , 'scheduled' ] ,
] ,
} ,
{
enrollmentKey : 'Carlos Garcia' ,
slotKey : 'diana_fri_1600_woodwind' ,
entries : [
[ '2026-01-09' , 'attended' , 'Assessment session — Carlos retained most of his fundamentals. Some embouchure drift after the break.' ] ,
[ '2026-01-16' , 'attended' ] ,
[ '2026-01-23' , 'attended' , 'Back up to speed on low register. Working on altissimo range.' ] ,
[ '2026-01-30' , 'attended' ] ,
[ '2026-02-06' , 'attended' , 'Started working through Charlie Parker\'s "Billie\'s Bounce" head at half tempo.' ] ,
[ '2026-02-13' , 'attended' ] ,
[ '2026-02-20' , 'attended' , 'Tone in the upper register sounding much stronger. Vibrato control improving.' ] ,
[ '2026-02-27' , 'attended' ] ,
[ '2026-03-06' , 'attended' , '"Billie\'s Bounce" head now solid at tempo. Moving to comping rhythms.' ] ,
[ '2026-03-13' , 'missed' ] ,
[ '2026-03-20' , 'attended' ] ,
[ '2026-03-27' , 'attended' , 'Carlos brought in his own transcription of a Cannonball Adderley lick — great initiative.' ] ,
[ '2026-04-03' , 'scheduled' ] ,
[ '2026-04-10' , 'scheduled' ] ,
[ '2026-04-17' , 'scheduled' ] ,
] ,
} ,
]
for ( const ss of sessionSets ) {
const enrollmentId = enrollmentIds [ ss . enrollmentKey ]
if ( ! enrollmentId ) continue
const [ slot ] = await sql ` SELECT start_time FROM schedule_slot WHERE id = ${ slotIds [ ss . slotKey ] } `
const scheduledTime = slot . start_time
for ( const [ date , status , instructorNotes ] of ss . entries ) {
const [ existing ] = await sql `
SELECT id FROM lesson_session WHERE enrollment_id = ${ enrollmentId } AND scheduled_date = ${ date } `
if ( existing ) continue
await sql `
INSERT INTO lesson_session (enrollment_id, scheduled_date, scheduled_time, status, instructor_notes, notes_completed_at)
VALUES (
${ enrollmentId } , ${ date } , ${ scheduledTime } , ${ status } ,
${ instructorNotes ? ? null } ,
${ instructorNotes && status !== 'scheduled' ? new Date ( date + 'T20:00:00Z' ) . toISOString ( ) : null }
) `
}
const count = ss . entries . length
console . log ( ` Sessions: ${ ss . enrollmentKey } ( ${ count } ) ` )
}
// ── Lesson plan template — Beginner Piano Fundamentals ─────────────────────
const [ existingTemplate ] = await sql ` SELECT id FROM lesson_plan_template WHERE name = 'Beginner Piano Fundamentals' `
if ( ! existingTemplate ) {
const [ tmpl ] = await sql `
INSERT INTO lesson_plan_template (name, description, instrument, skill_level, is_active)
VALUES (
'Beginner Piano Fundamentals',
'Core skills for students in their first year of piano study — from posture and note reading through first hands-together pieces.',
'Piano', 'beginner', true
) RETURNING id `
const sections = [
{
title : 'Posture & Hand Position' ,
sortOrder : 0 ,
items : [
{ title : 'Bench height and sitting posture' , sortOrder : 0 } ,
{ title : 'Hand arch and curved fingers' , sortOrder : 1 } ,
{ title : 'Finger numbering (1– 5)' , sortOrder : 2 } ,
{ title : 'Relaxed wrists and forearms' , sortOrder : 3 } ,
] ,
} ,
{
title : 'Reading Music' ,
sortOrder : 1 ,
items : [
{ title : 'Treble clef note names (C4– G5)' , sortOrder : 0 } ,
{ title : 'Bass clef note names (C3– G4)' , sortOrder : 1 } ,
{ title : 'Note values: whole, half, quarter' , sortOrder : 2 } ,
{ title : 'Time signatures: 4/4 and 3/4' , sortOrder : 3 } ,
{ title : 'Bar lines and repeats' , sortOrder : 4 } ,
] ,
} ,
{
title : 'Keyboard Geography' ,
sortOrder : 2 ,
items : [
{ title : 'All white key names across full keyboard' , sortOrder : 0 } ,
{ title : 'Black key groups (2s and 3s)' , sortOrder : 1 } ,
{ title : 'Middle C and octave identification' , sortOrder : 2 } ,
] ,
} ,
{
title : 'First Pieces' ,
sortOrder : 3 ,
items : [
{ title : 'Five-finger melody (right hand only)' , sortOrder : 0 } ,
{ title : 'Simple left hand accompaniment' , sortOrder : 1 } ,
{ title : 'Hands together at slow tempo' , sortOrder : 2 } ,
{ title : 'Mary Had a Little Lamb' , sortOrder : 3 } ,
{ title : 'Ode to Joy (Beethoven)' , sortOrder : 4 } ,
{ title : 'Merrily We Roll Along' , sortOrder : 5 } ,
] ,
} ,
]
for ( const sec of sections ) {
const [ s ] = await sql `
INSERT INTO lesson_plan_template_section (template_id, title, sort_order)
VALUES ( ${ tmpl . id } , ${ sec . title } , ${ sec . sortOrder } )
RETURNING id `
for ( const item of sec . items ) {
await sql `
INSERT INTO lesson_plan_template_item (section_id, title, grading_scale_id, sort_order)
VALUES ( ${ s . id } , ${ item . title } , ${ scaleId } , ${ item . sortOrder } ) `
}
}
console . log ( ' Template: Beginner Piano Fundamentals' )
}
// ── Lesson plan for Tommy Smith ────────────────────────────────────────────
const tommyEnrollmentId = enrollmentIds [ 'Tommy Smith' ]
const tommyMember = memberMap [ 'Tommy Smith' ]
if ( tommyEnrollmentId && tommyMember ) {
const [ existingPlan ] = await sql ` SELECT id FROM member_lesson_plan WHERE enrollment_id = ${ tommyEnrollmentId } AND is_active = true `
if ( ! existingPlan ) {
const [ plan ] = await sql `
INSERT INTO member_lesson_plan (member_id, enrollment_id, title, description, is_active, started_date)
VALUES ( ${ tommyMember . id } , ${ tommyEnrollmentId } , 'Piano Fundamentals — Tommy Smith', 'Working through first-year piano curriculum.', true, '2026-01-05')
RETURNING id `
// Section 1 — Posture: all mastered
const [ sec1 ] = await sql `
INSERT INTO lesson_plan_section (lesson_plan_id, title, sort_order)
VALUES ( ${ plan . id } , 'Posture & Hand Position', 0) RETURNING id `
const posturItems = [
{ title : 'Bench height and sitting posture' , status : 'mastered' , sortOrder : 0 } ,
{ title : 'Hand arch and curved fingers' , status : 'mastered' , sortOrder : 1 } ,
{ title : 'Finger numbering (1– 5)' , status : 'mastered' , sortOrder : 2 } ,
{ title : 'Relaxed wrists and forearms' , status : 'in_progress' , sortOrder : 3 } ,
]
for ( const it of posturItems ) {
await sql ` INSERT INTO lesson_plan_item (section_id, title, status, grading_scale_id, current_grade_value, sort_order)
VALUES ( ${ sec1 . id } , ${ it . title } , ${ it . status } , ${ scaleId } , ${ it . status === 'mastered' ? '4' : it . status === 'in_progress' ? '2' : null } , ${ it . sortOrder } ) `
}
// Section 2 — Reading Music: in progress
const [ sec2 ] = await sql `
INSERT INTO lesson_plan_section (lesson_plan_id, title, sort_order)
VALUES ( ${ plan . id } , 'Reading Music', 1) RETURNING id `
const readingItems = [
{ title : 'Treble clef note names (C4– G5)' , status : 'mastered' , sortOrder : 0 } ,
{ title : 'Bass clef note names (C3– G4)' , status : 'in_progress' , sortOrder : 1 } ,
{ title : 'Note values: whole, half, quarter' , status : 'mastered' , sortOrder : 2 } ,
{ title : 'Time signatures: 4/4 and 3/4' , status : 'in_progress' , sortOrder : 3 } ,
{ title : 'Bar lines and repeats' , status : 'not_started' , sortOrder : 4 } ,
]
for ( const it of readingItems ) {
await sql ` INSERT INTO lesson_plan_item (section_id, title, status, grading_scale_id, current_grade_value, sort_order)
VALUES ( ${ sec2 . id } , ${ it . title } , ${ it . status } , ${ scaleId } , ${ it . status === 'mastered' ? '4' : it . status === 'in_progress' ? '2' : null } , ${ it . sortOrder } ) `
}
// Section 3 — First Pieces: mix of complete and in progress
const [ sec3 ] = await sql `
INSERT INTO lesson_plan_section (lesson_plan_id, title, sort_order)
VALUES ( ${ plan . id } , 'First Pieces', 2) RETURNING id `
const pieceItems = [
{ title : 'Five-finger melody (right hand only)' , status : 'mastered' , sortOrder : 0 } ,
{ title : 'Simple left hand accompaniment' , status : 'mastered' , sortOrder : 1 } ,
{ title : 'Hands together at slow tempo' , status : 'in_progress' , sortOrder : 2 } ,
{ title : 'Mary Had a Little Lamb' , status : 'mastered' , sortOrder : 3 } ,
{ title : 'Ode to Joy (Beethoven)' , status : 'in_progress' , sortOrder : 4 } ,
{ title : 'Merrily We Roll Along' , status : 'not_started' , sortOrder : 5 } ,
]
for ( const it of pieceItems ) {
await sql ` INSERT INTO lesson_plan_item (section_id, title, status, grading_scale_id, current_grade_value, sort_order)
VALUES ( ${ sec3 . id } , ${ it . title } , ${ it . status } , ${ scaleId } , ${ it . status === 'mastered' ? '4' : it . status === 'in_progress' ? '2' : null } , ${ it . sortOrder } ) `
}
console . log ( ' Lesson plan: Tommy Smith — Piano Fundamentals' )
}
}
console . log ( 'Lessons seed complete.' )
}
seed ( ) . catch ( ( err ) = > {
console . error ( 'Seed failed:' , err )
process . exit ( 1 )