Add ContactThreadRead model to track when users last viewed each contact thread.
Contacts with messages newer than the last read time show a blue dot in the sidebar.
Opening a thread automatically marks it as read via markThreadRead mutation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add CalendarDateRange input to GraphQL schema; server resolver now accepts from/to params
- Frontend query sends year-scoped date range variables reactively
- Rewrite zoom-in/zoom-out animations using GSAP flying-rect overlay (650ms vs 2400ms)
- Add flying-rect element to CrmCalendarPanel with proper CSS
- Remove old calendarSceneTransformStyle CSS-transition approach
- Add calendarKillTweens cleanup in onBeforeUnmount
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace custom gqlFetch() with proper Apollo useQuery/useMutation hooks
powered by codegen-generated TypedDocumentNode types. Key changes:
- Add GraphQL SDL schema file and codegen config for typescript-vue-apollo
- Replace all 28 raw .graphql imports with generated typed documents
- Add 12 useQuery() hooks with cache-and-network fetch policy
- Add 17 useMutation() hooks with surgical refetchQueries per mutation
- Optimistic cache update for setContactInboxHidden (instant archive UX)
- Fix contact list subtitle: show lastText instead of channel name
- Migrate login page from gqlFetch to useMutation
- WebSocket realtime now calls Apollo refetch instead of full data reload
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>