diff --git a/backend/scripts/bisaya-course-phase4-extension.js b/backend/scripts/bisaya-course-phase4-extension.js index b263c0b..c0b88b7 100644 --- a/backend/scripts/bisaya-course-phase4-extension.js +++ b/backend/scripts/bisaya-course-phase4-extension.js @@ -3,14 +3,36 @@ export const BISAYA_PHASE4_DIDACTICS = { learningGoals: [ 'Über Kinder im Familienalltag sprechen.', 'Einfache Fragen zu Hunger, Müdigkeit und Schule stellen.', - 'Kurze Fürsorge-Dialoge mit Kindern laut üben.' + 'Kurze Fürsorge-Dialoge mit Kindern laut üben.', + 'Kinderroutinen mit kurzen Handlungsaufforderungen strukturieren.' + ], + corePatterns: [ + { target: 'Nikaon na ka?', gloss: 'Hast du schon gegessen?' }, + { target: 'Kapoy na ka?', gloss: 'Bist du schon müde?' }, + { target: 'Andam na ka sa eskwela?', gloss: 'Bist du bereit für die Schule?' }, + { target: 'Asa ang bata?', gloss: 'Wo ist das Kind?' }, + { target: 'Ali diri.', gloss: 'Komm her.' }, + { target: 'Ayaw pagdali.', gloss: 'Kein Stress / Beeil dich nicht.' }, + { target: 'Kuhaa imong bag.', gloss: 'Hol deine Tasche.' }, + { target: 'Hugas sa kamot.', gloss: 'Wasch dir die Hände.' }, + { target: 'Matulog na ta.', gloss: 'Lass uns schlafen gehen.' } ], - corePatterns: ['Nikaon na ang bata?', 'Asa ang bata?', 'Kapoy na ka?', 'Andam na ka sa eskwela?'], speakingPrompts: [ { title: 'Mit Kind sprechen', prompt: 'Frage ein Kind nach Essen, Müdigkeit und Schule.', cue: 'Nikaon na ka? Kapoy na ka?' + }, + { + title: 'Morgen mit Kind', + prompt: 'Baue eine kurze Morgenroutine mit Tasche und Losgehen.', + cue: 'Ali diri. Kuhaa imong bag. Andam na ka sa eskwela?' + } + ], + practicalTasks: [ + { + title: 'Routine in 5 Saetzen', + text: 'Sprich eine Routine mit fuenf kurzen Saetzen (Essen, Tasche, Haende, Schule, Losgehen).' } ] }, @@ -20,7 +42,30 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Über Tasche, Hefte, Lehrkraft und Unterricht sprechen.', 'Kinder- und Schulwortschatz mit Familienalltag verbinden.' ], - corePatterns: ['eskwela', 'maestra', 'bag', 'leksyon'] + corePatterns: [ + { target: 'eskwela', gloss: 'Schule' }, + { target: 'maestra', gloss: 'Lehrerin' }, + { target: 'maestro', gloss: 'Lehrer' }, + { target: 'bag', gloss: 'Tasche' }, + { target: 'leksyon', gloss: 'Lektion / Unterricht' }, + { target: 'assignment', gloss: 'Hausaufgabe' }, + { target: 'libro', gloss: 'Buch' }, + { target: 'lapis', gloss: 'Stift' }, + { target: 'Asa imong bag?', gloss: 'Wo ist deine Tasche?' } + ], + speakingPrompts: [ + { + title: 'Schulsachen', + prompt: 'Frage nach Tasche und Buch und sage, dass Schule gleich losgeht.', + cue: 'Asa imong bag? Asa ang libro? Andam na ta sa eskwela.' + } + ], + practicalTasks: [ + { + title: 'Zeige und sage', + text: 'Nenne vier Schulsachen und bilde je einen kurzen Satz oder eine Frage dazu.' + } + ] }, 'Fragen an Kinder vereinfachen': { learningGoals: [ @@ -28,13 +73,35 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Aufforderungen und Fragen freundlich unterscheiden.', 'Kindgerechte Alltagsmuster wiederholt anwenden.' ], - corePatterns: ['Unsa ni?', 'Asa imong bag?', 'Andam na ka?', 'Ali diri.'], + corePatterns: [ + { target: 'Unsa ni?', gloss: 'Was ist das?' }, + { target: 'Asa ni?', gloss: 'Wo ist das?' }, + { target: 'Kinsa ni?', gloss: 'Wer ist das?' }, + { target: 'Asa imong bag?', gloss: 'Wo ist deine Tasche?' }, + { target: 'Andam na ka?', gloss: 'Bist du fertig?' }, + { target: 'Ganahan ka?', gloss: 'Moechtest du?' }, + { target: 'Ali diri.', gloss: 'Komm her.' }, + { target: 'Ayaw.', gloss: 'Nicht (tu das nicht).' } + ], grammarFocus: [ { title: 'Kurze Fragen', text: 'Mit Kindern funktionieren kurze, klare Fragen oft besser als lange Sätze.', example: 'Asa imong bag? Andam na ka?' } + ], + speakingPrompts: [ + { + title: 'Vier Kurzfragen', + prompt: 'Stelle vier kurze Kinderfragen hintereinander.', + cue: 'Unsa ni? Asa ni? Andam na ka? Asa imong bag?' + } + ], + practicalTasks: [ + { + title: 'Frage oder Aufforderung', + text: 'Forme drei deutsche Saetze einmal als Frage und einmal als kurze Aufforderung auf Bisaya.' + } ] }, 'Hausaufgaben & Routine': { @@ -43,7 +110,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Einfachen Tagesablauf mit Schule und Zuhause verbinden.', 'Kurze Organisationsgespräche führen.' ], - corePatterns: ['Naa kay assignment?', 'Human na ka?', 'Magtuon ta.', 'Sunod, matulog na.'] + corePatterns: [ + { target: 'Naa kay assignment?', gloss: 'Hast du Hausaufgaben?' }, + { target: 'Human na ka?', gloss: 'Bist du fertig?' }, + { target: 'Wala pa ko nahuman.', gloss: 'Ich bin noch nicht fertig.' }, + { target: 'Magtuon ta.', gloss: 'Lass uns lernen.' }, + { target: 'Sunod, matulog na ta.', gloss: 'Danach gehen wir schlafen.' }, + { target: 'Ayaw sa ug dula.', gloss: 'Spiel erst mal nicht.' }, + { target: 'Pagkahuman, magdula ta.', gloss: 'Danach spielen wir.' }, + { target: 'Tabangi ko, palihug.', gloss: 'Hilf mir bitte.' } + ], + speakingPrompts: [ + { + title: 'Hausaufgaben-Dialog', + prompt: 'Frage nach Hausaufgaben, ob das Kind fertig ist, und mache eine Routineansage.', + cue: 'Naa kay assignment? Human na ka? Sunod, matulog na ta.' + } + ], + practicalTasks: [ + { + title: 'Routinekette', + text: 'Sprich eine Kette mit Lernen, Aufgabe, Hilfe, Spielen und Schlafen.' + } + ] }, 'Woche 7 - Intensivwiederholung I': { learningGoals: [ @@ -51,7 +140,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Frühere Fürsorgeformen mit Schulalltag verbinden.', 'Schneller zwischen Themen wechseln.' ], - corePatterns: ['Nikaon na ka?', 'Asa ang bata?', 'Magtuon ta.', 'Palihug lingkod.'] + corePatterns: [ + { target: 'Nikaon na ka?', gloss: 'Hast du schon gegessen?' }, + { target: 'Asa ang bata?', gloss: 'Wo ist das Kind?' }, + { target: 'Andam na ka?', gloss: 'Bist du fertig?' }, + { target: 'Asa imong bag?', gloss: 'Wo ist deine Tasche?' }, + { target: 'Magtuon ta.', gloss: 'Lass uns lernen.' }, + { target: 'Hugas sa kamot.', gloss: 'Wasch dir die Haende.' }, + { target: 'Pagkahuman, magdula ta.', gloss: 'Danach spielen wir.' }, + { target: 'Sunod, matulog na ta.', gloss: 'Danach gehen wir schlafen.' } + ], + speakingPrompts: [ + { + title: 'Schnelle Rollenwechsel', + prompt: 'Wechsle zwischen Betreuung, Schule und Routine in kurzen Antworten.', + cue: 'Asa imong bag? Andam na ka? Magtuon ta. Sunod, matulog na ta.' + } + ], + practicalTasks: [ + { + title: '8 Situationen', + text: 'Beantworte acht Situationen: Hunger, Tasche, Haende, Hausaufgaben, Spielen, Schlafen.' + } + ] }, 'Spiralwiederholung - Familie, Kinder & Fürsorge': { learningGoals: [ @@ -59,7 +170,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Bekannte Kernwörter schneller abrufen.', 'Alte Inhalte in neuen Situationen festigen.' ], - corePatterns: ['Nanay', 'Tatay', 'bata', 'eskwela'] + corePatterns: [ + { target: 'Nanay', gloss: 'Mutter' }, + { target: 'Tatay', gloss: 'Vater' }, + { target: 'bata', gloss: 'Kind' }, + { target: 'pamilya', gloss: 'Familie' }, + { target: 'eskwela', gloss: 'Schule' }, + { target: 'tabang', gloss: 'Hilfe' }, + { target: 'Kapoy na ka?', gloss: 'Bist du muede?' }, + { target: 'Ayaw kabalaka.', gloss: 'Mach dir keine Sorgen.' } + ], + speakingPrompts: [ + { + title: 'Familien-Fuersorge', + prompt: 'Sprich zwei kurze Fuersorgesetze zu Kind und Schule.', + cue: 'Ayaw kabalaka. Andam na ka sa eskwela?' + } + ], + practicalTasks: [ + { + title: 'Spiralabruf', + text: 'Nimm vier alte Woerter (Nanay/Tatay/bata/eskwela) und baue vier kurze Saetze.' + } + ] }, 'Spielen & Freizeit': { learningGoals: [ @@ -67,7 +200,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Kinder zu Spiel und Pause begleiten.', 'Leichte Alltagsdialoge mit Bewegung verbinden.' ], - corePatterns: ['Magdula ta.', 'Ganahan ka modula?', 'Lingaw ka?', 'Human na ang duwa.'] + corePatterns: [ + { target: 'Magdula ta.', gloss: 'Lass uns spielen.' }, + { target: 'Ganahan ka modula?', gloss: 'Moechtest du spielen?' }, + { target: 'Lingaw ka?', gloss: 'Hast du Spass?' }, + { target: 'Human na ang duwa.', gloss: 'Das Spiel ist vorbei.' }, + { target: 'Pahuway sa.', gloss: 'Mach erst mal Pause.' }, + { target: 'Dali na.', gloss: 'Komm, beeil dich.' }, + { target: 'Ayaw pag-away.', gloss: 'Streitet nicht.' }, + { target: 'Pag-ampo sa.', gloss: 'Bete erst mal.' } + ], + speakingPrompts: [ + { + title: 'Freizeit mit Regeln', + prompt: 'Biete Spiel an, mache eine Pauseansage und stoppe Streit freundlich.', + cue: 'Magdula ta. Pahuway sa. Ayaw pag-away.' + } + ], + practicalTasks: [ + { + title: '3 Mini-Dialoge', + text: 'Sprich drei Mini-Dialoge: anfangen, stoppen, Pause.' + } + ] }, 'Spielsachen & Aktivitäten': { learningGoals: [ @@ -75,7 +230,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Aktivitäten benennen und vergleichen.', 'Kinderalltag mit neuen Nomen anreichern.' ], - corePatterns: ['duwa', 'bola', 'libro', 'kanta'] + corePatterns: [ + { target: 'duwa', gloss: 'Spiel' }, + { target: 'bola', gloss: 'Ball' }, + { target: 'libro', gloss: 'Buch' }, + { target: 'kanta', gloss: 'Lied' }, + { target: 'sayaw', gloss: 'Tanz' }, + { target: 'drawing', gloss: 'Malen/Zeichnen' }, + { target: 'Ganahan ka ani?', gloss: 'Magst du das?' }, + { target: 'Pilia.', gloss: 'Waehle.' } + ], + speakingPrompts: [ + { + title: 'Auswahl anbieten', + prompt: 'Biete zwei Aktivitaeten an und lasse das Kind waehlen.', + cue: 'Ganahan ka og kanta o sayaw? Pilia.' + } + ], + practicalTasks: [ + { + title: 'Wortschatz aktiv', + text: 'Nenne sechs Spielsachen/Aktivitaeten und bilde zwei kurze Fragen dazu.' + } + ] }, 'Woche 7 - Intensivwiederholung II': { learningGoals: [ @@ -83,7 +260,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Schwierige Formen gezielt wiederholen.', 'Mehr Sicherheit in Alltagsszenen mit Kindern gewinnen.' ], - corePatterns: ['Andam na ka?', 'Magdula ta.', 'Human na ka?', 'Asa imong bag?'] + corePatterns: [ + { target: 'Andam na ka?', gloss: 'Bist du fertig?' }, + { target: 'Asa imong bag?', gloss: 'Wo ist deine Tasche?' }, + { target: 'Magdula ta.', gloss: 'Lass uns spielen.' }, + { target: 'Human na ka?', gloss: 'Bist du fertig?' }, + { target: 'Naa kay assignment?', gloss: 'Hast du Hausaufgaben?' }, + { target: 'Hugas sa kamot.', gloss: 'Wasch dir die Haende.' }, + { target: 'Ayaw pagdali.', gloss: 'Kein Stress.' }, + { target: 'Sunod, matulog na ta.', gloss: 'Danach schlafen wir.' } + ], + speakingPrompts: [ + { + title: 'Mischszene', + prompt: 'Baue eine Szene aus Schule, Hausaufgaben, Spiel und Schlaf.', + cue: 'Andam na ka sa eskwela? Naa kay assignment? Pagkahuman, magdula ta. Sunod, matulog na ta.' + } + ], + practicalTasks: [ + { + title: 'Tempo', + text: 'Sag acht Saetze laut und schnell (aber klar), ohne zu stolpern.' + } + ] }, 'Woche 7 - Checkpoint': { learningGoals: [ @@ -91,7 +290,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Abruf und Anwendung im Familienalltag testen.', 'Lücken vor Woche 8 sichtbar machen.' ], - corePatterns: ['eskwela', 'assignment', 'bata', 'magdula'] + corePatterns: [ + { target: 'eskwela', gloss: 'Schule' }, + { target: 'assignment', gloss: 'Hausaufgabe' }, + { target: 'bata', gloss: 'Kind' }, + { target: 'magdula', gloss: 'spielen' }, + { target: 'Andam na ka?', gloss: 'Bist du fertig?' }, + { target: 'Asa imong bag?', gloss: 'Wo ist deine Tasche?' }, + { target: 'Magtuon ta.', gloss: 'Lass uns lernen.' }, + { target: 'Sunod, matulog na ta.', gloss: 'Danach schlafen wir.' } + ], + speakingPrompts: [ + { + title: 'Checkpoint-Szene', + prompt: 'Loese eine kurze Szene: Schule, Tasche, Hausaufgabe, Routine.', + cue: 'Asa imong bag? Andam na ka sa eskwela? Naa kay assignment? Sunod, matulog na ta.' + } + ], + practicalTasks: [ + { + title: 'Diagnose', + text: 'Markiere die Saetze, die nicht sofort kamen, und wiederhole sie dreimal im Typing.' + } + ] }, 'Arzt & Termin': { learningGoals: [ @@ -99,7 +320,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Über Beschwerden, Termin und Wartezeit sprechen.', 'Einfache Gesundheitsgespräche strukturieren.' ], - corePatterns: ['Adto ta sa doktor.', 'Naa moy appointment?', 'Unsay gibati nimo?', 'Maghulat ta.'] + corePatterns: [ + { target: 'Adto ta sa doktor.', gloss: 'Wir gehen zum Arzt.' }, + { target: 'Naa mi appointment.', gloss: 'Wir haben einen Termin.' }, + { target: 'Naa moy appointment?', gloss: 'Haben Sie einen Termin?' }, + { target: 'Unsay gibati nimo?', gloss: 'Was fuehlst du / was hast du?' }, + { target: 'Sakit diri.', gloss: 'Es tut hier weh.' }, + { target: 'Pila ka oras ang hulat?', gloss: 'Wie lange ist die Wartezeit?' }, + { target: 'Maghulat ta.', gloss: 'Wir warten.' }, + { target: 'Palihug tabang.', gloss: 'Bitte helfen.' } + ], + speakingPrompts: [ + { + title: 'Arzttermin', + prompt: 'Sage, dass ihr zum Arzt geht, ihr einen Termin habt und frage nach Wartezeit.', + cue: 'Adto ta sa doktor. Naa mi appointment. Pila ka oras ang hulat?' + } + ], + practicalTasks: [ + { + title: '3 Fragen', + text: 'Uebe drei Fragen fuer den Arztbesuch: Termin, Beschwerden, Wartezeit.' + } + ] }, 'Apotheke & Medikamente': { learningGoals: [ @@ -107,7 +350,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Zwischen Medikament, Rezept und Dosierung unterscheiden.', 'Gesundheitswortschatz in Erledigungen einordnen.' ], - corePatterns: ['tambal', 'botika', 'reseta', 'dose'] + corePatterns: [ + { target: 'botika', gloss: 'Apotheke' }, + { target: 'tambal', gloss: 'Medizin' }, + { target: 'reseta', gloss: 'Rezept' }, + { target: 'dose', gloss: 'Dosis' }, + { target: 'Pila ang dose?', gloss: 'Wie ist die Dosierung?' }, + { target: 'Pila ka adlaw?', gloss: 'Wie viele Tage?' }, + { target: 'Naa moy tambal ani?', gloss: 'Haben Sie Medizin dafuer?' }, + { target: 'Unsaon pag-inom?', gloss: 'Wie nimmt man das ein?' } + ], + speakingPrompts: [ + { + title: 'In der Apotheke', + prompt: 'Frage nach Medizin, Rezept und Dosierung.', + cue: 'Naa moy tambal ani? Naa koy reseta. Unsaon pag-inom?' + } + ], + practicalTasks: [ + { + title: 'Etikett lesen', + text: 'Sag laut: Dosis, Tage, wie einnehmen, und wiederhole es in eigenen Worten.' + } + ] }, 'Beschwerden genauer beschreiben': { learningGoals: [ @@ -115,13 +380,35 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Zwischen leicht, stark und wiederkehrend unterscheiden.', 'Fragen und Antworten zu Schmerzen vertiefen.' ], - corePatterns: ['Sakit kaayo.', 'Gamaya ra ang sakit.', 'Nagsugod ganiha.', 'Mas maayo na karon.'], + corePatterns: [ + { target: 'Sakit kaayo.', gloss: 'Es tut sehr weh.' }, + { target: 'Gamaya ra ang sakit.', gloss: 'Der Schmerz ist nur leicht.' }, + { target: 'Sakit pa?', gloss: 'Tut es noch weh?' }, + { target: 'Nagsugod ganiha.', gloss: 'Es hat vorhin angefangen.' }, + { target: 'Balik-balik.', gloss: 'Es kommt immer wieder.' }, + { target: 'Mas maayo na karon.', gloss: 'Es ist jetzt besser.' }, + { target: 'Naa koy hilanat.', gloss: 'Ich habe Fieber.' }, + { target: 'Ubo ko.', gloss: 'Ich habe Husten.' } + ], grammarFocus: [ { title: 'Beschwerden abstufen', text: 'Im Alltag helfen kurze Verstärker und Zeitangaben, um Schmerzen genauer zu beschreiben.', example: 'Sakit kaayo. Nagsugod ganiha.' } + ], + speakingPrompts: [ + { + title: 'Verlauf beschreiben', + prompt: 'Sag, wie stark es ist, wann es anfing und ob es besser wird.', + cue: 'Gamaya ra ang sakit. Nagsugod ganiha. Mas maayo na karon.' + } + ], + practicalTasks: [ + { + title: '3 Varianten', + text: 'Bilde drei Varianten derselben Beschwerde: leicht, stark, wiederkehrend.' + } ] }, 'Notfälle & Hilfe': { @@ -130,7 +417,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Klare, kurze Anweisungen geben.', 'Grundmuster für schnelle Reaktion beherrschen.' ], - corePatterns: ['Tabang!', 'Tawag ug doktor.', 'Dali lang.', 'Asa ang tambal?'] + corePatterns: [ + { target: 'Tabang!', gloss: 'Hilfe!' }, + { target: 'Dali lang!', gloss: 'Schnell!' }, + { target: 'Tawag ug doktor.', gloss: 'Ruf einen Arzt.' }, + { target: 'Tawag ug ambulansya.', gloss: 'Ruf einen Krankenwagen.' }, + { target: 'Asa ang tambal?', gloss: 'Wo ist die Medizin?' }, + { target: 'Palihug tabang.', gloss: 'Bitte helfen.' }, + { target: 'Dili ko ginhawa.', gloss: 'Ich bekomme keine Luft.' }, + { target: 'Magpabilin diri.', gloss: 'Bleib hier.' } + ], + speakingPrompts: [ + { + title: 'Notfallansage', + prompt: 'Rufe Hilfe und gib eine kurze Anweisung.', + cue: 'Tabang! Tawag ug doktor. Dali lang!' + } + ], + practicalTasks: [ + { + title: 'Notfallanker', + text: 'Uebe vier Notfallsaetze, bis sie ohne Lesen kommen.' + } + ] }, 'Woche 8 - Intensivwiederholung I': { learningGoals: [ @@ -138,7 +447,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Beschwerden schneller abrufen und zuordnen.', 'Gesundheitskommunikation stabilisieren.' ], - corePatterns: ['doktor', 'tambal', 'tabang', 'sakit kaayo'] + corePatterns: [ + { target: 'Adto ta sa doktor.', gloss: 'Wir gehen zum Arzt.' }, + { target: 'Naa mi appointment.', gloss: 'Wir haben einen Termin.' }, + { target: 'Naa moy tambal ani?', gloss: 'Haben Sie Medizin dafuer?' }, + { target: 'Unsaon pag-inom?', gloss: 'Wie nimmt man das ein?' }, + { target: 'Sakit kaayo.', gloss: 'Es tut sehr weh.' }, + { target: 'Nagsugod ganiha.', gloss: 'Es fing vorhin an.' }, + { target: 'Tabang!', gloss: 'Hilfe!' }, + { target: 'Tawag ug doktor.', gloss: 'Ruf einen Arzt.' } + ], + speakingPrompts: [ + { + title: 'Mischszene Gesundheit', + prompt: 'Verbinde Arzttermin, Apotheke und Hilfe in einer Szene.', + cue: 'Adto ta sa doktor. Naa mi appointment. Naa moy tambal ani? Tabang!' + } + ], + practicalTasks: [ + { + title: 'Tempo-Mix', + text: 'Sag acht Saetze schnell hintereinander, ohne zu stolpern.' + } + ] }, 'Spiralwiederholung - Gesundheit': { learningGoals: [ @@ -146,7 +477,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Bekannte Wörter in neuen Gesundheitsdialogen wiederholen.', 'Gesundheitswortschatz langfristig verankern.' ], - corePatterns: ['Nikaon na ka?', 'Magpahuway sa.', 'doktor', 'tambal'] + corePatterns: [ + { target: 'Magpahuway sa.', gloss: 'Ruh dich erst mal aus.' }, + { target: 'Uminom og tubig.', gloss: 'Trink Wasser.' }, + { target: 'Niinom ka og tambal?', gloss: 'Hast du Medizin genommen?' }, + { target: 'Mas maayo na ka?', gloss: 'Geht es dir besser?' }, + { target: 'doktor', gloss: 'Arzt' }, + { target: 'tambal', gloss: 'Medizin' }, + { target: 'Sakit pa?', gloss: 'Tut es noch weh?' }, + { target: 'Ayaw kabalaka.', gloss: 'Mach dir keine Sorgen.' } + ], + speakingPrompts: [ + { + title: 'Fuersorgefolge', + prompt: 'Reagiere mit drei Fuersorgesatzen auf eine Beschwerde.', + cue: 'Ayaw kabalaka. Magpahuway sa. Uminom og tubig.' + } + ], + practicalTasks: [ + { + title: 'Problem -> Antwort', + text: 'Bilde fuenf Paare aus Problem und Antwort (z.B. sakit -> magpahuway).' + } + ] }, 'Essen, Ruhe & Genesung': { learningGoals: [ @@ -154,7 +507,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Kurze Pflegegespräche im Familienalltag führen.', 'Fürsorge und Gesundheit verbinden.' ], - corePatterns: ['Magpahuway sa.', 'Mokaon sa ka.', 'Uminom og tubig.', 'Mas maayo na ka?'] + corePatterns: [ + { target: 'Magpahuway sa.', gloss: 'Ruh dich erst mal aus.' }, + { target: 'Mokaon sa ka.', gloss: 'Iss erst einmal.' }, + { target: 'Uminom og tubig.', gloss: 'Trink Wasser.' }, + { target: 'Inom sa og tambal.', gloss: 'Nimm erst mal Medizin.' }, + { target: 'Mas maayo na ka?', gloss: 'Geht es dir besser?' }, + { target: 'Dili sa daghan.', gloss: 'Nicht zu viel.' }, + { target: 'Katulog og maayo.', gloss: 'Schlaf gut.' }, + { target: 'Naa ra ko diri.', gloss: 'Ich bin hier.' } + ], + speakingPrompts: [ + { + title: 'Pflegegespraech', + prompt: 'Biete Essen, Wasser, Ruhe an und frage nach Besserung.', + cue: 'Mokaon sa ka. Uminom og tubig. Magpahuway sa. Mas maayo na ka?' + } + ], + practicalTasks: [ + { + title: 'Pflegekette', + text: 'Sprich eine Pflegekette mit mindestens fuenf kurzen Saetzen.' + } + ] }, 'Körper, Symptome & Pflege': { learningGoals: [ @@ -162,7 +537,30 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Zwischen Ort und Art einer Beschwerde unterscheiden.', 'Pflegealltag mit konkreterem Wortschatz stützen.' ], - corePatterns: ['ulo', 'tiyan', 'hilanat', 'alaga'] + corePatterns: [ + { target: 'ulo', gloss: 'Kopf' }, + { target: 'tiyan', gloss: 'Bauch' }, + { target: 'likod', gloss: 'Ruecken' }, + { target: 'tutunlan', gloss: 'Hals' }, + { target: 'hilanat', gloss: 'Fieber' }, + { target: 'ubo', gloss: 'Husten' }, + { target: 'alaga', gloss: 'Pflege' }, + { target: 'doktor', gloss: 'Arzt' }, + { target: 'Sakit akong tutunlan.', gloss: 'Mein Hals tut weh.' } + ], + speakingPrompts: [ + { + title: 'Koerper + Schmerz', + prompt: 'Sage drei Saetze: wo es weh tut und was du brauchst.', + cue: 'Sakit akong ulo. Sakit akong tiyan. Asa ang tambal?' + } + ], + practicalTasks: [ + { + title: 'Koerperrunde', + text: 'Nenne vier Koerperteile und bilde zu jedem einen kurzen Satz mit sakit.' + } + ] }, 'Woche 8 - Intensivwiederholung II': { learningGoals: [ @@ -170,7 +568,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Fragen, Antworten und Reaktionen zügig abrufen.', 'Vor dem Wochenabschluss Sicherheit erhöhen.' ], - corePatterns: ['Mas maayo na ka?', 'Adto ta sa doktor.', 'Uminom og tubig.', 'Tabang!'] + corePatterns: [ + { target: 'Mas maayo na ka?', gloss: 'Geht es dir besser?' }, + { target: 'Adto ta sa doktor.', gloss: 'Wir gehen zum Arzt.' }, + { target: 'Naa moy appointment?', gloss: 'Haben Sie einen Termin?' }, + { target: 'Unsaon pag-inom?', gloss: 'Wie nimmt man das ein?' }, + { target: 'Uminom og tubig.', gloss: 'Trink Wasser.' }, + { target: 'Magpahuway sa.', gloss: 'Ruh dich aus.' }, + { target: 'Tabang!', gloss: 'Hilfe!' }, + { target: 'Dali lang!', gloss: 'Schnell!' } + ], + speakingPrompts: [ + { + title: 'Acht Antworten', + prompt: 'Reagiere auf acht gemischte Gesundheits- und Notfallsituationen.', + cue: 'Magpahuway sa. Uminom og tubig. Adto ta sa doktor. Tabang!' + } + ], + practicalTasks: [ + { + title: 'Kontrast', + text: 'Kontrastiere: leicht vs stark, Arzt vs Apotheke, Bitte vs Notfall.' + } + ] }, 'Woche 8 - Checkpoint': { learningGoals: [ @@ -178,7 +598,29 @@ export const BISAYA_PHASE4_DIDACTICS = { 'Abruf, Verständnis und situative Anwendung prüfen.', 'Stärken und Lücken für Woche 9 festhalten.' ], - corePatterns: ['doktor', 'botika', 'hilanat', 'tabang'] + corePatterns: [ + { target: 'doktor', gloss: 'Arzt' }, + { target: 'botika', gloss: 'Apotheke' }, + { target: 'hilanat', gloss: 'Fieber' }, + { target: 'tabang', gloss: 'Hilfe' }, + { target: 'Naa mi appointment.', gloss: 'Wir haben einen Termin.' }, + { target: 'Sakit kaayo.', gloss: 'Es tut sehr weh.' }, + { target: 'Unsaon pag-inom?', gloss: 'Wie nimmt man das ein?' }, + { target: 'Tawag ug doktor.', gloss: 'Ruf einen Arzt.' } + ], + speakingPrompts: [ + { + title: 'Checkpoint-Szene', + prompt: 'Loese eine Szene: Termin, Beschwerden, Apotheke, Notfall.', + cue: 'Naa mi appointment. Sakit kaayo. Naa moy tambal ani? Tawag ug doktor.' + } + ], + practicalTasks: [ + { + title: 'Diagnose', + text: 'Markiere die unsicheren Saetze und wiederhole sie im Typing bis sie sofort kommen.' + } + ] }, 'Einkaufen vertiefen': { learningGoals: [ @@ -531,26 +973,26 @@ export const BISAYA_PHASE4_DIDACTICS = { }; export const BISAYA_PHASE4_LESSONS = [ - { week: 7, day: 1, num: 64, type: 'conversation', title: 'Kinder im Alltag', desc: 'Mit Kindern sprechen und Fürsorge im Alltag ausdrücken', targetMin: 18, targetScore: 80, review: false, cultural: null }, - { week: 7, day: 1, num: 65, type: 'vocab', title: 'Schule & Betreuung', desc: 'Wortschatz für Schule, Tasche, Unterricht und Betreuung', targetMin: 18, targetScore: 85, review: true, cultural: null }, - { week: 7, day: 2, num: 66, type: 'grammar', title: 'Fragen an Kinder vereinfachen', desc: 'Kurze, klare Fragen für Kinder und Betreuungssituationen', targetMin: 20, targetScore: 78, review: true, cultural: null }, - { week: 7, day: 2, num: 67, type: 'conversation', title: 'Hausaufgaben & Routine', desc: 'Über Schule, Lernen und Routinen zuhause sprechen', targetMin: 18, targetScore: 80, review: false, cultural: null }, - { week: 7, day: 3, num: 68, type: 'review', title: 'Woche 7 - Intensivwiederholung I', desc: 'Kinder, Schule und Familienroutine intensiv wiederholen', targetMin: 28, targetScore: 80, review: false, cultural: null }, - { week: 7, day: 3, num: 69, type: 'vocab', title: 'Spiralwiederholung - Familie, Kinder & Fürsorge', desc: 'Frühe Kernmuster mit Kinderalltag verbinden', targetMin: 20, targetScore: 85, review: true, cultural: null }, - { week: 7, day: 4, num: 70, type: 'conversation', title: 'Spielen & Freizeit', desc: 'Mit Kindern über Spiel, Pause und Freizeit sprechen', targetMin: 18, targetScore: 80, review: false, cultural: null }, - { week: 7, day: 4, num: 71, type: 'vocab', title: 'Spielsachen & Aktivitäten', desc: 'Spiel- und Freizeitwortschatz für Familienalltag', targetMin: 18, targetScore: 85, review: true, cultural: null }, - { week: 7, day: 5, num: 72, type: 'review', title: 'Woche 7 - Intensivwiederholung II', desc: 'Große Mischwiederholung zur Kinder- und Schulwoche', targetMin: 28, targetScore: 80, review: false, cultural: null }, - { week: 7, day: 5, num: 73, type: 'vocab', title: 'Woche 7 - Checkpoint', desc: 'Checkpoint zu Familie, Kindern und Schule', targetMin: 16, targetScore: 82, review: true, cultural: null }, - { week: 8, day: 1, num: 74, type: 'conversation', title: 'Arzt & Termin', desc: 'Arzttermine vereinbaren und Gesundheitsfragen stellen', targetMin: 18, targetScore: 80, review: false, cultural: null }, - { week: 8, day: 1, num: 75, type: 'vocab', title: 'Apotheke & Medikamente', desc: 'Wichtiger Wortschatz für Apotheke und Medizin', targetMin: 18, targetScore: 85, review: true, cultural: null }, - { week: 8, day: 2, num: 76, type: 'grammar', title: 'Beschwerden genauer beschreiben', desc: 'Schmerz, Verlauf und Stärke konkreter ausdrücken', targetMin: 20, targetScore: 78, review: true, cultural: null }, - { week: 8, day: 2, num: 77, type: 'conversation', title: 'Notfälle & Hilfe', desc: 'In einfachen Notfällen Hilfe holen und reagieren', targetMin: 18, targetScore: 80, review: false, cultural: null }, - { week: 8, day: 3, num: 78, type: 'review', title: 'Woche 8 - Intensivwiederholung I', desc: 'Gesundheit, Arzt und Hilfe intensiv wiederholen', targetMin: 28, targetScore: 80, review: false, cultural: null }, - { week: 8, day: 3, num: 79, type: 'vocab', title: 'Spiralwiederholung - Gesundheit', desc: 'Frühere Fürsorge mit Gesundheit und Pflege verbinden', targetMin: 20, targetScore: 85, review: true, cultural: null }, - { week: 8, day: 4, num: 80, type: 'conversation', title: 'Essen, Ruhe & Genesung', desc: 'Pflege, Ruhe und Essen bei Krankheit besprechen', targetMin: 18, targetScore: 80, review: false, cultural: null }, - { week: 8, day: 4, num: 81, type: 'vocab', title: 'Körper, Symptome & Pflege', desc: 'Körper- und Pflegewortschatz ausbauen', targetMin: 18, targetScore: 85, review: true, cultural: null }, - { week: 8, day: 5, num: 82, type: 'review', title: 'Woche 8 - Intensivwiederholung II', desc: 'Große Mischwiederholung zu Gesundheit und Hilfe', targetMin: 28, targetScore: 80, review: false, cultural: null }, - { week: 8, day: 5, num: 83, type: 'vocab', title: 'Woche 8 - Checkpoint', desc: 'Checkpoint zu Arzt, Apotheke und Pflege', targetMin: 16, targetScore: 82, review: true, cultural: null }, + { week: 7, day: 1, num: 64, type: 'conversation', title: 'Kinder im Alltag', desc: 'Mit Kindern sprechen, Routinen strukturieren und Fürsorge ausdrücken', targetMin: 26, targetScore: 80, review: false, cultural: null }, + { week: 7, day: 1, num: 65, type: 'vocab', title: 'Schule & Betreuung', desc: 'Schul- und Betreuungsvokabeln plus kurze Alltagssätze (Tasche, Buch, Lehrkraft, Aufgabe)', targetMin: 24, targetScore: 85, review: true, cultural: null }, + { week: 7, day: 2, num: 66, type: 'grammar', title: 'Fragen an Kinder vereinfachen', desc: 'Kurze Fragen vs. Aufforderungen in Betreuungssituationen sicher bauen', targetMin: 26, targetScore: 78, review: true, cultural: null }, + { week: 7, day: 2, num: 67, type: 'conversation', title: 'Hausaufgaben & Routine', desc: 'Hausaufgaben, Lernen, Spielen und Schlafen in eine klare Routine bringen', targetMin: 26, targetScore: 80, review: false, cultural: null }, + { week: 7, day: 3, num: 68, type: 'review', title: 'Woche 7 - Intensivwiederholung I', desc: 'Kinder, Schule und Familienroutine intensiv wiederholen (Abruf + Rollenwechsel)', targetMin: 34, targetScore: 82, review: false, cultural: null }, + { week: 7, day: 3, num: 69, type: 'vocab', title: 'Spiralwiederholung - Familie, Kinder & Fürsorge', desc: 'Frühe Kernmuster in Kinder-/Schulszenen reaktivieren', targetMin: 24, targetScore: 85, review: true, cultural: null }, + { week: 7, day: 4, num: 70, type: 'conversation', title: 'Spielen & Freizeit', desc: 'Spiel, Pause, Regeln und ruhige Korrektur im Kinderalltag sprechen', targetMin: 24, targetScore: 80, review: false, cultural: null }, + { week: 7, day: 4, num: 71, type: 'vocab', title: 'Spielsachen & Aktivitäten', desc: 'Spiel- und Freizeitwortschatz aktiv nutzen (Auswahl, Fragen, kurze Saetze)', targetMin: 24, targetScore: 85, review: true, cultural: null }, + { week: 7, day: 5, num: 72, type: 'review', title: 'Woche 7 - Intensivwiederholung II', desc: 'Große Mischwiederholung zur Kinder- und Schulwoche (Szene bauen)', targetMin: 34, targetScore: 82, review: false, cultural: null }, + { week: 7, day: 5, num: 73, type: 'vocab', title: 'Woche 7 - Checkpoint', desc: 'Checkpoint zu Kindern, Schule, Hausaufgaben und Routine (Diagnose + freie Szene)', targetMin: 24, targetScore: 84, review: true, cultural: null }, + { week: 8, day: 1, num: 74, type: 'conversation', title: 'Arzt & Termin', desc: 'Arzttermine, Beschwerden und Wartezeit als Mini-Dialog organisieren', targetMin: 26, targetScore: 80, review: false, cultural: null }, + { week: 8, day: 1, num: 75, type: 'vocab', title: 'Apotheke & Medikamente', desc: 'Apotheke, Rezept, Dosierung und Einnahmefragen aktiv abrufen', targetMin: 24, targetScore: 85, review: true, cultural: null }, + { week: 8, day: 2, num: 76, type: 'grammar', title: 'Beschwerden genauer beschreiben', desc: 'Staerke, Verlauf, Zeitpunkte und wiederkehrende Beschwerden ausdruecken', targetMin: 26, targetScore: 78, review: true, cultural: null }, + { week: 8, day: 2, num: 77, type: 'conversation', title: 'Notfälle & Hilfe', desc: 'Hilfe rufen, kurze Anweisungen geben und Notfallanker sicher sprechen', targetMin: 26, targetScore: 80, review: false, cultural: null }, + { week: 8, day: 3, num: 78, type: 'review', title: 'Woche 8 - Intensivwiederholung I', desc: 'Arzt, Apotheke, Beschwerden und Hilfe intensiv wiederholen (Tempo + Abruf)', targetMin: 34, targetScore: 82, review: false, cultural: null }, + { week: 8, day: 3, num: 79, type: 'vocab', title: 'Spiralwiederholung - Gesundheit', desc: 'Fürsorge und Gesundheit als Langzeitabruf (Problem -> Antwort)', targetMin: 24, targetScore: 85, review: true, cultural: null }, + { week: 8, day: 4, num: 80, type: 'conversation', title: 'Essen, Ruhe & Genesung', desc: 'Pflegegespraeche: Essen, Wasser, Ruhe, Medizin und Besserung verbinden', targetMin: 24, targetScore: 80, review: false, cultural: null }, + { week: 8, day: 4, num: 81, type: 'vocab', title: 'Körper, Symptome & Pflege', desc: 'Koerper, Symptome und Pflegewortschatz mit kurzen Schmerzsaetzen kombinieren', targetMin: 24, targetScore: 85, review: true, cultural: null }, + { week: 8, day: 5, num: 82, type: 'review', title: 'Woche 8 - Intensivwiederholung II', desc: 'Große Mischwiederholung zu Gesundheit und Hilfe (Kontraste + freie Antworten)', targetMin: 34, targetScore: 82, review: false, cultural: null }, + { week: 8, day: 5, num: 83, type: 'vocab', title: 'Woche 8 - Checkpoint', desc: 'Checkpoint zu Arzt, Apotheke, Beschwerden und Notfall (Diagnose + Typing)', targetMin: 24, targetScore: 84, review: true, cultural: null }, { week: 9, day: 1, num: 84, type: 'conversation', title: 'Einkaufen vertiefen', desc: 'Komplexere Einkaufs- und Auswahlgespräche führen', targetMin: 18, targetScore: 80, review: false, cultural: null }, { week: 9, day: 1, num: 85, type: 'vocab', title: 'Markt & Mengen', desc: 'Wortschatz für Markt, Mengen und Auswahl', targetMin: 18, targetScore: 85, review: true, cultural: null }, { week: 9, day: 2, num: 86, type: 'grammar', title: 'Wünsche, Bedarf und Bitte', desc: 'Wunsch, Notwendigkeit und höfliche Bitte unterscheiden', targetMin: 20, targetScore: 78, review: true, cultural: null }, diff --git a/backend/scripts/create-bisaya-course-content.js b/backend/scripts/create-bisaya-course-content.js index 0403808..d059f66 100644 --- a/backend/scripts/create-bisaya-course-content.js +++ b/backend/scripts/create-bisaya-course-content.js @@ -15,7 +15,7 @@ import VocabCourse from '../models/community/vocab_course.js'; import User from '../models/community/user.js'; import { BISAYA_DIDACTICS_24_43, BISAYA_RELATIONSHIP_ANCHOR_DIDACTICS } from './bisaya-course-plan-24-43.js'; import { BISAYA_PHASE3_DIDACTICS, BISAYA_PHASE3_LESSONS } from './bisaya-course-phase3-extension.js'; -import { BISAYA_PHASE4_DIDACTICS } from './bisaya-course-phase4-extension.js'; +import { BISAYA_PHASE4_DIDACTICS, BISAYA_PHASE4_LESSONS } from './bisaya-course-phase4-extension.js'; import { BISAYA_PHASE5_DIDACTICS } from './bisaya-course-phase5-extension.js'; function withTypeName(exerciseTypeName, exercise) { @@ -33,9 +33,10 @@ const GENERATED_BISAYA_DIDACTICS = { ...BISAYA_PHASE5_DIDACTICS }; -const SAFE_EXERCISE_UPDATE_TITLES = new Set( - BISAYA_PHASE3_LESSONS.map((lesson) => lesson.title) -); +const SAFE_EXERCISE_UPDATE_TITLES = new Set([ + ...BISAYA_PHASE3_LESSONS.map((lesson) => lesson.title), + ...BISAYA_PHASE4_LESSONS.map((lesson) => lesson.title) +]); function normalizeText(value) { return String(value || '') diff --git a/backend/scripts/create-german-for-bisaya-course-content.js b/backend/scripts/create-german-for-bisaya-course-content.js index 41151c3..00d4ddc 100644 --- a/backend/scripts/create-german-for-bisaya-course-content.js +++ b/backend/scripts/create-german-for-bisaya-course-content.js @@ -285,13 +285,24 @@ function generateExercisesFromDidactics(lesson) { const pool = getLessonPatternPool(didactics); if (lesson.lessonType === 'conversation') { - return [ + const exercises = [ buildChoiceExercise(lesson, didactics, patternA, pool, 0), buildGapExercise(lesson.title, patternA), buildSentenceExercise(lesson.title, patternB), buildSituationalExercise(lesson.title, didactics, patternA), buildSpeakingExercise(lesson.title, didactics, patternB) ].filter(Boolean); + + // Ab Alltag/Stabilisierung konsequent mehr produktive Leistung verlangen. + if (Number(lesson.lessonNumber) >= 91) { + const extraSituational = buildSituationalExercise(lesson.title, didactics, patternB); + if (extraSituational) exercises.push(extraSituational); + } + if (Number(lesson.lessonNumber) >= 121) { + const extraSpeaking = buildSpeakingExercise(lesson.title, didactics, patternA); + if (extraSpeaking) exercises.push(extraSpeaking); + } + return exercises; } if (lesson.lessonType === 'grammar') { @@ -305,7 +316,7 @@ function generateExercisesFromDidactics(lesson) { } if (lesson.lessonType === 'review' || lesson.didacticMode === 'intensive_review') { - return [ + const exercises = [ buildChoiceExercise(lesson, didactics, patternA, pool, 0), buildChoiceExercise(lesson, didactics, patternB, pool, 1), buildGapExercise(lesson.title, patternA), @@ -313,6 +324,16 @@ function generateExercisesFromDidactics(lesson) { buildSituationalExercise(lesson.title, didactics, patternA), buildSpeakingExercise(lesson.title, didactics, patternB) ].filter(Boolean); + + if (Number(lesson.lessonNumber) >= 91) { + const extraSpeaking = buildSpeakingExercise(lesson.title, didactics, patternA); + if (extraSpeaking) exercises.push(extraSpeaking); + } + if (String(lesson.title || '').toLowerCase().includes('checkpoint')) { + const extraSituational = buildSituationalExercise(lesson.title, didactics, patternB); + if (extraSituational) exercises.push(extraSituational); + } + return exercises; } if (lesson.lessonType === 'culture') { diff --git a/backend/scripts/create-german-for-bisaya-course.js b/backend/scripts/create-german-for-bisaya-course.js index 65a5c6c..4a85fdb 100644 --- a/backend/scripts/create-german-for-bisaya-course.js +++ b/backend/scripts/create-german-for-bisaya-course.js @@ -16,7 +16,10 @@ import { GERMAN_FOR_BISAYA_PHASE1_DIDACTICS, GERMAN_FOR_BISAYA_PHASE1_LESSONS } import { GERMAN_FOR_BISAYA_PHASE3_DIDACTICS, GERMAN_FOR_BISAYA_PHASE3_LESSONS } from './german-for-bisaya-phase3-extension.js'; import { GERMAN_FOR_BISAYA_PHASE4_DIDACTICS, GERMAN_FOR_BISAYA_PHASE4_LESSONS } from './german-for-bisaya-phase4-extension.js'; import { GERMAN_FOR_BISAYA_PHASE5_DIDACTICS, GERMAN_FOR_BISAYA_PHASE5_LESSONS } from './german-for-bisaya-phase5-extension.js'; -import { getGermanForBisayaLessonPedagogy } from './german-for-bisaya-phase2-pedagogy.js'; +import { + getGermanForBisayaLessonPedagogy, + getGermanForBisayaProgressTargets +} from './german-for-bisaya-phase2-pedagogy.js'; const ALL_GERMAN_FOR_BISAYA_LESSONS = [ ...GERMAN_FOR_BISAYA_PHASE1_LESSONS, @@ -107,6 +110,7 @@ async function createGermanForBisayaCourse(ownerHashedId) { for (const lessonData of ALL_GERMAN_FOR_BISAYA_LESSONS) { const didactics = ALL_GERMAN_FOR_BISAYA_DIDACTICS[lessonData.title] || {}; const pedagogy = getGermanForBisayaLessonPedagogy(lessonData.num, lessonData.type, lessonData.title); + const progressTargets = getGermanForBisayaProgressTargets(lessonData, pedagogy); await VocabCourseLesson.create({ courseId: course.id, @@ -130,8 +134,8 @@ async function createGermanForBisayaCourse(ownerHashedId) { grammarFocus: didactics.grammarFocus || null, speakingPrompts: didactics.speakingPrompts || null, practicalTasks: didactics.practicalTasks || null, - targetMinutes: lessonData.targetMin, - targetScorePercent: lessonData.targetScore, + targetMinutes: progressTargets.targetMinutes, + targetScorePercent: progressTargets.targetScorePercent, requiresReview: lessonData.review }); } diff --git a/backend/scripts/extend-bisaya-course-phase4.js b/backend/scripts/extend-bisaya-course-phase4.js index ffb7209..8745057 100644 --- a/backend/scripts/extend-bisaya-course-phase4.js +++ b/backend/scripts/extend-bisaya-course-phase4.js @@ -30,6 +30,7 @@ async function extendBisayaCoursePhase4() { }); let addedLessons = 0; + let updatedLessons = 0; for (const course of courses) { await course.update({ @@ -45,17 +46,9 @@ async function extendBisayaCoursePhase4() { } }); - if (existing) { - continue; - } - const didactics = BISAYA_PHASE4_DIDACTICS[lessonData.title] || {}; const pedagogy = getBisayaLessonPedagogy(lessonData.num) || {}; - - await VocabCourseLesson.create({ - courseId: course.id, - chapterId: null, - lessonNumber: lessonData.num, + const lessonPayload = { title: lessonData.title, description: lessonData.desc, weekNumber: lessonData.week, @@ -77,6 +70,20 @@ async function extendBisayaCoursePhase4() { newUnitTarget: pedagogy.newUnitTarget ?? null, reviewWeight: pedagogy.reviewWeight ?? null, isIntensiveReview: Boolean(pedagogy.isIntensiveReview) + }; + + if (existing) { + await existing.update(lessonPayload); + updatedLessons++; + console.log(`🔄 Kurs ${course.id}: Lektion ${lessonData.num} - ${lessonData.title} aktualisiert`); + continue; + } + + await VocabCourseLesson.create({ + ...lessonPayload, + courseId: course.id, + chapterId: null, + lessonNumber: lessonData.num }); addedLessons++; @@ -87,6 +94,7 @@ async function extendBisayaCoursePhase4() { console.log(`\n🎉 Phase 4 vorbereitet.`); console.log(` Kurse: ${courses.length}`); console.log(` Neue Lektionen ergänzt: ${addedLessons}`); + console.log(` Bestehende Lektionen aktualisiert: ${updatedLessons}`); console.log(' Das Einspielen in die DB kann später gesammelt mit den übrigen Phasen erfolgen.'); } diff --git a/backend/scripts/extend-german-for-bisaya-course-phase3.js b/backend/scripts/extend-german-for-bisaya-course-phase3.js index a8c4b64..38a3be5 100644 --- a/backend/scripts/extend-german-for-bisaya-course-phase3.js +++ b/backend/scripts/extend-german-for-bisaya-course-phase3.js @@ -4,7 +4,10 @@ import { sequelize } from '../utils/sequelize.js'; import VocabCourse from '../models/community/vocab_course.js'; import VocabCourseLesson from '../models/community/vocab_course_lesson.js'; import { GERMAN_FOR_BISAYA_PHASE3_DIDACTICS, GERMAN_FOR_BISAYA_PHASE3_LESSONS } from './german-for-bisaya-phase3-extension.js'; -import { getGermanForBisayaLessonPedagogy } from './german-for-bisaya-phase2-pedagogy.js'; +import { + getGermanForBisayaLessonPedagogy, + getGermanForBisayaProgressTargets +} from './german-for-bisaya-phase2-pedagogy.js'; async function getLanguageId(name) { const [language] = await sequelize.query( @@ -38,6 +41,7 @@ async function extendGermanForBisayaPhase3() { const didactics = GERMAN_FOR_BISAYA_PHASE3_DIDACTICS[lessonData.title] || {}; const pedagogy = getGermanForBisayaLessonPedagogy(lessonData.num, lessonData.type, lessonData.title); + const progressTargets = getGermanForBisayaProgressTargets(lessonData, pedagogy); await VocabCourseLesson.create({ courseId: course.id, @@ -61,8 +65,8 @@ async function extendGermanForBisayaPhase3() { grammarFocus: didactics.grammarFocus || null, speakingPrompts: didactics.speakingPrompts || null, practicalTasks: didactics.practicalTasks || null, - targetMinutes: lessonData.targetMin, - targetScorePercent: lessonData.targetScore, + targetMinutes: progressTargets.targetMinutes, + targetScorePercent: progressTargets.targetScorePercent, requiresReview: lessonData.review }); } diff --git a/backend/scripts/extend-german-for-bisaya-course-phase4.js b/backend/scripts/extend-german-for-bisaya-course-phase4.js index e275e48..8ded5d0 100644 --- a/backend/scripts/extend-german-for-bisaya-course-phase4.js +++ b/backend/scripts/extend-german-for-bisaya-course-phase4.js @@ -4,7 +4,10 @@ import { sequelize } from '../utils/sequelize.js'; import VocabCourse from '../models/community/vocab_course.js'; import VocabCourseLesson from '../models/community/vocab_course_lesson.js'; import { GERMAN_FOR_BISAYA_PHASE4_DIDACTICS, GERMAN_FOR_BISAYA_PHASE4_LESSONS } from './german-for-bisaya-phase4-extension.js'; -import { getGermanForBisayaLessonPedagogy } from './german-for-bisaya-phase2-pedagogy.js'; +import { + getGermanForBisayaLessonPedagogy, + getGermanForBisayaProgressTargets +} from './german-for-bisaya-phase2-pedagogy.js'; async function getLanguageId(name) { const [language] = await sequelize.query( @@ -38,6 +41,7 @@ async function extendGermanForBisayaPhase4() { const didactics = GERMAN_FOR_BISAYA_PHASE4_DIDACTICS[lessonData.title] || {}; const pedagogy = getGermanForBisayaLessonPedagogy(lessonData.num, lessonData.type, lessonData.title); + const progressTargets = getGermanForBisayaProgressTargets(lessonData, pedagogy); await VocabCourseLesson.create({ courseId: course.id, @@ -61,8 +65,8 @@ async function extendGermanForBisayaPhase4() { grammarFocus: didactics.grammarFocus || null, speakingPrompts: didactics.speakingPrompts || null, practicalTasks: didactics.practicalTasks || null, - targetMinutes: lessonData.targetMin, - targetScorePercent: lessonData.targetScore, + targetMinutes: progressTargets.targetMinutes, + targetScorePercent: progressTargets.targetScorePercent, requiresReview: lessonData.review }); } diff --git a/backend/scripts/extend-german-for-bisaya-course-phase5.js b/backend/scripts/extend-german-for-bisaya-course-phase5.js index 3fc8c2d..6debc10 100644 --- a/backend/scripts/extend-german-for-bisaya-course-phase5.js +++ b/backend/scripts/extend-german-for-bisaya-course-phase5.js @@ -4,7 +4,10 @@ import { sequelize } from '../utils/sequelize.js'; import VocabCourse from '../models/community/vocab_course.js'; import VocabCourseLesson from '../models/community/vocab_course_lesson.js'; import { GERMAN_FOR_BISAYA_PHASE5_DIDACTICS, GERMAN_FOR_BISAYA_PHASE5_LESSONS } from './german-for-bisaya-phase5-extension.js'; -import { getGermanForBisayaLessonPedagogy } from './german-for-bisaya-phase2-pedagogy.js'; +import { + getGermanForBisayaLessonPedagogy, + getGermanForBisayaProgressTargets +} from './german-for-bisaya-phase2-pedagogy.js'; async function getLanguageId(name) { const [language] = await sequelize.query( @@ -38,6 +41,7 @@ async function extendGermanForBisayaPhase5() { const didactics = GERMAN_FOR_BISAYA_PHASE5_DIDACTICS[lessonData.title] || {}; const pedagogy = getGermanForBisayaLessonPedagogy(lessonData.num, lessonData.type, lessonData.title); + const progressTargets = getGermanForBisayaProgressTargets(lessonData, pedagogy); await VocabCourseLesson.create({ courseId: course.id, @@ -61,8 +65,8 @@ async function extendGermanForBisayaPhase5() { grammarFocus: didactics.grammarFocus || null, speakingPrompts: didactics.speakingPrompts || null, practicalTasks: didactics.practicalTasks || null, - targetMinutes: lessonData.targetMin, - targetScorePercent: lessonData.targetScore, + targetMinutes: progressTargets.targetMinutes, + targetScorePercent: progressTargets.targetScorePercent, requiresReview: lessonData.review }); } diff --git a/backend/scripts/german-for-bisaya-phase2-pedagogy.js b/backend/scripts/german-for-bisaya-phase2-pedagogy.js index 1f70e97..85314d9 100644 --- a/backend/scripts/german-for-bisaya-phase2-pedagogy.js +++ b/backend/scripts/german-for-bisaya-phase2-pedagogy.js @@ -63,3 +63,43 @@ export function getGermanForBisayaLessonPedagogy(lessonNumber, lessonType, lesso isIntensiveReview: lessonType === 'review' }; } + +export function getGermanForBisayaProgressTargets(lessonData, pedagogy) { + const baseMinutes = Number(lessonData?.targetMin || 18); + const baseScore = Number(lessonData?.targetScore || 80); + const lessonNumber = Number(lessonData?.num || 1); + const lessonType = String(lessonData?.type || ''); + const didacticMode = String(pedagogy?.didacticMode || ''); + const isCheckpoint = String(lessonData?.title || '').toLowerCase().includes('checkpoint'); + + // Spuerbar steilere Progression: spaetere Wochen bekommen mehr Produktionszeit + // und hoehere Zielwerte, ohne den Einstieg zu ueberfrachten. + let minutesBump = 0; + if (lessonNumber >= 61 && lessonNumber <= 90) minutesBump += 2; + if (lessonNumber >= 91 && lessonNumber <= 120) minutesBump += 4; + if (lessonNumber >= 121) minutesBump += 6; + + if (lessonType === 'conversation' && lessonNumber >= 91) minutesBump += 2; + if (lessonType === 'review') minutesBump += 3; + if (isCheckpoint) minutesBump += 2; + + let scoreBump = 0; + if (lessonNumber >= 61 && lessonNumber <= 90) scoreBump += 2; + if (lessonNumber >= 91 && lessonNumber <= 120) scoreBump += 4; + if (lessonNumber >= 121) scoreBump += 6; + + if (lessonType === 'grammar') scoreBump += 2; + if (lessonType === 'review') scoreBump += 2; + if (didacticMode === 'contrast_training') scoreBump += 1; + if (isCheckpoint) scoreBump += 3; + + const targetMinutes = Math.min(45, baseMinutes + minutesBump); + const targetScorePercent = lessonType === 'culture' + ? 0 + : Math.min(96, baseScore + scoreBump); + + return { + targetMinutes, + targetScorePercent + }; +} diff --git a/backend/scripts/update-bisaya-didactics.js b/backend/scripts/update-bisaya-didactics.js index 3c50217..ca174f7 100644 --- a/backend/scripts/update-bisaya-didactics.js +++ b/backend/scripts/update-bisaya-didactics.js @@ -17,6 +17,7 @@ import { BISAYA_RELATIONSHIP_ANCHOR_DIDACTICS } from './bisaya-course-plan-24-43.js'; import { BISAYA_PHASE3_DIDACTICS } from './bisaya-course-phase3-extension.js'; +import { BISAYA_PHASE4_DIDACTICS } from './bisaya-course-phase4-extension.js'; /** Alte Kurstitel → aktueller Schlüssel in LESSON_DIDACTICS (bestehende Datenbanken). */ export const LEGACY_DIDACTICS_TITLE_MAP = { @@ -488,7 +489,8 @@ export const LESSON_DIDACTICS = { }, ...BISAYA_RELATIONSHIP_ANCHOR_DIDACTICS, ...BISAYA_DIDACTICS_24_43, - ...BISAYA_PHASE3_DIDACTICS + ...BISAYA_PHASE3_DIDACTICS, + ...BISAYA_PHASE4_DIDACTICS }; function resolveDidacticsForLesson(lesson) {