# Cloudflare Workers Roadmap for Mylder ## Overview Edge computing strategy for Mylder platform using Cloudflare Workers, R2, D1, and KV. **Philosophy:** Move compute closer to users, reduce VPS load, improve UX with sub-100ms responses. ## Current Architecture vs Edge-First ### Current (VPS-Centric) ``` User → Cloudflare CDN → VPS (149.102.155.84) ├── Next.js (Frontend) ├── Supabase (Auth, DB) ├── n8n (Automation) └── Dokploy (Orchestration) ``` ### Future (Edge-First) ``` User → Cloudflare Workers (Edge Logic) ├── Static Assets (CDN) ├── Edge Auth (Workers + KV) ├── Edge API (Workers + D1) └── Origin (VPS for heavy compute) ├── Supabase (Primary DB) └── n8n (Automation) ``` ## Workers Use Cases ### 1. Edge Authentication (Priority: High) **Problem:** Every auth check hits VPS → Supabase (100-300ms) **Solution:** Cache JWT validation at edge ```typescript // workers/auth-edge.ts export default { async fetch(request: Request, env: Env): Promise { const token = request.headers.get('Authorization')?.split('Bearer ')[1]; if (!token) return new Response('Unauthorized', { status: 401 }); // Check KV cache for user session const cached = await env.SESSIONS.get(token); if (cached) { return new Response(cached, { headers: { 'X-Auth-Source': 'edge-cache' } }); } // Fallback to Supabase origin const response = await fetch('https://supabase.mylder.io/auth/v1/user', { headers: { Authorization: `Bearer ${token}` } }); if (response.ok) { const user = await response.text(); await env.SESSIONS.put(token, user, { expirationTtl: 3600 }); // 1 hour return new Response(user, { headers: { 'X-Auth-Source': 'origin' } }); } return response; } }; ``` **Benefits:** - Auth checks: 300ms → 10ms (30x faster) - Reduced Supabase load - Better UX for logged-in users **Trade-offs:** - Session invalidation complexity - KV storage costs ($0.50/1M reads) ### 2. API Rate Limiting (Priority: High) **Problem:** DDoS/abuse protection on VPS is resource-intensive **Solution:** Rate limit at edge before hitting origin ```typescript // workers/rate-limiter.ts import { RateLimiter } from '@cloudflare/workers-rate-limiter'; export default { async fetch(request: Request, env: Env): Promise { const limiter = new RateLimiter({ namespace: env.RATE_LIMIT, // 100 requests per 60 seconds per IP limit: 100, period: 60, }); const ip = request.headers.get('CF-Connecting-IP') || 'unknown'; const { success } = await limiter.limit({ key: ip }); if (!success) { return new Response('Rate limit exceeded', { status: 429, headers: { 'Retry-After': '60' } }); } // Forward to origin return fetch(request); } }; ``` **Benefits:** - Block abuse before it hits VPS - Per-IP, per-user, per-endpoint limits - 0ms latency overhead **Use Cases:** - `/api/*` endpoints - Login attempts - Form submissions - Search queries ### 3. A/B Testing at Edge (Priority: Medium) **Problem:** Client-side A/B testing causes layout shift (poor CLS) **Solution:** Server-side rendering with edge variants ```typescript // workers/ab-test.ts export default { async fetch(request: Request, env: Env): Promise { const url = new URL(request.url); // Check existing variant let variant = request.headers.get('Cookie')?.match(/variant=([AB])/)?.[1]; if (!variant) { // Assign 50/50 split variant = Math.random() < 0.5 ? 'A' : 'B'; } // Rewrite request to origin with variant const originUrl = `${url.origin}${url.pathname}?variant=${variant}`; const response = await fetch(originUrl, request); // Set variant cookie const headers = new Headers(response.headers); headers.set('Set-Cookie', `variant=${variant}; Path=/; Max-Age=2592000`); return new Response(response.body, { status: response.status, headers }); } }; ``` **Benefits:** - No layout shift (CLS = 0) - Instant variant assignment - Analytics at edge **Use Cases:** - Landing page variants - Pricing page tests - Feature flags ### 4. Edge Personalization (Priority: Medium) **Problem:** Generic content for all users (low engagement) **Solution:** Geo/device-specific content at edge ```typescript // workers/personalize.ts export default { async fetch(request: Request, env: Env): Promise { const country = request.cf?.country as string; const device = request.headers.get('User-Agent')?.includes('Mobile') ? 'mobile' : 'desktop'; // Fetch base HTML from origin const response = await fetch(request); const html = await response.text(); // Inject personalized content const personalized = html .replace('{{COUNTRY}}', country) .replace('{{DEVICE}}', device) .replace('{{CURRENCY}}', getCurrency(country)); return new Response(personalized, { headers: { 'Content-Type': 'text/html', 'Cache-Control': 'public, max-age=60, s-maxage=3600', 'Vary': 'CF-IPCountry, User-Agent' } }); } }; function getCurrency(country: string): string { const map: Record = { US: 'USD', GB: 'GBP', EU: 'EUR', DK: 'DKK' }; return map[country] || 'USD'; } ``` **Benefits:** - Geo-specific content (currency, language) - Device-optimized markup - Sub-50ms personalization **Use Cases:** - Pricing display - Content localization - Feature availability ### 5. Image Optimization & Resizing (Priority: Low) **Problem:** Next.js Image Optimization on VPS is CPU-intensive **Solution:** Cloudflare Images or Workers + R2 ```typescript // workers/image-optimize.ts export default { async fetch(request: Request, env: Env): Promise { const url = new URL(request.url); const imagePath = url.pathname.replace('/img/', ''); // Parse resize params const width = url.searchParams.get('w') || '1920'; const quality = url.searchParams.get('q') || '80'; const format = url.searchParams.get('f') || 'webp'; // Fetch from R2 const object = await env.IMAGES.get(imagePath); if (!object) return new Response('Not Found', { status: 404 }); // Resize at edge (requires paid Workers plan) const resized = await fetch(`https://mylder.io/cdn-cgi/image/width=${width},quality=${quality},format=${format}/${imagePath}`); return new Response(resized.body, { headers: { 'Content-Type': `image/${format}`, 'Cache-Control': 'public, max-age=31536000, immutable' } }); } }; ``` **Benefits:** - Offload VPS CPU - Auto WebP/AVIF conversion - Responsive images on-demand **Trade-offs:** - Requires Cloudflare Images ($5/month + $1/100k) - Or R2 storage ($0.015/GB/month) ### 6. Edge API Caching (Priority: Medium) **Problem:** Repeated API calls for same data **Solution:** Smart caching with stale-while-revalidate ```typescript // workers/api-cache.ts export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { const cache = caches.default; const cacheKey = new Request(request.url, request); // Check cache let response = await cache.match(cacheKey); if (response) { const age = Date.now() - new Date(response.headers.get('Date')!).getTime(); // If stale (>60s), revalidate in background if (age > 60000) { ctx.waitUntil(revalidate(request, cache, cacheKey)); } return response; } // Fetch from origin response = await fetch(request); // Cache for 5 minutes const cached = new Response(response.body, response); cached.headers.set('Cache-Control', 'public, max-age=300, stale-while-revalidate=3600'); ctx.waitUntil(cache.put(cacheKey, cached)); return response; } }; async function revalidate(request: Request, cache: Cache, key: Request) { const fresh = await fetch(request); await cache.put(key, fresh.clone()); } ``` **Benefits:** - API responses: 200ms → 10ms - Stale content served instantly - Background revalidation **Use Cases:** - Public API endpoints - User profiles - Content feeds ## Cloudflare R2 (Object Storage) ### Use Cases for R2 **What:** S3-compatible object storage at edge (no egress fees) #### 1. User Uploads ```typescript // Store user avatars, documents await env.UPLOADS.put(`users/${userId}/avatar.jpg`, file); ``` **Benefits:** - $0.015/GB/month (10x cheaper than S3) - No egress fees (free downloads) - Global CDN distribution **When to Use:** - User-generated content (avatars, documents) - Static assets (fonts, icons) - Media files (videos, audio) **When NOT to Use:** - Frequent small writes (use D1 instead) - Sub-10MB total storage (use KV instead) #### 2. Static Asset Hosting ```typescript // Move _next/static/* to R2 const asset = await env.STATIC_ASSETS.get(path); return new Response(asset.body, { headers: { 'Cache-Control': 'public, max-age=31536000, immutable' } }); ``` **Benefits:** - Reduce VPS storage needs - Faster global distribution - Immutable content = perfect cache #### 3. Backup Storage ```typescript // Daily Supabase backups to R2 await env.BACKUPS.put(`supabase-${date}.sql.gz`, backup); ``` ## Cloudflare D1 (Edge Database) ### Use Cases for D1 **What:** SQLite at edge (sub-10ms queries globally) #### 1. Edge Metadata ```typescript // Store user preferences, feature flags const db = env.DB; const result = await db.prepare( 'SELECT theme, locale FROM user_prefs WHERE user_id = ?' ).bind(userId).first(); ``` **Benefits:** - Read latency: 100ms (Supabase) → 5ms (D1) - No VPS load for reads - SQL interface (familiar) **When to Use:** - Read-heavy data (user settings, configs) - Small datasets (<1GB) - Geo-distributed reads **When NOT to Use:** - Write-heavy workloads (D1 eventual consistency) - Complex joins (use Supabase instead) - Primary data storage (Supabase is source of truth) #### 2. Analytics/Metrics ```typescript // Store page views, click events await db.prepare( 'INSERT INTO analytics (page, user_id, timestamp) VALUES (?, ?, ?)' ).bind(page, userId, Date.now()).run(); ``` **Benefits:** - High-volume writes - Real-time aggregations - No Supabase quota impact #### 3. Feature Flags ```typescript // Enable/disable features per user const flags = await db.prepare( 'SELECT * FROM feature_flags WHERE active = 1' ).all(); ``` ### D1 vs Supabase Decision Matrix | Feature | D1 (Edge) | Supabase (VPS) | |---------|-----------|----------------| | Read Latency | 5-10ms | 100-300ms | | Write Latency | 50-100ms | 100-300ms | | Consistency | Eventual | Strong | | Storage Limit | 1GB | 8GB+ | | Cost | Free (5M reads/day) | Included in VPS | | Use Case | Cached metadata | Primary data | **Strategy:** D1 = edge cache, Supabase = source of truth ## Cloudflare KV (Key-Value Store) ### Use Cases for KV **What:** Global key-value store (sub-1ms reads) #### 1. Session Storage ```typescript await env.SESSIONS.put(sessionId, userData, { expirationTtl: 3600 }); ``` **Benefits:** - Fastest storage option (<1ms reads) - Auto-expiration (TTL) - Global replication **Cost:** $0.50/1M reads, $5/1M writes (generous free tier) #### 2. Configuration/Secrets ```typescript const apiKey = await env.CONFIG.get('stripe_public_key'); ``` #### 3. Rate Limit Counters ```typescript const count = await env.RATE_LIMIT.get(ip); await env.RATE_LIMIT.put(ip, count + 1, { expirationTtl: 60 }); ``` ## Implementation Roadmap ### Phase 1: Foundation (Month 1) **Goal:** Basic edge infrastructure - [ ] Set up Cloudflare Workers project - [ ] Deploy edge auth validator (Worker + KV) - [ ] Implement rate limiting for `/api/*` - [ ] Migrate static assets to R2 - [ ] Monitor performance impact **Success Metrics:** - Auth latency: <20ms (p95) - Static asset cache hit rate: >95% - VPS CPU load: -20% ### Phase 2: Optimization (Month 2-3) **Goal:** Performance wins - [ ] Deploy A/B testing worker - [ ] Implement edge personalization - [ ] Set up D1 for user preferences - [ ] Create stale-while-revalidate API cache - [ ] Image optimization via R2 + Workers **Success Metrics:** - LCP: <1.5s (p75) - API latency: -50% for cached endpoints - Global availability: 99.9% ### Phase 3: Advanced (Month 4+) **Goal:** Edge-first architecture - [ ] Move session management to edge (D1 + KV) - [ ] Implement edge analytics (D1) - [ ] Deploy feature flags system (D1) - [ ] Create edge API gateway - [ ] Multi-region failover **Success Metrics:** - Edge request ratio: >70% - Origin load: -60% - Global latency: <100ms (p95) ## Cost Analysis ### Free Tier Limits - **Workers:** 100k requests/day - **KV:** 100k reads/day, 1k writes/day - **R2:** 10GB storage, 1M reads/month - **D1:** 5M reads/day, 100k writes/day ### Paid Costs (Estimated for 1M users/month) | Service | Usage | Cost/Month | |---------|-------|------------| | Workers | 100M requests | $5 (bundled) | | KV | 50M reads | $25 | | R2 | 100GB storage + 500M reads | $1.50 | | D1 | Included in Workers | $0 | | **Total** | | **~$30/month** | **ROI:** Potential to downgrade VPS ($30/month savings) → break even ## Anti-Patterns to Avoid ### 1. Over-Caching **Bad:** Cache everything at edge for 24 hours **Good:** Cache static assets long, dynamic content short ### 2. Edge as Primary DB **Bad:** Store all user data in D1 **Good:** D1 = cache, Supabase = source of truth ### 3. Synchronous Edge-Origin Calls **Bad:** Worker → fetch origin → wait → respond **Good:** Serve stale, revalidate in background ### 4. Ignoring Cold Starts **Bad:** Assume Workers are instant **Good:** Optimize bundle size (<1MB), minimize dependencies ### 5. Complex Business Logic at Edge **Bad:** Move entire Next.js app to Workers **Good:** Keep heavy compute on VPS, edge for lightweight tasks ## Monitoring & Debugging ### Workers Analytics **Dashboard:** Workers & Pages → Analytics - Request volume - Success rate (2xx/3xx/4xx/5xx) - CPU time (p50, p95, p99) - Error logs ### Tail Workers (Real-Time Logs) ```bash wrangler tail mylder-auth-edge ``` ### Custom Metrics ```typescript // workers/metrics.ts export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { const start = Date.now(); const response = await fetch(request); const duration = Date.now() - start; // Log to D1 analytics ctx.waitUntil( env.ANALYTICS.prepare( 'INSERT INTO metrics (endpoint, duration, status) VALUES (?, ?, ?)' ).bind(request.url, duration, response.status).run() ); return response; } }; ``` ## Next Steps 1. **Prototype:** Deploy simple edge auth worker (1 day) 2. **Measure:** Compare edge vs origin performance (1 week) 3. **Iterate:** Expand to rate limiting, A/B testing (1 month) 4. **Optimize:** Move 70%+ traffic to edge (3 months) ## References - [Cloudflare Workers Docs](https://developers.cloudflare.com/workers/) - [R2 Storage](https://developers.cloudflare.com/r2/) - [D1 Database](https://developers.cloudflare.com/d1/) - [Workers Examples](https://developers.cloudflare.com/workers/examples/) - [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/)