The API requires adaptive_mode when adaptive_timing_enabled is true,
but the frontend was only sending the enabled flag. This caused 400
errors when users tried to toggle adaptive timing on.
Now the toggle sends both fields when enabling, satisfying the API
validation requirements.
- Added PomodoroTimer component with work/break modes
- Timer appears as icon in header, expands to full widget on click
- Supports 25m work, 5m short break, 15m long break cycles
- Shows progress bar, cycle dots, and mode switcher
- Plays sound when timer completes
- Can be minimized while running (shows pulsing indicator)
- Added 'category' column to routine_templates table
- Categorized all 12 templates into: Daily Routines, Getting Things Done, Health & Body, Errands
- Added /api/templates/categories endpoint to list unique categories
- Updated /api/templates to support filtering by category query param
- Redesigned templates page with collapsible accordion sections by category
- Categories are sorted in logical order (Daily → Work → Health → Errands)
- All categories expanded by default for easy browsing
- Dynamic start/end hours computed from actual events (+1h padding each
side) instead of hard-coded 5 AM–11 PM; falls back to 7 AM–10 PM
when no events are scheduled
- Lane algorithm (greedy interval scheduling) prevents overlapping events
from hiding each other; routines and med groups share the same lane
pool so conflicts split the column width side by side
- Outer container locked to h-screen overflow-hidden to eliminate the
page-level scrollbar; timeline inner scrollbar hidden via
[&::-webkit-scrollbar]:hidden + scrollbarWidth:none
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replaces the flat routine card list with a day-oriented timeline showing
scheduled routines at their time slots, with week strip navigation and
a live "now" indicator. Adds bulk schedules API endpoint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses the existing bot token to send DMs to users by their Discord user ID
instead of posting to a channel webhook.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Issue #4 — Skip not clearing med
File: synculous-client/src/app/dashboard/medications/page.tsx Root cause: Skipped medications were routed to the "Upcoming" section (status === 'skipped' in the
upcoming condition), so they appeared as if still pending.
Fix: Removed || status === 'skipped' from the grouping condition. Now skipped meds go to the "Due"
section where they properly render with the "Skipped" label — same pattern as taken meds showing
"Taken".
Issue #5 — "Invested -359m in yourself"
Files: api/routes/routines.py, synculous-client/src/app/dashboard/page.tsx,
synculous-client/src/app/dashboard/stats/page.tsx
Root cause: Session duration was calculated by comparing a naive UTC created_at from PostgreSQL with
the user's local time (after stripping timezone). For users behind UTC (e.g., CST/UTC-6), this
produced negative durations (~-359 minutes ≈ -6 hours offset).
Fix: Added _make_aware_utc() helper that treats naive datetimes as UTC before comparison. Also clamped
durations to max(0, ...) on both backend and frontend formatTime as a safety net.
Issue #6 — Push notifications not working
File: api/routes/notifications.py
Root cause: Subscribing to push notifications created a push_subscriptions row but never set
web_push_enabled: true in the notifications table. The scheduler daemon checks web_push_enabled before
sending, so push notifications were always skipped.
Fix: When subscribing, also call notifications.setNotificationSettings() to enable web_push_enabled.
When unsubscribing (and no subscriptions remain), disable it.
- Add all 14 missing database tables (medications, med_logs, routines, etc.)
- Rewrite medication scheduling: support specific days, every N days, as-needed (PRN)
- Fix taken_times matching: match by created_at date, not scheduled_time string
- Fix adherence calculation: taken / expected doses, not taken / (taken + skipped)
- Add formatSchedule() helper for readable display
- Update client types and API layer
- Rename brilli-ins-client → synculous-client
- Make client PWA: add manifest, service worker, icons
- Bind dev server to 0.0.0.0 for network access
- Fix SVG icon bugs in Icons.tsx
- Add .dockerignore for client npm caching
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>