commits
TypeScript 5.7+ makes Uint8Array generic over its buffer type.
Pass .buffer as ArrayBuffer to pushManager.subscribe() to fix
the type incompatibility with BufferSource.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The fixed-position feedback banners had no safe area padding, causing the
Continue button to be obscured by the home indicator on modern phones.
Added viewport-fit=cover and safe-area-inset-bottom padding to both banners.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a new exercise appears, automatically plays TTS audio if the
exercise has promptAudio enabled or is a speak exercise. This matches
the Duolingo-style experience where pronunciation is heard immediately.
Implements issue 3mgztgjxd3c22
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add audioText field to exercises so the speaker button plays just
the Tagalog word/phrase instead of the entire English question text.
For example, "What does 'Kamusta' mean?" now speaks "Kamusta".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the lesson route outside the AppShell layout route so the
main navigation bar (mascot, streak, XP, hearts, settings, logout)
is not shown during lessons, which have their own dedicated UI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Swaps the "AYOS" Typography in the header for a small Rambi SVG
that also acts as a home navigation link.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Backend: VAPID key generation/storage, push subscription CRUD,
notification preferences (reminder time in UTC), background scheduler
that checks every minute and sends push notifications to users
- Frontend: Settings page with daily reminder toggle and time picker,
service worker push event handlers via workbox importScripts,
usePushNotifications hook for subscription management
- Database: push_subscriptions table, vapid_keys table, reminder
columns on user_stats (reminder_enabled, reminder_time, last_notified_date)
Implements issue 3mgztv7hflj22
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the Continue button inside the feedback banners so it's always
accessible. Previously the fixed-position banners covered the
standalone Continue button, leaving users stuck.
Closes issue 3mgztkdfjzg22
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The .npmrc file with legacy-peer-deps=true was not being copied into the
Docker build stage, causing npm ci to fail on the vite-plugin-pwa peer
dependency conflict with vite@8.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When streak freezes bridge a gap, extend the streak by 1 for today's
activity (previously the streak stayed flat, losing a day). Also handle
duplicate column errors in migration runner so ALTER TABLE migrations
don't panic on server restart.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add streak freeze mechanic: users earn 1 streak freeze for every 7-day
streak milestone. Freezes are consumed to preserve streaks when users
miss days. If insufficient freezes exist, the streak resets.
Backend: new migration for streak_freezes column, updated streak logic
in progress route, updated stats responses to include streak_freezes.
Frontend: updated UserStats type, StreakBanner shows freeze count.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace trivial same-word matching pairs (Bag->Bag, Menu->Menu, etc.)
with actual Tagalog vocabulary (Payong->Umbrella, Pagkain->Food, etc.)
- Fix misleading "Match opposite adjectives" prompt to accurately describe
the Tagalog-to-English matching exercise
- Remove awkward slash-separated alternative in directions fill-in-the-blank
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The phrases lesson had "___ ko." with blank "Hindi ko alam" which
would produce the nonsensical "Hindi ko alam ko." Fixed to
"Hindi ko ___." with blank "alam" for correct "Hindi ko alam."
Also changed let to const for seenSections Set (mutated via .add(),
not reassigned).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduce sections concept (Section 1-4 planned) with section banners
on the home page. Expand Section 1 (Foundations) from 6 to 30 topics
covering CEFR A1 material: greetings, basics, introductions, courtesy,
numbers, colors, family, emotions, adjectives, body parts, clothing,
animals, home, nature, time, days, weather, verbs, daily routine, food,
shopping, market, restaurant, school, jobs, sports, health, directions,
travel, and common phrases.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The route /api/lesson-state/:topic_id/:lesson_id used the old Axum 0.6
colon syntax which doesn't work in Axum 0.8. Changed to curly brace
syntax so the GET and DELETE endpoints actually match incoming requests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add lesson_state table and API endpoints (PUT/GET/DELETE /api/lesson-state)
to persist in-progress lesson state (current exercise index, hearts, correct
count). On lesson load, check for saved state and restore it. After each
exercise advance, save state to the server. On lesson completion, delete the
saved state. This prevents losing all progress on disconnect or page refresh.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Handle browser AudioContext suspension by resuming on use, pass ctx
parameter to playTone to avoid redundant calls, and wrap all play
functions in try/catch for graceful degradation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Synthesize short tones via Web Audio API - no external audio files needed.
Correct answers play an ascending two-note ding, incorrect answers play a
gentle descending tone, and lesson completion plays a four-note fanfare.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add /api/tts endpoint using msedge-tts crate for high-quality
Filipino neural voices (fil-PH-BlessicaNeural default)
- Disk-based LRU cache in data/tts-cache/ to avoid re-synthesis
- Update useSpeech hook to fetch from server and play audio via
HTMLAudioElement instead of Web Speech API
- Add loading spinner to SpeakButton while audio is fetched
- TTS is now always available regardless of browser support
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove orphaned Divider in ReviewPage card (no content above it after
message moved to SpeechBubble)
- Remove unused Divider import
- Simplify lowHeartMessages in LessonPage: only 2 of 4 entries were
reachable, replaced array with direct ternary
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add 'encourage' mood with nodding animation
- Create SpeechBubble component for Rambi to "speak"
- Add Rambi to correct/incorrect feedback banners with Tagalog phrases
- Enhance ReviewPage with speech bubble and varied score-based messages
- Show Rambi encouragement during lessons when hearts are low
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename the mascot component from Rambutan to Rambi and introduce the
name in the HomePage greeting ("Kamusta! I'm Rambi!"). Update all
imports across LoginPage, RegisterPage, and ReviewPage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
vite-plugin-pwa@1.2.0 only supports vite up to v7, causing npm ci
to fail in the Docker build. Setting legacy-peer-deps=true allows
the install to proceed while the upstream adds vite@8 support.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the lightning bolt favicon with a rambutan mascot SVG matching
the in-app character. Set the tab title to "Ayos". Add PWA support via
vite-plugin-pwa with manifest, service worker, and installability in
Chrome. Generate PNG icons at 192x192, 512x512, and 180x180 for
apple-touch-icon. Include cargo fmt formatting fixes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a new exercise appears, automatically plays TTS audio if the
exercise has promptAudio enabled or is a speak exercise. This matches
the Duolingo-style experience where pronunciation is heard immediately.
Implements issue 3mgztgjxd3c22
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Backend: VAPID key generation/storage, push subscription CRUD,
notification preferences (reminder time in UTC), background scheduler
that checks every minute and sends push notifications to users
- Frontend: Settings page with daily reminder toggle and time picker,
service worker push event handlers via workbox importScripts,
usePushNotifications hook for subscription management
- Database: push_subscriptions table, vapid_keys table, reminder
columns on user_stats (reminder_enabled, reminder_time, last_notified_date)
Implements issue 3mgztv7hflj22
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When streak freezes bridge a gap, extend the streak by 1 for today's
activity (previously the streak stayed flat, losing a day). Also handle
duplicate column errors in migration runner so ALTER TABLE migrations
don't panic on server restart.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add streak freeze mechanic: users earn 1 streak freeze for every 7-day
streak milestone. Freezes are consumed to preserve streaks when users
miss days. If insufficient freezes exist, the streak resets.
Backend: new migration for streak_freezes column, updated streak logic
in progress route, updated stats responses to include streak_freezes.
Frontend: updated UserStats type, StreakBanner shows freeze count.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace trivial same-word matching pairs (Bag->Bag, Menu->Menu, etc.)
with actual Tagalog vocabulary (Payong->Umbrella, Pagkain->Food, etc.)
- Fix misleading "Match opposite adjectives" prompt to accurately describe
the Tagalog-to-English matching exercise
- Remove awkward slash-separated alternative in directions fill-in-the-blank
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The phrases lesson had "___ ko." with blank "Hindi ko alam" which
would produce the nonsensical "Hindi ko alam ko." Fixed to
"Hindi ko ___." with blank "alam" for correct "Hindi ko alam."
Also changed let to const for seenSections Set (mutated via .add(),
not reassigned).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduce sections concept (Section 1-4 planned) with section banners
on the home page. Expand Section 1 (Foundations) from 6 to 30 topics
covering CEFR A1 material: greetings, basics, introductions, courtesy,
numbers, colors, family, emotions, adjectives, body parts, clothing,
animals, home, nature, time, days, weather, verbs, daily routine, food,
shopping, market, restaurant, school, jobs, sports, health, directions,
travel, and common phrases.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add lesson_state table and API endpoints (PUT/GET/DELETE /api/lesson-state)
to persist in-progress lesson state (current exercise index, hearts, correct
count). On lesson load, check for saved state and restore it. After each
exercise advance, save state to the server. On lesson completion, delete the
saved state. This prevents losing all progress on disconnect or page refresh.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add /api/tts endpoint using msedge-tts crate for high-quality
Filipino neural voices (fil-PH-BlessicaNeural default)
- Disk-based LRU cache in data/tts-cache/ to avoid re-synthesis
- Update useSpeech hook to fetch from server and play audio via
HTMLAudioElement instead of Web Speech API
- Add loading spinner to SpeakButton while audio is fetched
- TTS is now always available regardless of browser support
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove orphaned Divider in ReviewPage card (no content above it after
message moved to SpeechBubble)
- Remove unused Divider import
- Simplify lowHeartMessages in LessonPage: only 2 of 4 entries were
reachable, replaced array with direct ternary
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add 'encourage' mood with nodding animation
- Create SpeechBubble component for Rambi to "speak"
- Add Rambi to correct/incorrect feedback banners with Tagalog phrases
- Enhance ReviewPage with speech bubble and varied score-based messages
- Show Rambi encouragement during lessons when hearts are low
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the lightning bolt favicon with a rambutan mascot SVG matching
the in-app character. Set the tab title to "Ayos". Add PWA support via
vite-plugin-pwa with manifest, service worker, and installability in
Chrome. Generate PNG icons at 192x192, 512x512, and 180x180 for
apple-touch-icon. Include cargo fmt formatting fixes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>