Skip to content

Data Flow

This document provides an overview of data flow concepts in the content system. Data flow refers to how content moves through the system, from storage to presentation and back, including transformations, event propagation, and state management.

Core Data Flow Principles

The content system follows several key principles for data flow:

  1. Unidirectional Flow: Data generally flows in one direction, from storage through transformations to presentation
  2. Immutability: Content objects are treated as immutable to prevent unexpected side effects
  3. Explicit Transformations: All changes to content happen through explicit transformation steps
  4. Reactive Updates: Changes trigger events that allow reactive updates to dependent components
  5. Predictable Operations: Content operations follow a consistent pattern with predictable lifecycle

Data Flow Overview

At a high level, the content system data flow consists of several key stages:

Storage Layer → Adapter Layer → Middleware Layer → Store Layer → Application Layer

Content Reading Flow

When reading content, data flows through these stages:

  1. Storage Retrieval: Physical content is retrieved from storage (filesystem, database, API)
  2. Adapter Processing: Adapter converts raw data to standardized Content objects
  3. Middleware Processing: Middleware pipeline applies transformations and enhancements
  4. Store Processing: Content store applies additional operations (caching, normalization)
  5. Application Usage: Application components consume and render content

Content Writing Flow

When writing content, data flows in the reverse direction:

  1. Application Input: Application generates or modifies content
  2. Store Processing: Content store validates and prepares content
  3. Middleware Processing: Middleware pipeline applies transformations
  4. Adapter Processing: Adapter converts Content objects to storage format
  5. Storage Persistence: Physical content is saved to storage

Key Data Flow Concepts

Content Operations

Content operations are the primary method for data flow in the system:

  • read: Retrieve content from storage and process it
  • write: Process content and save it to storage
  • delete: Remove content from storage
  • list: Retrieve a list of available content
  • exists: Check if content exists in storage
  • watch: Observe changes to content

Each operation follows a defined lifecycle with hooks for customization.

Learn more about content operations

Content Transformation

Content undergoes transformations as it flows through the system:

  • Parsing: Convert raw storage format to structured content
  • Validation: Ensure content meets schema requirements
  • Normalization: Standardize content structure and metadata
  • Enrichment: Add derived or computed properties
  • Formatting: Convert content for specific display needs
  • Serialization: Convert structured content to storage format

Transformations maintain content immutability by returning new instances.

Learn more about content transformation

Event Propagation

Changes to content trigger events that propagate through the system:

  • Change Events: Notify about content creation, updates, and deletion
  • Error Events: Signal issues during content operations
  • Lifecycle Events: Indicate operation progress and completion
  • Observation Events: Notify about external changes to content

Events enable reactive updates and synchronization across components.

Learn more about the event system

Data Flow Patterns

Repository Pattern

The content store implements the repository pattern, providing a higher-level abstraction over storage:

typescript
// Repository pattern with content store
const store = createContentStore({
  adapter: createFileSystemAdapter({ basePath: '/content' }),
})

// Higher-level operations
const content = await store.read('articles/welcome.md')
await store.write('articles/welcome.md', updatedContent)

Middleware Pattern

The middleware pattern enables composable processing stages:

typescript
// Middleware chain for content processing
const store = createContentStore({
  middleware: [
    cacheMiddleware({ ttl: 3600 }),
    validationMiddleware({ schema }),
    transformMiddleware({ transforms }),
    loggingMiddleware({ level: 'info' }),
  ],
})

Observer Pattern

The observer pattern enables reactive updates:

typescript
// Observe content changes
const unsubscribe = store.watch('articles/*.md', (uri, content, changeType) => {
  console.log(`Content ${changeType}: ${uri}`)

  if (content) {
    // Update application state with new content
    updateState(uri, content)
  }
})

Pipeline Pattern

The pipeline pattern enables sequential processing:

typescript
// Content transformation pipeline
const transformContent = pipe(
  parseMarkdown,
  extractFrontmatter,
  validateSchema,
  applyTheme,
  generateToc
)

// Apply transformation
const transformedContent = await transformContent(rawContent)

Data Flow Through Layers

Adapter Layer Flow

The adapter layer handles the transformation between storage formats and Content objects:

Storage Format → Parse → Normalize → Content
Content → Serialize → Normalize → Storage Format

Middleware Layer Flow

The middleware layer applies transformations and cross-cutting concerns:

Context → Middleware 1 → Middleware 2 → ... → Middleware N → Result

Each middleware can modify the context before and after subsequent middleware.

Store Layer Flow

The store layer coordinates operations and manages caching:

Operation Request → Validate → Cache Check → Adapter Operation → Process Result → Return

Application Layer Flow

The application layer renders and interacts with content:

Content → Component Props → Render → User Interaction → Update → Write

Environment-Specific Data Flow

Node.js (Server)

In Node.js environments, data often flows from filesystem to HTTP responses:

Filesystem → Adapter → Store → HTTP Response

Browser

In browser environments, data often flows from HTTP requests to DOM:

HTTP Request → Adapter → Store → React Components → DOM

Isomorphic Flow

Isomorphic applications share data flow patterns across environments:

Storage → Content Store → UI Components → User Interaction → Content Store → Storage

Data Flow Optimization

Caching Strategies

Caching optimizes data flow by storing frequently accessed content:

  • Memory Cache: Store content in memory for fastest access
  • Persistent Cache: Store content in IndexedDB or localStorage
  • HTTP Cache: Leverage browser cache for remote content
  • Cache Invalidation: Clear cache when content changes

Lazy Loading

Lazy loading optimizes data flow by loading content on demand:

typescript
// Lazy loading with content fragments
const article = await store.read('articles/long-article.md', {
  lazyLoadSections: true,
})

// Later, load specific section
const section = await article.loadSection('introduction')

Batching

Batching optimizes data flow by combining multiple operations:

typescript
// Batch multiple read operations
const [article, sidebar, comments] = await store.batchRead([
  'articles/welcome.md',
  'components/sidebar.md',
  'comments/welcome.md',
])

Released under the MIT License.