Implements Firebase read optimization with cache-first data loading, ReadCounter tracking, and real-time listener optimization to prevent excessive reads and costs.
This skill enforces Firebase read optimization patterns to prevent excessive costs and improve performance through cache-first data loading, comprehensive ReadCounter tracking, and optimized real-time listeners.
This workflow was developed in response to a **58 million Firebase read incident** that resulted in significant unexpected costs. ALL Firebase development must prioritize read efficiency and implement comprehensive caching.
1. **Planning Phase**
- Think through the problem and read relevant codebase files
- Write a detailed plan to `todo.md` with checkable todo items
- Check in with the user to verify the plan before proceeding
2. **Implementation Phase**
- Work through todo items, marking complete as you go
- Provide high-level explanations of changes at each step
- Keep every change as simple as possible, impacting minimal code
- Focus on simplicity over complexity
3. **Review Phase**
- Add a review section to `todo.md` summarizing changes
- Include relevant information about Firebase read optimization
- Document cache hit rates and cost savings
Every component that reads Firestore data MUST:
**Implementation Pattern:**
```javascript
const cachedData = cacheService.getCachedData(key);
if (cachedData) {
setData(cachedData);
readCounter.recordCacheHit('collection', 'Component', cachedData.length);
} else {
readCounter.recordCacheMiss('collection', 'Component');
// Fetch from Firestore and cache
}
```
ALL Firestore operations must be tracked:
```javascript
// Record cache hits
readCounter.recordCacheHit(collection, component, savedReads);
// Record cache misses
readCounter.recordCacheMiss(collection, component);
// Record actual reads
readCounter.recordRead(operation, collection, component, count);
```
Implement optimized listeners:
```javascript
const latestTimestamp = cacheService.getLatestTimestamp(key);
const unsubscribe = service.subscribeToNewData(
key,
(newData, isIncremental) => {
if (isIncremental) {
const updatedData = cacheService.appendNewData(key, newData);
setData(updatedData);
} else {
setData(newData);
cacheService.setCachedData(key, newData);
}
},
latestTimestamp
);
```
Every data type needs a dedicated cache service following this pattern:
```javascript
class DataCacheService {
constructor() {
this.CACHE_PREFIX = 'focal_data_';
this.CACHE_VERSION = '1.0';
this.MAX_CACHE_AGE = 7 * 24 * 60 * 60 * 1000; // 7 days
}
getCachedData(key) { /* implementation */ }
setCachedData(key, data) { /* implementation */ }
clearCache(key) { /* implementation */ }
getLatestTimestamp(key) { /* implementation */ }
appendNewData(key, newData) { /* implementation */ }
}
```
Before completing any Firebase-related task, verify:
```bash
npm start
npm run build
npm test
npm run lint
npm run lint:fix
```
See `ChatContext` and `ChatCacheService` in the codebase for the standard implementation pattern of cache-first loading with ReadCounter integration.
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/cache-first-firebase-development/raw