# CLAUDE.md

This file provides comprehensive guidance to Claude Code (claude.ai/code) and developers when working with the Storyteller SDK JavaScript codebase.

## Project Overview

The Storyteller SDK for JavaScript/TypeScript is a comprehensive SDK for embedding interactive stories and clips into web applications. Published as `@getstoryteller/storyteller-sdk-javascript` on npm, it provides a complete solution for content presentation with support for stories, clips, polls, quizzes, and advertisements.

**Key Features:**
- Interactive story and clip players with swipe navigation
- Multiple layout options (row, grid, player views)
- Comprehensive theming system with dark mode support
- Analytics and engagement tracking
- Ad integration support
- Offline caching capabilities
- Server-side rendering support

## Quick Start Development Workflow

### Prerequisites
- [Node.js](https://nodejs.org/) - Version 16.20.2 (specified in `volta` field of package.json)
- [npm](https://www.npmjs.com/) (comes with Node.js)
- Note: `.nvmrc` file exists for Node version management

### Initial Setup
```bash
# Clone and install dependencies
git clone [repo-url]
npm ci

# Install demo dependencies separately
cd demo
npm install
cd ..

# Start development (SDK + demo site)
npm run start

# This runs three parallel processes:
# 1. SDK watch mode (rebuilds on changes)
# 2. Local proxy server (serves SDK locally)
# 3. Demo site (Next.js app for testing)
```

### Development URLs
- Demo site: http://localhost:8080
- SDK served at: http://localhost:8091/storyteller.min.js
- SDK CSS: http://localhost:8091/storyteller.min.css

### Environment Configuration
Set environment via localStorage in browser console:
```javascript
localStorage.setItem('API_ENVIRONMENT', 'staging'); // or 'development', 'production'
```

## Architecture Deep Dive

### Core Architectural Patterns

#### 1. Singleton Pattern
The SDK uses singletons for critical services to ensure consistent state:
```typescript
// Main SDK instance
Storyteller.sharedInstance

// Service singletons
DataService.sharedInstance
StoriesApiService.sharedInstance
ClipsApiService.sharedInstance
StorytellerDelegate.sharedInstance
```

**Why:** Prevents multiple instances that could cause state inconsistencies and memory leaks.

#### 2. Command Pattern for API Calls
All API operations use command objects:
```typescript
export class GetStoriesCommand extends HttpCommandBase<void, StoriesResponse> {
  public endpoint = 'story/stories/default';
  public method: HttpMethod = HttpMethod.get;
  
  public buildEndpoint(): string {
    // Dynamic endpoint construction
  }
  
  public transformResponse(response: StoriesResponse): StoriesResponse {
    // Response transformation logic
  }
}
```

**Why:** Encapsulates request logic, enables caching strategies, standardizes error handling.

#### 3. Delegate Pattern
Enables host app customization without modifying SDK:
```typescript
StorytellerDelegate.sharedInstance.userActivityOccurred = (type, data) => {
  // Host app handles activity
};
```

**Why:** Clean separation between SDK and host app, flexible integration patterns.

#### 4. Context-Based State Management
React contexts for localized state:
- `StoryViewContext` - Story player state
- `ClipContext` - Clips player state
- `HlsContext` - Video streaming state

**Why:** Leverages React's declarative paradigm while maintaining component isolation.

### Service Layer Architecture

```
┌─────────────────────────────────────┐
│         Host Application            │
├─────────────────────────────────────┤
│         Storyteller SDK             │
├─────────────────────────────────────┤
│         View Components             │
├─────────────────────────────────────┤
│         API Services                │
├─────────────────────────────────────┤
│         Data Service                │
├─────────────────────────────────────┤
│     Infrastructure Services         │
└─────────────────────────────────────┘
```

### Data Flow

1. **User Action** → Component event handler
2. **API Call** → Service creates command → DataService executes
3. **Response** → Command transforms → Service updates state
4. **UI Update** → Context/props trigger re-render

## Common Development Tasks

### Adding a New API Endpoint

1. **Create Command Class** in appropriate domain:
```typescript
// src/stories/commands/getStoryDetailsCommand.ts
export class GetStoryDetailsCommand extends HttpCommandBase<void, StoryDetails> {
  constructor(private storyId: string) {
    super();
  }
  
  public endpoint = 'story/details';
  public method = HttpMethod.get;
  
  public buildEndpoint(): string {
    return `${this.endpoint}/${this.storyId}`;
  }
}
```

2. **Add Service Method**:
```typescript
// src/stories/storiesApiService.ts
public async getStoryDetails(storyId: string): Promise<StoryDetails> {
  const command = new GetStoryDetailsCommand(storyId);
  return await this.dataService.execute(command);
}
```

3. **Use in Component**:
```typescript
const details = await StoriesApiService.sharedInstance.getStoryDetails(storyId);
```

### Creating a New View Component

1. **Create Base View Class**:
```typescript
// src/row/newFeature/storytellerNewFeatureBaseView.tsx
export abstract class StorytellerNewFeatureBaseView extends StorytellerAbstractListView {
  protected abstract renderContent(): JSX.Element;
  
  public render(): JSX.Element {
    return (
      <div className={styles.container}>
        {this.renderContent()}
      </div>
    );
  }
}
```

2. **Implement Specific Views**:
```typescript
// src/row/newFeature/storytellerNewFeatureRowView.tsx
export class StorytellerNewFeatureRowView extends StorytellerNewFeatureBaseView {
  protected renderContent(): JSX.Element {
    // Row-specific implementation
  }
}
```

3. **Export from Index**:
```typescript
// src/index.ts
export { StorytellerNewFeatureRowView } from './row/newFeature/storytellerNewFeatureRowView';
```

### Adding Theme Support

1. **Define Theme Interface**:
```typescript
// src/configuration/models/theme/newFeature/newFeatureTheme.ts
export interface INewFeatureTheme {
  backgroundColor?: string;
  textColor?: string;
  borderRadius?: number;
}
```

2. **Add to Main Theme**:
```typescript
// src/configuration/models/theme/storytellerTheme.ts
export interface IStorytellerTheme {
  // ... existing properties
  newFeature?: INewFeatureTheme;
}
```

3. **Apply in Component**:
```typescript
const theme = useTheme();
const styles = {
  backgroundColor: theme.newFeature?.backgroundColor || '#ffffff'
};
```

### Adding Analytics Events

1. **Define Event Type**:
```typescript
// src/infrastructure/activity/activityType.ts
export enum ActivityType {
  // ... existing types
  NewFeatureInteraction = 'new_feature_interaction'
}
```

2. **Create Analytics Command**:
```typescript
// src/infrastructure/activity/commands/newFeatureCommand.ts
export class NewFeatureAnalyticsCommand extends AnalyticsCommandBase {
  constructor(private featureData: any) {
    super(ActivityType.NewFeatureInteraction);
  }
  
  protected buildEventData(): any {
    return {
      feature_id: this.featureData.id,
      timestamp: Date.now()
    };
  }
}
```

3. **Track Event**:
```typescript
StorytellerDelegate.sharedInstance.onUserActivityOccurred?.(
  ActivityType.NewFeatureInteraction,
  eventData
);
```

## Code Conventions & Best Practices

### Naming Conventions
- **Files**: camelCase (e.g., `storyView.tsx`, `storiesApiService.ts`)
- **Classes**: PascalCase with "Storyteller" prefix for public APIs
- **Interfaces**: PascalCase with "I" prefix (e.g., `IStorytellerTheme`)
- **Commands**: PascalCase with "Command" suffix
- **Services**: PascalCase with "Service" suffix

### Component Structure
```typescript
// 1. Imports
import { Component } from 'preact';

// 2. Interfaces/Types
interface IProps { }
interface IState { }

// 3. Component Class
export class MyComponent extends Component<IProps, IState> {
  // 4. Static properties
  // 5. Instance properties
  // 6. Constructor
  // 7. Lifecycle methods
  // 8. Event handlers
  // 9. Helper methods
  // 10. Render method
}
```

### Error Handling
```typescript
try {
  const result = await apiCall();
  return result;
} catch (error) {
  this.logError('Failed to fetch data', error);
  // Graceful degradation
  return defaultValue;
}
```

### Performance Guidelines
- Use Preact instead of React (already aliased)
- Implement proper memoization for expensive operations
- Use CSS modules for styling (`.module.scss` files, no runtime style calculations)
- Lazy load external dependencies (e.g., HLS.js)
- Cache API responses when appropriate

### Security Considerations
- Never log sensitive data (user tokens, personal information)
- Sanitize user inputs before API calls
- Use HTTPS for all external requests
- Implement proper CORS handling
- Respect user privacy settings

## Testing Strategy

### Unit Tests
Location: Alongside source files as `*.spec.ts`
```typescript
// src/stories/storiesApiService.spec.ts
describe('StoriesApiService', () => {
  it('should fetch stories', async () => {
    const stories = await service.getStories();
    expect(stories).toBeDefined();
  });
});
```

### Running Tests
```bash
# Run all tests
npm test

# Run with coverage
npm test -- --coverage

# Run specific test file
npm test -- storiesApiService.spec.ts
```

### Test Utilities
- Jest with TypeScript support
- Canvas mocking for rendering tests
- Custom test setup in package.json globals

## Build System

### Build Targets

1. **Development Build** (`npm run watch`)
   - Source maps enabled
   - No minification
   - Hot module replacement
   - Faster builds

2. **Production Web Build** (`npm run build`)
   - Minified and optimized
   - No source maps
   - Tree shaking enabled
   - For direct browser inclusion

3. **NPM Package Build** (`npm run build:npm`)
   - CommonJS output
   - TypeScript declarations
   - For use with bundlers

### Webpack Configuration
- **Common**: Shared configuration, Preact aliasing
- **Dev**: Development server, source maps
- **Prod**: Optimization, minification
- **NPM**: Library output, externals

### Bundle Analysis
```bash
npm run analyze:npm
# Opens visual bundle analyzer
```

## Demo Site Development

### Structure
```
demo/
├── src/
│   ├── app/          # Next.js app directory
│   ├── components/   # React components
│   │   ├── atoms/    # Basic components
│   │   └── containers/ # Complex components
│   ├── contexts/     # React contexts
│   ├── data/         # Demo configurations
│   └── helpers/      # Utility functions
```

### Testing SDK Changes
1. SDK auto-rebuilds on file changes
2. Demo site hot-reloads
3. Check console for SDK logs
4. Use React DevTools to inspect components

### Common Demo Tasks
- Change theme: Modify `demo/src/data/customThemes.ts`
- Add test content: Update API environment
- Test delegates: Edit `demo/src/components/containers/Demo.tsx`

## Troubleshooting Guide

### Common Issues

#### SDK Not Loading
```javascript
// Check if SDK is initialized
console.log(Storyteller.sharedInstance.isInitialized);

// Verify API key
localStorage.getItem('API_KEY');
```

#### Stories Not Showing
1. Check API environment
2. Verify category exists
3. Check console for API errors
4. Ensure content is scheduled

#### Theme Not Applying
```javascript
// Force theme refresh
Storyteller.sharedInstance.theme.update(newTheme);
```

#### Build Failures
```bash
# Clean and rebuild
npm run clean-dist
npm run build

# Check for circular dependencies
# (Build will fail if found)
```

### Debug Mode
Enable verbose logging:
```javascript
localStorage.setItem('DEBUG_MODE', 'true');
```

## Performance Optimization

### Bundle Size Optimization
- Use Preact (saves ~30KB vs React)
- Dynamic imports for large features
- Tree shaking in production builds
- CSS modules prevent duplicate styles

### Runtime Performance
- Virtual scrolling for large lists
- Image lazy loading
- Debounced API calls
- Cached API responses

### Memory Management
- Proper cleanup in componentWillUnmount
- Remove event listeners
- Clear timers and intervals
- Dispose of video players

## Integration Guidelines

### Basic Integration
```html
<!-- Include SDK -->
<script src="https://cdn.storyteller.io/storyteller.min.js"></script>
<link rel="stylesheet" href="https://cdn.storyteller.io/storyteller.min.css">

<!-- Initialize -->
<script>
  const storyteller = new Storyteller.Storyteller('api-key');
  
  // Create row view
  const rowView = new Storyteller.StorytellerStoriesRowView();
  document.getElementById('stories').appendChild(rowView.render());
</script>
```

### React Integration
```typescript
import { Storyteller, StorytellerStoriesRowView } from '@getstoryteller/storyteller-sdk-javascript';

function App() {
  useEffect(() => {
    const storyteller = Storyteller.sharedInstance;
    storyteller.initialize('api-key');
  }, []);
  
  return <div id="stories-container" />;
}
```

### Delegate Implementation
```typescript
StorytellerDelegate.sharedInstance.onUserActivityOccurred = (type, data) => {
  // Send to analytics service
  analytics.track(type, data);
};

StorytellerDelegate.sharedInstance.onShareButtonTapped = async (text, title, url) => {
  // Custom share implementation
  await navigator.share({ text, title, url });
};
```

## Security Guidelines

### API Key Management
- Never commit API keys
- Use environment variables
- Rotate keys regularly
- Implement key restrictions

### Content Security Policy
```html
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; 
               script-src 'self' https://cdn.storyteller.io; 
               style-src 'self' 'unsafe-inline' https://cdn.storyteller.io;">
```

### Data Privacy
- Respect user privacy settings
- Implement GDPR compliance
- Clear storage on user request
- Anonymize analytics data

## Useful Commands Reference

### Development
- `npm run start` - Start full development environment
- `npm run watch` - Watch SDK only
- `npm run dev:demo-site` - Run demo site only
- `npm run dev:serve-sdk` - Serve SDK locally

### Building
- `npm run build` - Production web build
- `npm run build:npm` - NPM package build
- `npm run build:prod:sdk-and-demo` - Build everything

### Quality
- `npm run lint` - Check code quality
- `npm run lint:fix` - Auto-fix issues
- `npm test` - Run tests
- `npm run analyze:npm` - Analyze bundle

### Utilities
- `npm run clean-dist` - Clean build directory
- `git status` - Check changes
- `git diff` - Review changes

## Important Files & Locations

### Core SDK
- `src/storyteller.tsx` - Main SDK class
- `src/index.ts` - Public API exports
- `src/index.npm.ts` - NPM package wrapper (re-exports index.ts)
- `src/configuration/` - Configuration models
- `src/infrastructure/` - Core services

### Components
- `src/row/` - List view components
- `src/storyView/` - Story player
- `src/clipsView/` - Clips player

### Configuration
- `webpack.*.cjs` - Build configs
- `tsconfig.json` - TypeScript config
- `package.json` - Dependencies & scripts
- `.eslintrc.cjs` - Linting rules

### Documentation
- `docs/` - User documentation
- `README.md` - NPM readme
- `.github/README.md` - GitHub readme

## Notes for AI Assistants

When working with this codebase:

1. **Always use existing patterns** - Don't introduce new architectural patterns without strong justification
2. **Check for existing implementations** - Many features have established patterns to follow
3. **Use the demo site for testing** - It's the fastest way to verify changes
4. **Follow the service layer architecture** - Don't bypass service layers for direct API calls
5. **Respect the singleton pattern** - Don't create new instances of singleton services
6. **Maintain backward compatibility** - This is a public SDK, breaking changes affect users
7. **Update tests when changing code** - Even though test coverage is limited, maintain what exists
8. **Use TypeScript strictly** - Don't use `any` type unless absolutely necessary
9. **Consider bundle size** - This SDK is included in customer websites, size matters
10. **Document public APIs** - Add JSDoc comments to exported classes and methods

## Version Information

- Current Version: 10.12.1
- Node Version: 16.20.2 (via Volta)
- TypeScript: 4.2.3
- Webpack: 5.66.0
- Preact: 10.16.0 (aliased as React)