Database & Scaling Strategy โ
Last Updated: 2026-01-11
Status: Active โ guiding pilot through Year 3 infrastructure decisions
Overview โ
This document outlines Lantern's database selection rationale, scaling thresholds, migration triggers, and cost considerations. It also addresses how location-based features (Google Maps API, geofencing) impact infrastructure decisions.
TL;DR: Firestore handles our needs for 3-5 years. Focus on merchant adoption, not premature optimization.
Current Architecture โ
Firestore (Primary Database) โ
What we use it for:
- User profiles (encrypted location, preferences, Wave history)
- Merchant data (venue info, offers, analytics)
- Offer redemptions & check-in logs
- Encrypted notification queues
Why Firestore:
- Rich querying: Compound indexes for "nearby offers user hasn't redeemed"
- Offline-first: IndexedDB persistence for PWA (enabled in firebase.js)
- Real-time: Document listeners for live offer updates
- Security: Granular Firestore Security Rules
- Scalability: Horizontal scaling built-in (no sharding needed)
Implementation Details โ
- Persistence: IndexedDB with memory fallback (see firebase.js)
- Location Privacy: Ephemeral location checks only (never store raw coordinates)
- Encryption: Client-side encryption before Firestore writes (see encryption.js)
Scale Limits & Thresholds โ
Firestore Capacity (What You Actually Get) โ
Free Tier (Spark Plan) โ
- 50K document reads/day
- 20K document writes/day
- 20K document deletes/day
- 1 GiB storage
- Use case: Pilot phase (5-10 merchants, <1K users)
Blaze Plan (Pay-as-you-go) โ
- Reads: $0.06 per 100K documents
- Writes: $0.18 per 100K documents
- Deletes: $0.02 per 100K documents
- Storage: $0.18/GB/month
- No hard limits โ scales to millions of ops/day
Real-World Benchmarks โ
| Scale | Users | Operations/Day | Monthly Cost | Notes |
|---|---|---|---|---|
| Pilot | <1K | 50K-100K | $0 (free tier) | 5-10 merchants, light usage |
| Early Growth | 1K-10K | 500K-1M | $50-150 | Typical SaaS startup |
| Scaling | 10K-100K | 5M-10M | $200-800 | Regional platform |
| Enterprise | 100K-1M | 50M-100M | $2K-5K | Multi-region, heavy traffic |
| Breaking Point | 1M+ | 100M+ | $5K-15K+ | Consider hybrid architecture |
Lantern Year 1 projection: 40 merchants ร ~500 users/merchant = 20K users
โ ~1M operations/day = $50-100/month (0.02% of Firestore's comfort zone)
Firebase Realtime Database vs Firestore โ
| Feature | Firestore โ (Recommended) | Realtime Database |
|---|---|---|
| Querying | Rich (compound indexes, range queries, ordering) | Limited (shallow queries only) |
| Scalability | Unlimited horizontal scale | ~200K concurrent connections/instance |
| Data Model | Document/collection (structured) | JSON tree (denormalized) |
| Offline Support | Excellent (IndexedDB) | Good (local cache) |
| Pricing | Per-operation | Per-GB-downloaded |
| Real-time | Document listeners | Full tree sync |
| Best for | Complex queries, structured data | Simple chat, live scoreboards |
Decision Matrix for Lantern โ
Firestore wins because we need:
- Compound queries: "offers within 5km of user who hasn't redeemed yet"
- Structured data: Users, merchants, offers, redemptions as separate collections
- Offline-first: PWA requires IndexedDB persistence
- Security rules: Fine-grained access control per document
Realtime DB would be better for:
- Simple key-value stores
- Global state sync (all users see same data)
- <50ms latency for every update (e.g., multiplayer games, typing indicators)
Verdict: Stick with Firestore. Our use case is location-based discovery, not real-time chat.
Google Maps API Impact โ
API Integration Points โ
1. Places API (Venue Search & Discovery) โ
- Use case: Merchant onboarding (verify business exists, get coordinates)
- Cost: $32 per 1K requests (Place Details)
- Pilot usage: ~100-200 requests/month (manual merchant onboarding)
- Year 1 cost: <$10/month
2. Geolocation API (Browser-based) โ
- Use case: Get user's current location for "nearby offers"
- Cost: Free (browser API, no Google quota)
- Implementation:
navigator.geolocation.getCurrentPosition()
3. Maps JavaScript API (Optional: Display map UI) โ
- Use case: Show merchant locations on map view
- Cost: $7 per 1K map loads (Dynamic Maps)
- Pilot cost: <$10/month (most users just see list view)
- Optimization: Lazy load map only when user taps "Map View"
4. Geocoding API (Optional) โ
- Use case: Convert addresses to coordinates
- Cost: $5 per 1K requests
- When needed: Merchant address input (if not using Places API)
Cost Projections with Google Maps โ
| Scale | Users | Maps Loads/Month | Places Lookups | Monthly Cost | % of Total Infra |
|---|---|---|---|---|---|
| Pilot | 100 | 500-1K | 100-200 | $5-10 | <10% |
| Early Growth | 1K | 5K-10K | 500-1K | $50-100 | ~30% |
| Scaling | 10K | 50K-100K | 5K-10K | $500-1K | ~30% |
| Enterprise | 100K | 500K-1M | 50K-100K | $5K-10K | ~20% |
Key Insight: Google Maps costs scale linearly with user activity but remain <30% of total infrastructure costs (Firebase + Cloudflare + Maps). Payment processing fees dwarf all API costs.
Optimization Strategies:
- Cache Place Details: Store merchant coordinates in Firestore (don't re-query)
- Lazy load maps: Only load JavaScript API when user taps "Map View"
- Static maps for previews: Use Static Maps API ($2/1K loads) for thumbnails
- Batch geocoding: Geocode all merchant addresses once during onboarding
Database Impact: Minimal โ
- Google Maps responses are cached in Firestore (merchant collection)
- User location is ephemeral (never stored, only used for proximity checks)
- No additional database load from Maps integration
Geofencing Implementation & Impact โ
Geofencing Strategy โ
1. Client-Side Haversine Distance โ
- How it works: Browser gets GPS โ calculates distance to merchant โ enables "Light Lantern" if <200m
- Firestore query: Geohash-based filtering (see implementation below)
- Database impact: Low โ 1 read per location check (~5-10K reads/day for 1K users)
- Cost: <$5/month
2. Server-Side Verification (Fraud Prevention) โ
- How it works: Client submits redemption + encrypted location โ Cloud Function validates โ writes to Firestore
- Database impact: Medium โ 1 write + 1 read per redemption (~500-1K ops/day)
- Cost: Cloud Functions $0.40/million invocations + Firestore writes ($0.18/100K)
- Total cost: <$10/month for pilot
3. QR Code Verification (High-Value Offers) โ
- How it works: Merchant shows QR code โ user scans โ server validates merchant signature
- Database impact: Low โ 1 read to verify QR signature
- Use case: BOGO offers, >$20 value redemptions
- Cost: Negligible (<$1/month)
Geofencing Data Model โ
Firestore Structure โ
// merchants/{merchantId}
{
name: "Coffee Shop",
location: {
lat: 32.7157,
lng: -117.1611,
geohash: "9mudgbe0c", // For proximity queries
radius: 200 // meters
},
offers: [...]
}
// offers/{offerId}
{
merchantId: "abc123",
geohash: "9mudgbe0c", // Indexed for "nearby offers" query
redemptionCount: 42,
maxRedemptions: 100,
perUserLimit: 1
}
// redemptions/{redemptionId}
{
userId: "xyz789",
offerId: "offer456",
timestamp: "2026-01-11T10:30:00Z",
verifiedLocation: true, // Server-side validation flag
verificationMethod: "geofence" | "qr-code"
}Geohash Indexing for Proximity Queries โ
Implementation: Use geofire-common library
import { geohashForLocation, geohashQueryBounds } from 'geofire-common'
// 1. When merchant creates offer, store geohash
const geohash = geohashForLocation([lat, lng])
await setDoc(doc(db, 'offers', offerId), {
...offerData,
geohash,
location: { lat, lng, radius: 200 }
})
// 2. Query offers within 5km of user
const center = [userLat, userLng]
const radiusInM = 5000
const bounds = geohashQueryBounds(center, radiusInM)
const promises = bounds.map((b) => {
const q = query(
collection(db, 'offers'),
orderBy('geohash'),
startAt(b[0]),
endAt(b[1])
)
return getDocs(q)
})
const snapshots = await Promise.all(promises)
// Filter results by actual distance (geohash is approximate)Database Operations:
- Writes: 1 geohash calculation per offer creation (negligible cost)
- Reads: 2-4 Firestore queries per "nearby offers" check (~10-20 reads)
- Index: Composite index on
geohash(auto-created by Firestore)
Cost Impact:
- 1K users checking location 5x/day = 50K reads/day = 1.5M reads/month
- Cost: 1.5M reads ร $0.06/100K = $0.90/month ๐ฏ
GCP Migration Path (When Needed) โ
Firebase is GCP under the hood. Migration is gradual, not binary.
Migration Triggers (Not Before Year 3-5) โ
| Trigger | Symptom | Solution | Timeline |
|---|---|---|---|
| Query latency >500ms | Complex joins, heavy aggregations | Add Cloud SQL (Postgres) for relational data | Month 18-24 |
| Analytics queries slow Firestore | Merchant dashboards timeout | Stream to BigQuery for analytics | Month 12-18 |
| >1M ops/day | Firestore costs >$1K/month | Add Redis cache for hot data | Month 24-36 |
| Multi-region compliance | GDPR, data residency laws | Cloud Spanner or regional Firestore | Year 3+ |
| Sub-10ms query latency | Real-time Wave interactions | Memorystore (Redis) + CDN edge caching | Year 2-3 |
Hybrid Architecture (Long-Term Vision) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Client (PWA) โ
โ - IndexedDB offline cache โ
โ - Encrypted local storage โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Cloud Load Balancer โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโ
โผ โผ โผ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Firestore โ โ Cloud Functions โ โ Memorystore โ
โ (user data, โ โ (business logic,โ โ (Redis) โ
โ offers, โ โ auth, webhooks)โ โ (hot cache) โ
โ redemptions)โ โ โ โ โ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ โ
โผ โผ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ BigQuery โ โ Cloud SQL โ
โ (analytics, โ โ (relational โ
โ reporting) โ โ merchant data)โ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโMigration sequence:
- Year 1-2: Firestore only (current)
- Year 2-3: Firestore + BigQuery (analytics offload)
- Year 3-4: Firestore + BigQuery + Redis (hot cache)
- Year 4-5: Firestore + BigQuery + Redis + Cloud SQL (relational data)
Cost Comparison at 1M Active Users:
| Architecture | Monthly Cost | Use Case |
|---|---|---|
| Firestore alone | $500-1,500 | Simple apps, <10M ops/day |
| Firestore + BigQuery | $800-2,000 | Analytics-heavy |
| Firestore + Redis | $1,200-2,500 | Low-latency reads |
| Full GCP stack (SQL + Datastore + Redis + BigQuery) | $2,500-5,000 | Enterprise multi-region |
Cost Bottlenecks (In Order of Impact) โ
Pilot โ Year 3 Cost Breakdown โ
| Cost Category | Pilot (100 users) | Year 1 (20K users) | Year 3 (100K users) | % of Total |
|---|---|---|---|---|
| Payment Processing (Stripe) | $240/month | $1,500/month | $15,000/month | 85-90% |
| Google Maps API | $5-10 | $50-100 | $500-1,000 | 3-5% |
| Firestore | $0 (free) | $50-150 | $500-1,000 | 3-5% |
| Cloud Functions | $0 (free) | $10-20 | $100-200 | 1-2% |
| Cloudflare Hosting | $0 (free) | $0 (free) | $0 (free) | 0% |
| Total Infrastructure | ~$245 | ~$1,610 | ~$16,600 | 100% |
Key Insight: Payment processing dominates costs (85-90%). Database optimization is <5% of total spend.
Priority order for cost optimization:
- ๐ฅ Negotiate Stripe rates (2.9% โ 2.5% saves $1K/month at scale)
- ๐ Cache Google Maps data (saves $200-500/month)
- ๐พ Optimize Firestore queries (saves $50-100/month)
- โก Add Redis cache (costs $100/month but improves UX)
Action Items โ
Immediate (Pilot Phase) โ
- [x] Enable Firestore offline persistence โ (already enabled in firebase.js)
- [ ] Implement geohash indexing for proximity queries
- Use
geofire-commonlibrary - Create composite index:
offerscollection โgeohashfield - Document in Firestore rules
- Use
- [ ] Set Firebase budget alerts
- Firebase Console โ Usage & Billing โ Budget Alerts
- Alert threshold: $50/month (10x expected pilot cost)
- [ ] Create Firestore composite indexes
offerscollection:[geohash, redemptionCount]redemptionscollection:[userId, timestamp]- Run
firebase deploy --only firestore:indexes
- [ ] Document data model
- Create
docs/engineering/architecture/DATA_MODEL.md - Define collections, fields, security rules, indexes
- Create
Year 1 (Growth Phase) โ
- [ ] Upgrade to Blaze plan when free tier limits hit (~1K users)
- [ ] Implement geofence server-side validation (Cloud Function)
- Verify user location matches redemption location
- Flag suspicious redemptions (>5km from venue)
- Log fraud metrics to Firestore
- [ ] Add Google Maps caching
- Store Place Details in Firestore merchants collection
- Cache for 90 days, refresh on merchant update
- [ ] Monitor query performance
- Enable Firestore performance monitoring
- Set up Cloud Logging alerts for >500ms queries
Year 2-3 (Scaling Phase) โ
- [ ] Add BigQuery analytics pipeline
- Stream Firestore writes to BigQuery
- Build merchant analytics dashboards
- Offload reporting queries from Firestore
- [ ] Evaluate Redis cache if query latency >300ms
- Cache hot merchant offers (updated hourly)
- Cache user profiles (invalidate on update)
- Use Memorystore (managed Redis on GCP)
- [ ] Review migration triggers (quarterly)
- Query latency P95
- Monthly Firestore costs
- User-reported performance issues
Related Documentation โ
- Tech Stack โ Full technology overview
- Economics โ Cost projections & unit economics
- Security Architecture โ Encryption & privacy model
- Pilot Strategy โ Business timeline & financial model
- API Documentation โ Backend API design
Changelog โ
| Date | Change | Rationale |
|---|---|---|
| 2026-01-11 | Initial version | Document scaling strategy & migration triggers |
Next Review: 2026-07-01 (after pilot completion, 6 months)