2025-12-30: Offline Capability
Task Metadata
Date: 2025-12-30
Status: Complete
1. Context
-
Goal: Enable the application to function without an active internet connection. Users should be able to:
- Load the application shell (PWA).
- View their previously loaded dashboard/meals (Read Cache).
- Add meals while offline, which sync automatically when connectivity returns (Write Queue).
-
Trigger: "Next Up" task in Phase 1 Foundation roadmap.
2. Approach
- Technical Strategy: Hybrid Offline Support (PWA + React Query).
- App Shell: Use
vite-plugin-pwato cache HTML, JS, and CSS assets, allowing the app to boot offline. - Data Caching (Read): Migrate from manual
useEffectfetching to TanStack Query (React Query). This provides out-of-the-box caching, background refetching, and robust state management. - Data Persistence (Write): Use
persistQueryClient(part of React Query) or a custom optimistic update pattern to handle offline mutations.
- App Shell: Use
- Key Decisions (Confirmed):
- Strategy Selection: Read the detailed comparison here.
- 1. React Query for Data: Chosen over Amplify DataStore.
- Role: Manages the "Furniture" (API responses, JSON data).
- Reasoning: Preserves custom backend logic/schema. Lightweight. Handles "Optimistic Updates" for instant UI feedback.
- 2. Vite PWA for App Shell:
- Role: Manages the "House" (HTML, JS, CSS).
- Reasoning: Ensures the app starts without internet (fixing the "No Internet" browser error), allowing React Query to take over.
3. Impact Analysis
- Files to Modify:
frontend/package.json(Add@tanstack/react-query,vite-plugin-pwa).frontend/vite.config.js(Configure PWA).frontend/src/main.jsx(Wrap app inQueryClientProvider).frontend/src/hooks/useMeals.js(Rewrite to useuseQueryanduseMutation).frontend/src/pages/Tracker.jsx(Adapt to new hook signature if needed).
- Risks:
- Migration Friction: Replacing
useMealslogic requires careful testing to ensure daily totals are still calculated correctly. - Cache Invalidation: Need to ensure that adding a meal immediately updates the list (Optimistic Updates).
- Migration Friction: Replacing
4. Execution Plan
- Step 1: Install Dependencies
@tanstack/react-query(Core Logic)@tanstack/react-query-persist-client(Offline Persistence)idb-keyval(Storage Adapter for Persistence)vite-plugin-pwa(App Shell Caching)
- Step 2: Service Layer Setup
- Create
src/services/ApiMealService.jsto encapsulate AppSync logic.
- Create
- Step 3: Query Client Configuration
- Setup
QueryClientinsrc/main.jsxwithpersistQueryClientplugin.
- Setup
- Step 4: PWA Configuration
- Configure
vite.config.jsandmanifest.json.
- Configure
- Step 5: Refactor useMeals
- Rewrite
useMeals.jsto useuseQuery(Read) anduseMutation(Write) calling the Service Layer.
- Rewrite
- Step 6: Verify
- Test offline load (PWA) and offline writes (Sync Queue).
5. Execution Notes
- Implementation Successful: Implemented the "PWA + React Query" strategy.
- Cache Duration: Configured Persistence
maxAgeto 30 Days and In-MemorygcTimeto Infinity.- Reasoning: To address the "Cold Cache" problem, allowing users to view meal history for the past month while offline (e.g., on a flight), provided the data was previously fetched.
- Trade-off: Slightly increased IndexedDB storage usage, which is acceptable for text-based data.
- Correction: Initially attempted to set
gcTimeto 30 days, but discovered that TanStack Query's internalsetTimeoutimplementation overflows at ~24.8 days, causing immediate cache removal. Switching toInfinityfor in-memory cache solved this while preserving the 30-day disk persistence limit.
- Freshness (
staleTime): Configured to 10 Seconds. Ensures multi-device sync works when switching tabs/apps.- Reasoning: Reduces redundant network requests when a user quickly navigates between days (e.g., comparing today vs. yesterday) or reloads a view. The UI remains instant and "quiet" (no spinners) for recently viewed data.
- Architecture: Created
frontend/src/services/ApiMealService.jsto decouple API logic from the UI, facilitating easier testing and potential future swapping of the storage engine. - PWA: Configured
vite-plugin-pwato cache the app shell (HTML/JS/CSS), ensuring the app loads instantly even without a network connection. - Identified Tech Debt: We are not currently persisting the
Timezonein the DynamoDBMealrecord.- Risk: While
UserDateensures data integrity for the current "4 AM Rule", we cannot retroactively re-calculate daily summaries if we ever change that rule (e.g., to a 5 AM rule) because we lack the original timezone context for theCreatedAttimestamp. - Action: Logged for a future backend update.
- Risk: While
6. User Approval & Notes
User Feedback: Implementing this was great since I got to learn about React Query and optimistic UI. Figuring out
gcTimevsstaleTimevsmaxAgeand what React Query is trying to do was interesting, also around figuring out the different query states and updating/invalidating specific query keys which you can do across keys :)