@@ -11,7 +11,10 @@ This is Tyler Earls' portfolio website built with React, Vite, TailwindCSS, and
1111### Development
1212
1313- ` npm run dev ` - Start development server with Vite on port 3000 (auto-opens browser)
14+ - ` npm run dev:flags ` - Start Cloudflare Worker for feature flags locally (port 8787)
15+ - ` npm run dev:all ` - Run both React app and feature flags Worker concurrently
1416- ` npm run build ` - Build for production (runs TypeScript compiler first, then Vite)
17+ - ` npm run preview ` - Preview production build locally
1518
1619### Testing
1720
@@ -30,6 +33,11 @@ This is Tyler Earls' portfolio website built with React, Vite, TailwindCSS, and
3033- ` npm run oxlint:fix ` - Auto-fix OxLint issues
3134- ` npm run format:check ` - Check Prettier formatting
3235- ` npm run format:fix ` - Auto-fix formatting with Prettier
36+ - ` npm run ci ` - Run all quality checks (lint, format, test, build) - used in CI/CD
37+
38+ ### Deployment
39+
40+ - ` npm run deploy:flags ` - Deploy feature flags Worker to Cloudflare
3341
3442## Architecture
3543
@@ -42,6 +50,14 @@ This is Tyler Earls' portfolio website built with React, Vite, TailwindCSS, and
4250- ** TypeScript** : Strict configuration with separate configs for app/node/tests
4351- ** Testing** : Vitest for unit tests, Cypress for integration tests
4452
53+ ### Monorepo Structure
54+
55+ This project uses ** npm workspaces** for managing multiple packages:
56+
57+ - ** Root** - Main React application
58+ - ** ` packages/shared-types/ ` ** - Shared TypeScript types between React app and Worker
59+ - ** ` packages/feature-flags/ ` ** - Cloudflare Worker for feature flags (KV storage, CORS, caching)
60+
4561### Project Structure
4662
4763- ` /src/components/ ` - React components organized by feature
@@ -51,23 +67,31 @@ This is Tyler Earls' portfolio website built with React, Vite, TailwindCSS, and
5167 - CSS Modules use ` .module.css ` extension
5268- ` /src/pages/ ` - Page components for routing
5369- ` /src/state/ ` - State management with XState
54- - ` /contexts/ ` - React contexts (ThemeContext uses XState actors)
70+ - ` /contexts/ ` - React contexts (ThemeContext, FeatureFlagContext use XState actors)
5571 - ` /machines/ ` - XState state machines (themeMachine, navigationMachine)
5672- ` /src/hooks/ ` - Custom React hooks
57- - ` /src/util/ ` - Utility functions and constants
73+ - ` /src/util/ ` - Utility functions and constants (includes ` API_URIS ` , ` BASE_URLS ` )
5874- ` /src/types/ ` - TypeScript type definitions
5975- ` /tests/ ` - Test files organized by type
6076 - ` /unit/ ` - Unit tests with Vitest
6177 - ` /integration/ ` - Cypress E2E tests
6278 - ` /component/ ` - Component-specific tests
79+ - ` /packages/ ` - Workspace packages
80+ - ` /feature-flags/ ` - Cloudflare Worker (wrangler.toml, KV namespaces)
81+ - ` /shared-types/ ` - Shared types for feature flags
6382
6483### Key Patterns
6584
6685- ** Path Aliasing** : ` @/ ` maps to ` /src/ ` directory
67- - ** CSS Modules** : Component styles use camelCase conversion
86+ - ** CSS Modules** : Component styles use camelCase conversion (e.g., ` styles.myClass ` )
6887- ** State Machines** : XState for complex state logic (theme toggling, navigation)
88+ - ** Feature Flags** : Runtime configuration via Cloudflare Worker + KV
89+ - Use ` FeatureFlagWrapper ` component for conditional rendering
90+ - Feature flags fetched from Worker, cached in localStorage (60s TTL)
91+ - Flags configured in Worker's KV namespace
6992- ** Image Optimization** : Cloudinary integration for optimized image delivery
70- - ** Performance Monitoring** : Why Did You Render development tool integrated
93+ - ** Performance Monitoring** : Why Did You Render development tool integrated (dev only)
94+ - ** React Compiler** : Babel plugin for automatic memoization (compilationMode: "infer")
7195
7296### Testing Strategy
7397
@@ -81,4 +105,64 @@ This is Tyler Earls' portfolio website built with React, Vite, TailwindCSS, and
81105- React Router configured for client-side only (SSR disabled)
82106- Vite dev server runs on port 3000
83107- CSS modules generate scoped class names (hash-based in production)
84- - The project includes performance profiling with why-did-you-render in development
108+ - ESLint uses flat config format (eslint.config.mts)
109+ - Two linters: ESLint (comprehensive) and OxLint (faster alternative)
110+
111+ ## Feature Flags System
112+
113+ ### Architecture
114+
115+ The feature flags system uses a ** Cloudflare Worker + KV** architecture:
116+
117+ 1 . ** Worker** (` packages/feature-flags/ ` ) serves flags via ` /api/flags ` endpoint
118+ 2 . ** KV Storage** holds flag configuration as JSON
119+ 3 . ** React Context** (` FeatureFlagContext ` ) fetches and caches flags
120+ 4 . ** Shared Types** (` packages/shared-types/ ` ) ensure type safety across stack
121+
122+ ### Managing Feature Flags
123+
124+ ** Update a flag value:**
125+
126+ ``` bash
127+ npx wrangler kv key put --binding=FEATURE_FLAGS --preview false " flags" \
128+ ' {"contactForm":{"enabled":true}}' \
129+ --config packages/feature-flags/wrangler.toml
130+ ```
131+
132+ ** Deploy Worker changes:**
133+
134+ ``` bash
135+ npm run deploy:flags
136+ ```
137+
138+ ** Environment variables:**
139+
140+ - Development: ` .env.development ` → ` VITE_FEATURE_FLAGS_API_URL=http://localhost:8787/api/flags `
141+ - Production: ` .env.production ` → ` VITE_FEATURE_FLAGS_API_URL=https://portfolio-feature-flags.tyler-a-earls.workers.dev/api/flags `
142+
143+ ### Using Feature Flags
144+
145+ ``` tsx
146+ import FeatureFlagWrapper from " @/components/FeatureFlagWrapper/FeatureFlagWrapper.tsx" ;
147+
148+ <FeatureFlagWrapper
149+ flagKey = " contactForm"
150+ whenEnabled = { <ContactEmailForm />}
151+ whenDisabled = { <ComingSoonMessage />}
152+ whenLoading = { <LoadingSpinner />}
153+ />;
154+ ```
155+
156+ ** Available flags:**
157+
158+ - ` contactForm ` - Controls contact form visibility ({ enabled: boolean, message?: string })
159+
160+ ## XState Integration
161+
162+ State machines live in ` /src/state/machines/ ` and are consumed via React contexts in ` /src/state/contexts/ ` . The pattern uses XState's actor model:
163+
164+ 1 . Define machine in ` /machines/ ` (e.g., ` themeMachine.ts ` )
165+ 2 . Create context provider wrapping ` createActorContext `
166+ 3 . Export hooks for accessing state and sending events
167+
168+ Example: ` ThemeContext ` wraps ` themeMachine ` and provides ` useTheme() ` hook.
0 commit comments