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?
What Goes in D1?
Does a user create, edit, or interact with this data?
Does Brad need to see the same data on phone AND desktop?
PWA vs Native App
Does the app need native device capabilities?
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?
Sterling Build Time Benchmarks
| Project Type | Human Cost | Sterling Time |
|---|---|---|
| Full auth system (12 features) | $5-10K, 1-2 sprints | ~8 minutes |
| Client landing page | $2-4K, 3-5 days | 15-30 minutes |
| API integration | $1-3K, 2-4 days | 5-15 minutes |
| Dashboard / reporting tool | $5-15K, 2-4 weeks | 30-60 minutes |
| Team/roster page | $3-5K, 1-2 weeks | <1 hour |
Hosting Platform
What kind of site is this?
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.")
Color Palette
Live color explorer. Change the primary and secondary colors to preview how every UI element updates across the design system.
#7c3aed
#6d28d9
Generated Color Scale
Header & Navigation
Header Gradient BarPage header
Primary-to-secondary gradient background with white text. Sticky top bar.
CSS: background: linear-gradient(160deg, primary, secondary)
Tab ButtonsTab bar
Inactive, hover, and active states. Active tab shows primary color text with bottom border.
Inactive
Hover
Active
CSS: color: var(--primary); border-bottom-color: var(--primary)
Variants: inactive (#6b7280), hover (primary), active (primary + border)
Cards & Containers
Standard CardContent wrapper
White background, subtle shadow, 12px border-radius. Primary content container.
Standard card content with subtle shadow
CSS: background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.06)
Card with Accent BorderHighlighted content
Left border uses primary color to draw attention. Used for emphasis or selected state.
Accent card with primary-colored left border
CSS: border-left: 3px solid var(--primary)
Category HeaderSection grouping
Purple gradient background with white text. Used for grouping like Key Pages/Key Projects.
Category Header
CSS: background: linear-gradient(135deg, primary, secondary)
Collapsible SectionExpandable content
Click-to-expand header with chevron indicator. Border-bottom separator.
Section Title▼
Collapsed content revealed on click
CSS: cursor: pointer; border-bottom: 1px solid #f3f4f6
Buttons
Primary ButtonMain actions
Solid primary color background with white text. Main call-to-action.
Primary
Hover
CSS: background: var(--primary); hover: var(--secondary)
Variants: default, hover (secondary color), disabled (opacity 0.5)
Secondary ButtonAlternative actions
Light background with gray border. Used for cancel, secondary, or less prominent actions.
Secondary
CSS: background: #f3f4f6; border: 1px solid #d1d5db
Danger ButtonDestructive actions
Red-tinted background for delete/destructive operations. Fixed color, not affected by palette changes.
Delete Project
CSS: background: #fee2e2; color: #dc2626 (fixed)
Icon ButtonRefresh, close, etc.
Circular button with icon. Used for refresh in header, close on modals.
CSS: border-radius: 50%; background: var(--primary)
Form Elements
Text InputAll forms
Standard input with focus ring using primary color. 8px border-radius.
CSS: border-color: var(--primary); box-shadow: 0 0 0 3px rgba(primary, 0.1)
Select DropdownOptions selection
Native select element styled with same border radius and focus ring as text inputs.
CSS: border: 1px solid #d1d5db; border-radius: 8px
CheckboxChecklists, toggles
Native checkbox with accent-color set to primary. Used heavily in QA checklist.
CSS: accent-color: var(--primary)
Radio Button PillsWizard options
Pill-style radio selections. Selected state uses primary background.
Selected
Unselected
Option C
CSS: background: var(--primary); color: #fff (selected)
Badges & Pills
Status BadgesLabels, tags
Small rounded badges for categorization and status. Primary badge uses palette colors.
Primary
Success
Info
Warning
CSS: background: rgba(primary, 0.1); color: var(--primary)
Variants: primary (palette), success (green), info (blue), warning (amber) -- fixed
Category PillsApp cards, filters
Tags in app cards showing tech stack, features. Colored by context.
D1
Custom Auth
Static
Workers
CSS: padding: 2px 8px; border-radius: 10px; font-size: 0.7rem
Priority PillsTask priority
Fixed colors by priority level. Not affected by palette changes.
Critical
High
Medium
Low
CSS: fixed colors per priority level (not palette-driven)
Count BadgeCounters, notifications
Small circular or pill-shaped badge showing counts. Primary color background.
5
12 items
CSS: background: var(--primary); color: #fff; border-radius: 50%
Tables
Data TableLists, grids
Headers use dark gray (#1a1a1a) bold 700 text (mandatory). Row hover uses primary at ~6% opacity. Alternating stripe optional.
| Name | Status | Type | Last Updated |
|---|---|---|---|
| Command Center | Live | Dashboard | Jul 7, 2026 |
| Family Planner | Live | App | Jul 6, 2026 |
| Client Portal | Dev | Dashboard | Jul 5, 2026 |
CSS: th { color: #1a1a1a; font-weight: 700 } (MANDATORY DARK HEADERS)
Variants: hover row (primary ~6%), striped (#f9fafb alternating)
Progress Indicators
Progress BarQA checklist, completion
Gradient fill from primary to lighter variant. Track is light gray.
72%
35%
CSS: background: linear-gradient(90deg, primary, lighter-primary)
Status DotsApp status
Small colored dots indicating live/dev/planned status. Fixed colors, not palette-driven.
Live
Dev
Planned
CSS: width: 8px; height: 8px; border-radius: 50% (fixed colors)
Overlays & Feedback
Toast NotificationAction feedback
Fixed-position dark banner at bottom of screen. Shown briefly after actions like save/delete.
Project saved successfully
CSS: background: #1a1a2e; color: #fff; border-radius: 8px
Modal OverlayConfirmations, dialogs
Semi-transparent backdrop with centered white card. Used for confirm/delete dialogs.
CSS: background: rgba(0,0,0,0.4) (overlay); #fff (modal card)
Focus RingAll interactive elements
Primary color outline with low-opacity shadow. Applied on :focus to inputs and interactive elements.
Element with focus ring
CSS: border-color: var(--primary); box-shadow: 0 0 0 3px rgba(primary, 0.1)
Text & Typography
HeadingsPage/card/section titles
Three heading levels used across the app. All use Inter font, dark color.
H1 - Page Title (1.25rem / 700)
H2 - Card Title (1.1rem / 700)
H3 - Section Title (0.95rem / 600)
CSS: font-family: Inter; color: #1a1a2e / #374151
Body & Secondary TextContent, descriptions
Primary body text and muted secondary text for descriptions and metadata.
Body text - Primary content at 0.88rem, #4b5563
Secondary text - Descriptions at 0.82rem, #6b7280
Muted text - Timestamps, hints at 0.78rem, #9ca3af
CSS: color: #4b5563 (body), #6b7280 (secondary), #9ca3af (muted)
Link & Accent TextURLs, emphasis
Links use primary color. Underline on hover. Also used for emphasis text.
Link text (primary color)
Hover state
CSS: color: var(--primary); text-decoration: underline (hover)
Code BlockTechnical content
Dark background monospace block for code examples. Fixed colors.
const app = new CloudflarePages({
database: 'D1',
auth: 'custom-jwt'
});
CSS: background: #1e1b2e; color: #e2e8f0; font-family: monospace