Gate dashboard rendering on isLockResolved to prevent content flash
before lock state is known. Remove animate-fade-in from LockOverlay
so it renders instantly. Always write accent color to localStorage
(even default cyan) to prevent theme flash on reload. Resolve lock
state on auth query error to avoid permanent blank screen. Lift
mobileOpen state above lock gate to survive lock/unlock cycles.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical: Lock state was purely React useState — refreshing the page reset it.
Now persisted server-side via is_locked/locked_at columns on user_sessions.
POST /auth/lock sets the flag, /auth/verify-password clears it, and
GET /auth/status returns is_locked so the frontend initializes correctly.
UI: Cache accent color in localStorage and apply via inline script in
index.html before React hydrates to eliminate the cyan flash on load.
UI: Increase TanStack Query gcTime from 5min to 30min so page data
survives component unmount/remount across tab switches without skeleton.
UI: Move Projects nav onClick from the icon element to the full-width
container div so the entire row is clickable when the sidebar is collapsed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
S-02: Confirmed drift-3 is used by auth/AmbientBackground — not dead code.
S-03: Extracted noise SVG data URI to module-level NOISE_SVG constant.
S-04: Added will-change: transform to drift orbs for GPU layer promotion.
S-05: Documented the 9 AM snooze default in getMinutesUntilTomorrowMorning.
S-06: Made calendar toolbar bg-card/95 with backdrop-blur-md for better
readability over the transparent FullCalendar grid.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
W-02: Renamed layout/AmbientBackground → AppAmbientBackground to avoid
naming collision with auth/AmbientBackground (IDE auto-import confusion).
S-01: Added visibilitychange listener to re-sync clock after tab
sleep/resume. Previously the interval would drift after laptop sleep
or long tab backgrounding.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Moved ambient from DashboardPage to AppLayout so all pages get the
drifting gradient effect, not just the dashboard
- Lightened card colors: --card 5% → 8%, --card-elevated 7% → 11%,
popover and FullCalendar backgrounds updated to match
- Renamed DashboardAmbient → AmbientBackground in layout/
- Glassmorphism class renamed dashboard-glass → ambient-glass,
applied at AppLayout content wrapper level
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Scale down all content text on mobile via .mobile-scale CSS class (excludes
navbar/UMBRA title). Hide calendar event times in month view (Google Calendar
style). Restructure CategoryFilterBar so categories display on a separate row
when toggled instead of being hidden behind the search bar. Reduce dashboard
widget density with hidden badges and tighter spacing on small screens.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
W-08: Add CHECK constraint on notifications.type (migration 044) with
defensive pre-check and matching __table_args__ on model.
W-05: Auto-detach umbral contact before Person delete — nulls out
connection's person_id so the connection survives deletion.
W-01: Add PUT /requests/{id}/cancel endpoint with atomic UPDATE,
silent notification cleanup, and audit logging. Frontend: direction-aware
ConnectionRequestCard, cancel mutation, pending requests section on
PeoplePage with incoming/outgoing subsections.
W-06: Convert useNotifications to context provider pattern — single
subscription shared via NotificationProvider in AppLayout. Adds
refreshNotifications convenience function.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Notification fixes:
- Add NotificationToaster component with real-time toast notifications
for new incoming notifications (30s polling, 15s stale time)
- Connection request toasts show inline Accept/Reject buttons
- Add inline Accept/Reject buttons to connection_request notifications
in NotificationsPage (prevents bricked requests after navigation)
- Don't mark connection_request as read or navigate away when pending
- Auto-refetch notification list when unread count increases
Admin panel fixes:
- Add error state UI to UserDetailSection and ConfigPage (previously
silently returned null/empty on API errors)
- Fix get_user response missing must_change_password and locked_until
- Fix create_user response missing preferred_name and date_of_birth
- Add defensive limit(1) on settings query to prevent MultipleResultsFound
- Guard _target_username_col JSONB cast with CASE to prevent crash on
non-JSON audit detail values
- Add connection audit action types to ConfigPage filter dropdown
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements the full User Connections & Notification Centre feature:
Phase 1 - Database: migrations 039-043 adding umbral_name to users,
profile/social fields to settings, notifications table, connection
request/user_connection tables, and linked_user_id to people.
Phase 2 - Notifications: backend CRUD router + service + 90-day purge,
frontend NotificationsPage with All/Unread filter, bell icon in sidebar
with unread badge polling every 60s.
Phase 3 - Settings: profile fields (phone, mobile, address, company,
job_title), social card with accept_connections toggle and per-field
sharing defaults, umbral name display with CopyableField.
Phase 4 - Connections: timing-safe user search, send/accept/reject flow
with atomic status updates, bidirectional UserConnection + Person records,
in-app + ntfy notifications, per-receiver pending cap, nginx rate limiting.
Phase 5 - People integration: batch-loaded shared profiles (N+1 prevention),
Ghost icon for umbral contacts, Umbral filter pill, split Add Person button,
shared field indicators (synced labels + Lock icons), disabled form inputs
for synced fields on umbral contacts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add animate-fade-in page transitions to all pages
- Persist sidebar collapsed state in localStorage
- Add two-click logout confirmation using useConfirmAction
- Restructure Todos header: replace <select> with pill filters, move search right
- Move Reminders search right-aligned with spacer
- Add event search dropdown + Create Event button to Calendar toolbar
- Add search input to Projects header with name/description filtering
- Fix CategoryFilterBar search focus ring clipping with ring-inset
- Create EventDetailPanel: read-only event view with copyable fields,
recurrence display, edit/delete actions, location name resolution
- Refactor CalendarPage to 55/45 split-panel layout matching People/Locations
- Add mobile overlay panel for calendar event details
- Add navigation state handler for CalendarPage (date/view from dashboard)
- Add navigation state handler for ProjectsPage (status filter from dashboard)
- Make all dashboard widgets navigable: stat cards → pages, week timeline
days → calendar day view, upcoming items → source pages, countdown items
→ calendar, today's events/todos/reminders → respective pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Swap LockProvider to outer wrapper so AlertsProvider can read isLocked.
When locked, dismiss all visible reminder toasts and skip firing new ones.
Toasts re-fire normally on unlock via the firedRef.clear() reset.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- [C-1] Add rate limiting and account lockout to /verify-password endpoint
- [W-3] Add max length validator (128 chars) to VerifyPasswordRequest
- [W-1] Move activeMutations to ref in useLock to prevent timer thrashing
- [W-5] Add user_id field to frontend Settings interface
- [S-1] Export auth schemas from schemas registry
- [S-3] Add aria-label to LockOverlay password input
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- C1: Replaced duplicate useAlerts() calls with AlertsProvider context
wrapping AppLayout — single hook instance, no double polling/toasts
- C2: Added null guard on remind_at in Active Reminders card format()
- W2: Clear snoozed_until when dismissing a reminder
- W5: Extracted getRelativeTime to shared lib/date-utils.ts
- S3: Replaced inline SVG with Lucide Bell component in toasts
- S4: Clear snoozed_until when remind_at is updated via PUT
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract duplicate statusColors/statusLabels to projects/constants.ts
- Add staleTime + select to sidebar tracked projects query to reduce
refetches and narrow data to only id/name
- Gate TrackedProjectsWidget query on settings being loaded
- Remove unnecessary from_attributes on TrackedTaskResponse schema
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds is_tracked boolean to projects, expandable tracked projects
in sidebar navigation, pin toggle on project cards/detail, and a
dashboard widget showing upcoming tasks from tracked projects.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add logout button to sidebar with destructive hover styling
- Fix case-sensitive todo category filter with .toLowerCase()
- Widen dialog popups from max-w-lg to max-w-xl with mobile margin
- Update CLAUDE.md with commit-and-push instruction
- Update progress.md: all CRUD tests verified, all outstanding items resolved
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>