npm package: @merittdev/sdk
Description: SDK for Meritt Engine content management with Firebase integration
Author: Meritt Dev Team
Latest version: 0.1.3

# Meritt SDK - Development Context & Architecture

[![Quality Pipeline](https://github.com/Mhmdhammoud/meritt-dev-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/Mhmdhammoud/meritt-dev-sdk/actions/workflows/ci.yml)
This document provides comprehensive context about the Meritt SDK development, architectural decisions, and implementation details for future reference.

## Project Overview

**Name:** `@merittdev/sdk`  
**Purpose:** A powerful SDK for Meritt Engine content management with Firebase integration  
**Architecture:** Provider-only React SDK with TypeScript  
**State Management:** Zustand stores  
**Database:** Firebase Firestore

## Key Architectural Decisions

### 1. Provider-Only Architecture (Final Decision)

**Decision:** Use React Provider pattern exclusively, removing global `initializeSDK()` function.

**Rationale:**

- ✅ Cleaner API - just wrap with provider
- ✅ Multiple instances support (multi-tenant apps)
- ✅ Better testing - easy to mock with different configs
- ✅ React-first approach - follows React patterns
- ✅ Type safety - hooks require provider context
- ✅ Clear error handling - helpful errors if provider missing

**Implementation:**

```tsx
// Client usage
;<MerittProvider config={firebaseConfig}>
  <App />
</MerittProvider>

// Inside components
const { products, loading } = useProducts({ featured: true })
```

**Alternative Considered:** Hybrid approach with both `initializeSDK()` and provider, but rejected for complexity.

### 2. Firebase Instance Management

**Decision:** Each provider creates its own Firebase app instance with unique names.

**Implementation:**

- Provider creates Firebase app with namespace: `meritt-${namespace}` or `meritt-default`
- Firebase instances (db, auth, storage) passed to all store methods
- No global Firebase state - everything context-based

**Benefits:**

- Multiple Firebase projects in same app
- Isolated instances for testing
- No singleton issues

### 3. Store Architecture

**Decision:** Zustand stores that accept Firebase instances as parameters.

**Pattern:**

```typescript
// Store method signature
fetchProducts: (options: ProductQueryOptions, firebase: FirebaseInstances) =>
  Promise<Product[]>

// Hook usage
const { firebase } = useMerittContext()
await fetchProducts(options, firebase)
```

**Benefits:**

- Works with provider pattern
- Testable with mock Firebase instances
- No global dependencies

### 4. Firestore Indexes Strategy

**Decision:** Include `firestore.indexes.json` file in npm package for manual deployment.

**Alternatives Considered:**

1. ❌ Automated setup script - too complex
2. ❌ Manual console creation - too error-prone
3. ✅ JSON file + Firebase CLI - simple and standard

**Client Setup:**

```bash
cp node_modules/@merittdev/sdk/firestore.indexes.json .
firebase deploy --only firestore:indexes
```

## File Structure

```
src/
├── index.ts                    # Main exports
├── providers/
│   └── MerittProvider.tsx     # React provider + context hooks
├── hooks/
│   ├── useProducts.ts         # Product management hook
│   ├── useMedia.ts           # Media management hook
│   ├── useUpload.ts          # File upload hook
│   ├── useSettings.ts        # Settings management hook
│   ├── useCategories.ts      # Categories management hook
│   └── useCart.ts            # Shopping cart hook
├── stores/
│   ├── productStore.ts       # Zustand product store
│   ├── mediaStore.ts         # Zustand media store
│   ├── settingsStore.ts      # Zustand settings store
│   └── cartStore.ts          # Zustand cart store
├── services/
│   ├── productService.ts     # Direct Firebase product operations
│   └── categoryService.ts    # Direct Firebase category operations
├── utils/
│   ├── firebaseContext.ts    # Firebase instance utilities
│   ├── contentUtils.ts       # Content/Firestore utilities
│   ├── mediaUtils.ts         # Media/file utilities
│   ├── formatters.ts         # Text and data formatting utilities
│   └── cartUtils.ts          # Shopping cart utilities
├── config/
│   └── firebase.ts           # Firebase configuration
└── types.ts                  # TypeScript type definitions

firestore.indexes.json         # Firestore composite indexes
package.json                   # NPM package configuration
README.md                     # User documentation
```

## Core Components

### MerittProvider

**Purpose:** Initialize Firebase and provide context to child components.

**Key Features:**

- Creates unique Firebase app instances
- Provides Firebase instances to hooks
- Handles initialization state and errors
- Supports multiple instances with namespaces

**Exports:**

- `MerittProvider` - Main provider component
- `useMerittContext()` - Access provider context
- `useFirebaseInstances()` - Direct Firebase access

### Content Hooks

**Available Hooks:**

- `useProducts(options)` - Product management
- `useMedia(options)` - Media management
- `useUpload()` - File upload functionality
- `useSettings(options)` - Settings management
- `useCategories(options)` - Category management
- `useCart(options)` - Shopping cart functionality

**Pattern:**

- All hooks require MerittProvider
- Get Firebase instances from context
- Pass instances to store methods
- Handle loading/error states

### Zustand Stores

**Architecture:**

- Store methods accept Firebase instances as parameters
- No global Firebase dependencies
- Maintain local state (products, loading, error)
- Provide CRUD operations

**Example Store Method:**

```typescript
fetchProducts: async (
  options: ProductQueryOptions,
  firebase: FirebaseInstances,
) => {
  // Use firebase.db for Firestore operations
  // Update store state
  // Return results
}
```

## Type System

### Core Types

**Content Types:**

- `Product` - E-commerce product
- `Article` - Blog article
- `PortfolioProject` - Portfolio project
- `Media` - Media asset
- `Category` - Content category
- `Order` - E-commerce order
- `Cart` - Shopping cart
- `CartItem` - Shopping cart item

**Query Types:**

- `ProductQueryOptions` - Product filtering options
- `MediaQueryOptions` - Media filtering options
- `ArticleQueryOptions` - Article filtering options
- `PortfolioProjectQueryOptions` - Portfolio project filtering options
- `CartQueryOptions` - Cart filtering options
- `SettingsQueryOptions` - Settings filtering options

**Firebase Types:**

- `FirebaseInstances` - Firebase service instances
- `MerittConfig` - Firebase configuration

**Project Generator Types:**

- `ProjectConfiguration` - Complete project configuration
- `ProjectMetadata` - Project metadata
- `PageDefinition` - Page definition
- `ComponentPlacement` - Component placement
- `SectionSelection` - Section selection
- `ThemeConfiguration` - Theme configuration
- `SiteConfiguration` - Site configuration
- `ComponentMapping` - Component mapping
- `GenerationOptions` - Generation options
- `GeneratedFile` - Generated file
- `GenerationResult` - Generation result
- `GenerationSummary` - Generation summary
- `TemplateContext` - Template context
- `ComponentInstance` - Component instance

## Firestore Schema

### Collections

**Products Collection:**

```typescript
{
  id: string;
  name: string;
  slug: string;
  price: number;
  salePrice?: number;
  description: string;
  shortDescription?: string;
  images: string[];
  categories: string[];
  tags?: string[];
  inStock: boolean;
  quantity?: number;
  variants?: ProductVariant[];
  attributes?: Record<string, string>;
  featured?: boolean;
  relatedProducts?: string[];
  createdAt: Timestamp;
  updatedAt: Timestamp;
}
```

**Articles Collection:**

```typescript
{
  id: string;
  title: string;
  slug: string;
  content: string;
  excerpt?: string;
  coverImage?: string;
  author: string;
  publishedDate: Timestamp;
  categories: string[];
  tags?: string[];
  isPublished: boolean;
  isFeatured?: boolean;
  readTime?: number;
  createdAt: Timestamp;
  updatedAt: Timestamp;
}
```

**Media Collection:**

```typescript
{
  id: string;
  fileName: string;
  fileType: string;
  fileSize: number;
  url: string;
  thumbnailUrl?: string;
  alt?: string;
  caption?: string;
  width?: number;
  height?: number;
  folder?: string;
  tags?: string[];
  createdAt: Timestamp;
  updatedAt: Timestamp;
}
```

**Categories Collection:**

```typescript
{
  id: string;
  name: string;
  slug: string;
  description?: string;
  parentId?: string;
  image?: string;
  createdAt: Timestamp;
  updatedAt: Timestamp;
}
```

**Carts Collection:**

```typescript
{
  id: string;
  userId?: string;
  sessionId?: string;
  items: CartItem[];
  subtotal: number;
  itemCount: number;
  discount: number;
  discountCode?: string;
  currency: string;
  createdAt: Timestamp;
  updatedAt: Timestamp;
  expiresAt?: Timestamp;
}
```

**Settings Collection:**

```typescript
{
  id: string;
  theme: ThemeConfig;
  sidebarCollapsed: boolean;
  language: string;
  timezone: string;
  branding?: BrandingConfig;
  ui?: UIPreferences;
  localization?: LocalizationPreferences;
  notifications?: NotificationPreferences;
  security?: SecurityPreferences;
  projectInfo?: ProjectInfo;
}
```

### Required Indexes

**Products:**

- `featured + createdAt`
- `inStock + createdAt`
- `featured + inStock + createdAt`
- `categories (array-contains) + createdAt`
- `categories (array-contains) + featured + createdAt`

**Articles:**

- `isPublished + createdAt`
- `isFeatured + createdAt`
- `categories (array-contains) + isPublished + createdAt`

**Media:**

- `fileType + createdAt`
- `folder + createdAt`
- `tags (array-contains) + createdAt`

**Carts:**

- `userId + updatedAt`
- `sessionId + updatedAt`
- `expiresAt + updatedAt`

## Development Decisions Log

### Provider vs Initialize Function Debate

**Initial Approach:** Global `initializeSDK()` function
**Problem:** Not React-friendly, no multiple instances, testing issues
**Solution:** Provider-only architecture
**Result:** Cleaner, more flexible, better DX

### Store Parameter Passing

**Challenge:** How to get Firebase instances to stores?
**Options:**

1. Global Firebase instances (rejected - not provider-friendly)
2. Store methods accept Firebase parameters (chosen)
3. Context-aware stores (rejected - too complex)

**Implementation:** All store methods accept `firebase: FirebaseInstances` parameter

### Index Management Strategy

**Challenge:** How to handle Firestore composite indexes?
**Options:**

1. Automated script with deployment (rejected - too complex)
2. Manual console creation (rejected - error-prone)
3. JSON file + Firebase CLI (chosen - simple, standard)

**Result:** Include `firestore.indexes.json` in package, document copy+deploy process

### Shopping Cart Implementation

**Challenge:** How to handle guest carts vs user carts?
**Solution:**

- Use `userId` for logged-in users
- Use `sessionId` for guest users
- Merge carts on login

**Implementation:**

- Flexible cart store with session management
- Cart persistence in Firestore
- Cart expiration for guest carts

### Error Handling Philosophy

**Approach:** Fail fast with helpful error messages
**Examples:**

- Hook used outside provider: Clear error with setup instructions
- Firebase not initialized: Specific error about provider setup
- Missing indexes: Point to documentation

## Testing Strategy

### Local Development

**Setup:**

```bash
npm link                    # In SDK directory
cd /path/to/test-project
npm link @merittdev/sdk   # In test project
```

**Test Pattern:**

```tsx
<MerittProvider config={testFirebaseConfig}>
  <TestComponent />
</MerittProvider>
```

### Multiple Instances Testing

```tsx
<MerittProvider config={tenant1Config} namespace="tenant1">
  <TenantApp />
</MerittProvider>
<MerittProvider config={tenant2Config} namespace="tenant2">
  <TenantApp />
</MerittProvider>
```

## Performance Considerations

### Query Optimization

- All queries use composite indexes
- Pagination with `startAfter` cursors
- Limit queries to reasonable sizes
- Cache results in Zustand stores

### Firebase Optimization

- Unique app names prevent conflicts
- Minimal Firebase SDK imports
- Efficient query patterns

## Project Generator

The SDK includes a powerful project generator for creating new Meritt Engine projects.

**Key Features:**

- Dynamic page generation based on project configuration
- Component selection and customization
- Theme configuration
- Firebase integration
- TypeScript type safety

**Generation Process:**

1. Load project configuration from Firestore
2. Process component selections and customizations
3. Generate files based on templates
4. Apply customizations to components
5. Set up Firebase configuration
6. Generate necessary configuration files

## E-commerce Features

The SDK provides comprehensive e-commerce functionality:

**Product Management:**

- Product CRUD operations
- Product variants
- Product categories
- Product search and filtering

**Shopping Cart:**

- Add to cart
- Update cart items
- Remove from cart
- Cart persistence
- Guest carts
- Cart merging on login
- Cart expiration

**Order Processing:**

- Order creation
- Order status management
- Order history

## Future Considerations

### Potential Enhancements

1. **Offline Support:** Add Firebase offline persistence
2. **Real-time Updates:** WebSocket/Firestore listeners
3. **Caching Strategy:** More sophisticated caching
4. **Authentication:** Built-in auth hooks
5. **File Upload:** Progress tracking, resumable uploads
6. **Analytics Integration:** User behavior tracking
7. **Payment Processing:** Integration with payment gateways
8. **Internationalization:** Multi-language support
9. **Advanced Search:** Full-text search capabilities
10. **Webhooks:** Event-driven integrations

### Breaking Changes to Avoid

- Don't change store method signatures
- Don't remove provider pattern
- Don't change core type definitions
- Don't modify index requirements without migration

## Troubleshooting Guide

### Common Issues

**"useMerittContext must be used within a MerittProvider"**

- Solution: Wrap app with `<MerittProvider>`

**"Firebase not initialized"**

- Solution: Check provider config, ensure valid Firebase credentials

**"Index not found" errors**

- Solution: Deploy `firestore.indexes.json` file

**Products not loading**

- Check: Firebase config, indexes deployed, documents exist, console errors

### Debug Steps

1. Check provider setup and config
2. Verify Firebase project access
3. Confirm indexes are built
4. Check browser console for errors
5. Verify document structure matches types

## Deployment Checklist

### Before Publishing

- [ ] Run `npm run build`
- [ ] Test with `npm link` in real project
- [ ] Verify `firestore.indexes.json` included
- [ ] Update version in `package.json`
- [ ] Update README if needed
- [ ] Test index deployment process

### Publishing

```bash
npm run build
npm publish
```

### Post-Publishing

- [ ] Test installation: `npm install @merittdev/sdk`
- [ ] Verify files included in package
- [ ] Test index setup process
- [ ] Update documentation if needed

## Integration with Meritt Engine Dashboard

The SDK is designed to work seamlessly with the Meritt Engine Dashboard:

**Dashboard Features:**

- Visual interface for content management
- Real-time data synchronization
- User authentication and authorization
- File upload and management
- Analytics and reporting
- Settings management

**Integration Points:**

- SDK provides data layer for dashboard
- Dashboard uses SDK hooks for data fetching
- Dashboard uses SDK types for type safety
- Dashboard uses SDK utilities for formatting and validation

## Contact & Support

**Repository:** https://github.com/merittdev/sdk  
**Issues:** https://github.com/merittdev/sdk/issues  
**Support:** support@meritt.dev

---

_This document should be updated whenever significant architectural decisions are made or implementation details change._