App Development Command Center

Every dimension. Nothing missed.
Overall QA Progress
0%

Architecture Standards

These are Brad's established, non-negotiable standards for all apps built with Sterling. Every new project follows these unless explicitly overridden.

Data Layer

D1 for ALL User Data REQUIRED
Every piece of data a user creates, edits, or interacts with MUST be stored in a Cloudflare D1 database. This includes tasks, settings, preferences, checklists, categories, dropdown options, templates, board data... everything. The ONLY acceptable localStorage uses are auth/session tokens, ephemeral form drafts that auto-clear, and one-time migration flags.
Cross-Device Sync by Default REQUIRED
If Brad opens the app on his phone and then on his desktop, it must show the exact same data. This is automatic when using D1 correctly. Test this explicitly before launch.
D1 Table + API Endpoint FIRST REQUIRED
When building any new feature, the D1 table and API endpoint come first, before any frontend code. The frontend is just a view of the database state.

Hosting & Deployment

Cloudflare Pages + Functions REQUIRED
Standard architecture: static frontend in /public/, API endpoints in /functions/api/. D1 bindings in wrangler.toml. Deploy via wrangler pages deploy.
Brad's Personal Cloudflare Account (Default) REQUIRED
Account ID: f80e8ac3dae61d519e12427b58f8bd4d. ALL deployments go here unless Brad explicitly says "OA Cloudflare." Business-related or not, personal account is the default.
SSL Active REQUIRED
HTTPS with proper redirect. Cloudflare handles this automatically for .pages.dev domains. Custom domains need DNS configured through Cloudflare.

Design System

Sterling Pages Design System REQUIRED
Light gray background (#f5f5f7), white cards (#ffffff), purple gradient header (linear-gradient(160deg, #0f0c29 0%, #302b63 50%, #24243e 100%)), primary accent #7c3aed, Inter font. Tab navigation ALWAYS (never scroll-down sections).
Branded Mode Override OVERRIDE ONLY
Custom brand identity used ONLY for standalone product sites (DugoutReady, Automate & Delegate, client websites). Brad must explicitly direct this.
Refresh Button REQUIRED
Every page gets a 36x36px refresh button in the top-right header. White semi-transparent, SVG refresh icon, spin animation on click, then location.reload(true). Must preserve current tab via sessionStorage. Brad saves pages as web apps on his phone.
Light Theme Default RECOMMENDED
Brad explicitly chose light over dark for readability. White/light backgrounds with dark text.

Authentication

Clerk for Retail Products RECOMMENDED
Self-signup apps where unknown users create accounts. Clerk handles auth, password reset, session management, and edge cases (browser cookie changes, Apple security updates) automatically. Free for 10K users.
Custom HMAC JWT for Internal/Invite-Only RECOMMENDED
When Brad controls who gets access. Backend-created accounts with invite codes or admin-set credentials. Simpler, no third-party dependency.
API Auth Enforced REQUIRED
Every API endpoint must verify authentication. No unprotected write endpoints. Auth check happens at the API level, not just the frontend.

API Design

RESTful Endpoints in /functions/api/ REQUIRED
Standard REST conventions: GET for reads, POST for creates, PUT/PATCH for updates, DELETE for removes. Consistent JSON response format with error handling.
CORS Configuration REQUIRED
Set appropriate CORS headers. For same-origin apps on Pages, this is often automatic. For cross-origin consumers, configure explicitly.
Error Handling Pattern REQUIRED
All API responses return { success: true, data: ... } or { success: false, error: "message" }. HTTP status codes used correctly (200, 201, 400, 401, 404, 500).

UX Patterns

Auto-Save with Toast REQUIRED
Settings and configuration changes auto-save on change/blur. Show a brief toast notification ("Saved") confirming the save. No save buttons unless Brad specifically requests one.
Dropdown Management: Both REQUIRED
Users can create new dropdown options on-demand in the section where they're used (type a new value, it gets added). Edit and delete in Settings. Best of both worlds.
Mobile-Desktop Feature Parity REQUIRED
Zero tolerance. Every feature accessible on mobile must be accessible on desktop, and vice versa. Bottom nav "More" menu items must have desktop equivalents.
Touch Targets 44px+ REQUIRED
All interactive elements must be at least 44x44px on mobile for comfortable tapping. Apple's HIG standard.

Launch Checklist (Non-Negotiable)

Favicon REQUIRED
Custom favicon. Never the default platform icon. Verify visually in browser tab.
Site Icon 512x512 REQUIRED
For bookmark and home screen use on all devices.
Apple Touch Icon 180x180 REQUIRED
iOS home screen icon. Without this, iOS uses a screenshot which looks terrible.
OG Image 1200x630 REQUIRED
Social sharing preview image. When someone shares the URL, this image appears.
Mobile Responsive REQUIRED
Tested at phone (375px), tablet (768px), and desktop (1200px+) widths minimum.

Active Apps Portfolio

All apps Brad has built with Sterling, with architecture details and status.

Decision Framework

Visual decision trees for the most common architectural choices. Use these to make fast, consistent decisions on every new project.

Auth Strategy

Who creates user accounts?
Unknown users sign up themselves
Public-facing app, anyone can create an account. Need email verification, password reset, social login, edge case handling.
Use Clerk (free for 10K users, specialist warranty)
Brad/admin creates accounts
Invite-only. Known user base. Brad controls who gets in. Simpler auth needs.
Build custom HMAC JWT (~8 min Sterling build)
Both paths needed
Some users self-register, some get invited. Different onboarding flows.
Use Clerk (handles both natively)
No real auth needed
Public reference page, internal dashboard with simple PIN gate, or single-user tool.
PIN gate or no auth (5 min build)

What Goes in D1?

Does a user create, edit, or interact with this data?
Yes - User-generated data
Tasks, settings, preferences, checklists, categories, dropdown options, templates, board data, form inputs, profiles
MUST go in D1. Zero exceptions.
No - Ephemeral/temp data
Auth tokens, form drafts that auto-clear, one-time migration flags, UI animation state
localStorage is OK
Does Brad need to see the same data on phone AND desktop?
Yes
This is the standard case. Almost everything Brad interacts with needs to sync.
D1 only. localStorage = different data per device.
No - Device-specific only
Rare. Maybe device-specific display preferences (font size, collapsed sections).
localStorage is acceptable

PWA vs Native App

Does the app need native device capabilities?
No - Standard web features only
CRUD operations, dashboards, forms, checklists, media display, notifications (web push).
PWA (10 min Sterling build, works on iOS + Android + desktop)
Yes - Needs camera, GPS, Bluetooth, etc.
Deep hardware integration, background location, Bluetooth devices, NFC, AR.
Consider native wrapper (Capacitor) or true native

PWA Advantages

  • Sterling builds in minutes, not weeks
  • No app store approval process
  • Instant updates (no user download)
  • Works on iOS, Android, AND desktop
  • Single codebase
  • Installable to home screen
  • Offline support with service worker
  • No app store fees (15-30%)
  • Chrome + Samsung Internet on Android handle PWAs great

PWA Limitations

  • iOS Safari has some PWA restrictions
  • No App Store/Play Store discoverability
  • Limited background processing on iOS
  • Push notifications limited on iOS (but improving)
  • No access to some native APIs
  • Can't sell through app stores

Build vs Buy (The Back Deck Test)

What type of component is this?
One-off project
Landing page, dashboard, microsite, one-time tool, checklist, reference page.
ALWAYS BUILD. Sterling's speed makes this a no-brainer. Zero ongoing cost.
Ongoing infrastructure that could break
Auth, SSL, email delivery, payment processing. Edge cases multiply over time.
LEAN TOWARD BUYING from a specialist. They handle edge cases you'd never anticipate.
Specialist does it for <$50/mo
Clerk (free 10K), Stripe (2.9%), Resend ($20/mo). Their team maintains it full-time.
BUY the warranty. Subscription < opportunity cost of debugging.
No good product exists
The market doesn't offer what Brad needs. Custom requirements.
BUILD IT. This is Sterling's sweet spot.

Sterling Build Time Benchmarks

Project TypeHuman CostSterling Time
Full auth system (12 features)$5-10K, 1-2 sprints~8 minutes
Client landing page$2-4K, 3-5 days15-30 minutes
API integration$1-3K, 2-4 days5-15 minutes
Dashboard / reporting tool$5-15K, 2-4 weeks30-60 minutes
Team/roster page$3-5K, 1-2 weeks<1 hour

Hosting Platform

What kind of site is this?
App / Dashboard / Tool
Interactive SPA, needs API endpoints, D1 database, custom logic.
Cloudflare Pages + Functions (free, fast, global CDN)
Content/Blog/SEO site
Lots of pages, blog posts, needs CMS for non-technical editors, SEO critical.
WordPress on Cloudways ($14/mo, proven CMS)
E-commerce
Product catalog, cart, checkout, inventory management.
Shopify or WooCommerce (specialist platforms)
Static reference / landing page
No database, no user accounts, just information display.
Cloudflare Pages (free, zero maintenance)

Reusable Components Library

Patterns Brad has across multiple apps. When building a new app, pull from these established patterns rather than inventing from scratch.

Tab Navigation with Reordering

Top tab bar with horizontal scroll on mobile. User can drag-reorder tabs. Active tab preserved in sessionStorage across refreshes. Tab order saved to D1 per user.
Key Implementation Notes
- sessionStorage.setItem('activeTab', tabId) on click - On load: check sessionStorage for saved tab - Tab order: D1 table `user_settings` with key='tab_order', value=JSON array - Mobile: overflow-x: auto, -webkit-overflow-scrolling: touch - Hide scrollbar: ::-webkit-scrollbar { display: none } - Active indicator: border-bottom: 2px solid #7c3aed

Bottom Nav with "More" Menu

Fixed bottom navigation on mobile (max 4-5 items visible). Overflow items go into a "More" sheet that slides up. Desktop shows all items in top tab bar or sidebar. Feature parity is mandatory.
Key Implementation Notes
- position: fixed; bottom: 0; left: 0; right: 0 - Safe area: padding-bottom: env(safe-area-inset-bottom) - "More" button opens overlay with remaining tabs - Desktop: @media (min-width: 768px) { .bottom-nav { display: none } } - CRITICAL: Every item in "More" must have a desktop equivalent - Touch targets: min 44px height per item

Settings Panel with Auto-Save

Settings changes auto-save on blur/change. Toast notification confirms save. No save buttons. Dropdowns manageable in Settings (edit/delete) and createable on-demand in context.
Key Implementation Notes
- input.addEventListener('change', async () => { await fetch('/api/settings', { method: 'PUT', body: ... }); showToast('Saved'); }); - Toast: fixed bottom center, fade in/out, 2s duration - Category/dropdown management: - In context: type new value, "Add" button, POST /api/categories - In Settings: list all, edit inline, delete with confirm - All settings stored in D1 `user_settings` table

D1-Backed CRUD Pattern

Standard pattern for any entity. API endpoints in /functions/api/[entity].js. D1 binding in wrangler.toml. Frontend fetches on load, optimistic UI on write.
Standard API Structure
// functions/api/items.js export async function onRequestGet({ env }) { const { results } = await env.DB.prepare( 'SELECT * FROM items ORDER BY created_at DESC' ).all(); return Response.json({ success: true, data: results }); } export async function onRequestPost({ request, env }) { const body = await request.json(); const result = await env.DB.prepare( 'INSERT INTO items (id, title, ...) VALUES (?, ?, ...)' ).bind(crypto.randomUUID(), body.title, ...).run(); return Response.json({ success: true }, { status: 201 }); } // wrangler.toml [[d1_databases]] binding = "DB" database_name = "my-app-db" database_id = "uuid-here"

Auth Gate (PIN / Username-Password)

Simple auth gate for internal tools. PIN mode: single shared PIN. Username/password mode: per-user credentials stored in D1 with bcrypt hashing. JWT issued on success, stored in localStorage.
Key Implementation Notes
PIN Mode: - Single PIN stored as env var or D1 setting - On match: set localStorage token, show app - No user accounts needed Username/Password Mode: - D1 `users` table: id, username, password_hash, role - Login: POST /api/auth/login -> verify bcrypt -> issue JWT - JWT: HMAC-SHA256, include user_id + role + exp - Every API call: verify JWT in Authorization header - Frontend: check localStorage for valid JWT on load Clerk Mode (retail): - npm install @clerk/clerk-js - Wrap app in ClerkProvider - useAuth() hook for state - Middleware for API protection

Toast Notifications

Non-intrusive feedback for user actions. Fixed position, bottom center. Auto-dismiss after 2-3 seconds. Multiple types: success (green), error (red), info (blue).
Key Implementation Notes
function showToast(message, type = 'success') { const t = document.getElementById('toast'); t.textContent = message; t.className = 'toast show ' + type; setTimeout(() => t.className = 'toast', 2500); } CSS: .toast { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); padding: 10px 20px; border-radius: 8px; font-size: 0.85rem; opacity: 0; transition: opacity 0.3s; z-index: 1000; } .toast.show { opacity: 1; } .toast.success { background: #065f46; color: #fff; } .toast.error { background: #991b1b; color: #fff; }

Pull-to-Refresh

Mobile gesture to refresh data. Shows spinner animation during refresh. Works alongside the header refresh button.
Key Implementation Notes
- Track touchstart Y position - On touchmove: if scrollTop === 0 and pulling down > 60px - Show refresh indicator - On touchend: call data refresh function - After fetch complete: hide indicator - Alternative: use header refresh button (works on all platforms) - iOS PWA: pull-to-refresh sometimes conflicts with Safari's built-in gesture. Test carefully.

Service Worker with Cache Busting

Enables offline access and faster loads. Version-stamped cache names so updates deploy cleanly. Handles the "stale app" problem.
Key Implementation Notes
// sw.js const CACHE_NAME = 'app-v1.0.0'; // Bump on deploy const ASSETS = ['/', '/index.html', '/styles.css']; self.addEventListener('install', e => { e.waitUntil(caches.open(CACHE_NAME) .then(c => c.addAll(ASSETS))); self.skipWaiting(); }); self.addEventListener('activate', e => { e.waitUntil(caches.keys().then(keys => Promise.all(keys.filter(k => k !== CACHE_NAME) .map(k => caches.delete(k))))); }); // Network-first for API, cache-first for assets self.addEventListener('fetch', e => { if (e.request.url.includes('/api/')) { e.respondWith(fetch(e.request)); } else { e.respondWith(caches.match(e.request) .then(r => r || fetch(e.request))); } });

Category Management (On-Demand + Settings)

Users create categories/dropdown values wherever they need them (inline "Add new" in dropdowns). Full management (rename, reorder, delete) lives in Settings. Both backed by D1.
Key Implementation Notes
D1 Table: CREATE TABLE categories ( id TEXT PRIMARY KEY, type TEXT NOT NULL, -- 'vendor_type', 'task_category', etc. label TEXT NOT NULL, sort_order INTEGER DEFAULT 0, created_at TEXT DEFAULT (datetime('now')) ); In-context creation: - Dropdown shows existing + "Add new..." option at bottom - Selecting "Add new..." shows inline input - On submit: POST /api/categories, refresh dropdown, select new Settings management: - List all categories grouped by type - Inline edit (click to rename) - Drag to reorder (update sort_order) - Delete with confirmation ("This will remove the category. Items using it will become uncategorized.")