Template Component Architecture
Overview
The MyStoryFlow Template Component Architecture implements a “Lego Pieces” system where content templates are built from reusable, modular components that can be composed into pages, chapters, and complete books.
Three-Tier Component System
Tier 1: Page Components (Atomic Level)
Page components are the smallest building blocks - individual content units that users fill out.
interface PageComponent {
id: string
name: string
description: string
category: 'text' | 'media' | 'interactive' | 'special' | 'design'
version: string
// Component definition
schema: ComponentSchema
prompts: string[]
defaultContent: Record<string, unknown>
// Publishing metadata
formatOptions: {
pdf: FormatConfig
epub: FormatConfig
kdp: FormatConfig
}
// Validation rules
validation: ValidationRules
dependencies?: string[] // Required components
// Usage tracking
usage_count: number
is_public: boolean
creator_id?: string
created_at: string
updated_at: string
}Example Page Components
PersonalInfoPage
{
id: 'personal-info-page',
name: 'Personal Information',
description: 'Basic personal details with photo',
category: 'text',
schema: {
fields: [
{ name: 'full_name', type: 'text', required: true },
{ name: 'birth_date', type: 'date', required: false },
{ name: 'birth_place', type: 'text', required: false },
{ name: 'photo', type: 'image', required: false },
{ name: 'bio_summary', type: 'rich_text', required: true }
]
},
prompts: [
'What would you like people to know about you?',
'What makes you unique?',
'What are you most proud of?'
],
defaultContent: {
full_name: '',
bio_summary: '<p>Tell us about yourself...</p>'
}
}TimelinePage
{
id: 'timeline-page',
name: 'Timeline Events',
description: 'Chronological list of important events',
category: 'interactive',
schema: {
fields: [
{ name: 'title', type: 'text', required: true },
{ name: 'events', type: 'array', required: true, itemSchema: {
date: { type: 'date', required: true },
event: { type: 'text', required: true },
description: { type: 'rich_text', required: false },
importance: { type: 'select', options: ['high', 'medium', 'low'] }
}}
]
},
prompts: [
'What were the most important events in your life?',
'What moments changed your direction?',
'What achievements are you most proud of?'
]
}Tier 2: Chapter Components (Molecular Level)
Chapter components are logical groupings of page components with narrative flow.
interface ChapterComponent {
id: string
name: string
description: string
category: 'life-events' | 'relationships' | 'historical' | 'creative' | 'memorial'
// Component composition
page_components: PageComponentReference[]
flow_config: ChapterFlowConfig
// Narrative structure
narrative_arc: 'chronological' | 'thematic' | 'problem-solution' | 'journey'
estimated_length: {
word_count: number
page_count: number
time_to_complete: number // minutes
}
// Chapter metadata
chapter_settings: {
include_in_toc: boolean
page_break_before: boolean
chapter_number_style: 'numeric' | 'roman' | 'none'
header_footer_style: string
}
// Template metadata
version: string
usage_count: number
is_public: boolean
creator_id?: string
created_at: string
updated_at: string
}
interface PageComponentReference {
component_id: string
position: number
is_required: boolean
customizations?: Record<string, unknown>
conditional_logic?: ConditionalRule[]
}
interface ChapterFlowConfig {
introduction_prompt?: string
transition_prompts: string[]
conclusion_prompt?: string
navigation_style: 'linear' | 'branching' | 'freeform'
completion_criteria: CompletionRule[]
}Example Chapter Components
EarlyChildhoodChapter
{
id: 'early-childhood-chapter',
name: 'Early Childhood (0-5 years)',
description: 'Foundational years and first memories',
category: 'life-events',
page_components: [
{
component_id: 'personal-info-page',
position: 1,
is_required: true,
customizations: {
focus_age_range: '0-5',
prompts_override: [
'What are your earliest memories?',
'What stories did your family tell about your early years?'
]
}
},
{
component_id: 'timeline-page',
position: 2,
is_required: true,
customizations: {
title_default: 'Early Years Timeline',
event_categories: ['first_words', 'first_steps', 'family_moments']
}
},
{
component_id: 'photo-gallery-page',
position: 3,
is_required: false,
customizations: {
suggested_photos: ['baby_photos', 'family_photos', 'home_photos']
}
}
],
flow_config: {
introduction_prompt: 'Let\'s explore your earliest years and the foundation they laid for your life story.',
transition_prompts: [
'Now let\'s look at the important moments from this time period.',
'What photos capture these precious early memories?'
],
conclusion_prompt: 'How did these early experiences shape who you became?',
navigation_style: 'linear'
},
narrative_arc: 'chronological',
estimated_length: {
word_count: 2500,
page_count: 8,
time_to_complete: 90
}
}Tier 3: Template Components (Organism Level)
Template components are complete book/campaign structures using chapter components.
interface TemplateComponent {
id: string
name: string
description: string
category: 'memoir' | 'family_history' | 'cookbook' | 'photo_book' | 'custom'
// Template composition
chapter_components: ChapterComponentReference[]
special_sections: SpecialSectionReference[]
// Book structure
book_structure: {
front_matter: FrontMatterSection[]
main_content: MainContentSection[]
back_matter: BackMatterSection[]
}
// Publishing configuration
publishing_config: {
target_length: {
min_pages: number
max_pages: number
optimal_pages: number
}
pricing_tier: 'starter' | 'family' | 'premium'
kdp_settings: KDPConfiguration
export_formats: ('pdf' | 'epub' | 'print')[]
}
// User experience
completion_flow: {
estimated_duration_months: number
prompt_schedule: 'daily' | 'weekly' | 'self_paced'
milestone_celebrations: MilestoneConfig[]
}
// Template metadata
version: string
usage_count: number
is_featured: boolean
is_public: boolean
creator_id?: string
created_at: string
updated_at: string
}
interface ChapterComponentReference {
component_id: string
position: number
is_required: boolean
customizations?: Record<string, unknown>
conditional_logic?: ConditionalRule[]
chapter_title_override?: string
}Example Template Component
CompleteLifeJourneyTemplate
{
id: 'complete-life-journey-template',
name: 'Complete Life Journey',
description: 'Comprehensive life story from birth to present day',
category: 'memoir',
chapter_components: [
{
component_id: 'early-childhood-chapter',
position: 1,
is_required: true,
chapter_title_override: 'The Beginning (0-5 years)'
},
{
component_id: 'school-years-chapter',
position: 2,
is_required: true,
chapter_title_override: 'Learning and Growing (6-18 years)'
},
{
component_id: 'young-adulthood-chapter',
position: 3,
is_required: true,
chapter_title_override: 'Finding My Way (18-25 years)'
},
{
component_id: 'career-beginnings-chapter',
position: 4,
is_required: true
},
{
component_id: 'family-formation-chapter',
position: 5,
is_required: false,
conditional_logic: [
{
condition: 'has_family',
show_if: true
}
]
},
{
component_id: 'career-peak-chapter',
position: 6,
is_required: true
},
{
component_id: 'parenting-adventures-chapter',
position: 7,
is_required: false,
conditional_logic: [
{
condition: 'has_children',
show_if: true
}
]
},
{
component_id: 'community-friendships-chapter',
position: 8,
is_required: true
},
{
component_id: 'challenges-triumphs-chapter',
position: 9,
is_required: true
},
{
component_id: 'retirement-years-chapter',
position: 10,
is_required: false,
conditional_logic: [
{
condition: 'age_over_60',
show_if: true
}
]
},
{
component_id: 'wisdom-reflections-chapter',
position: 11,
is_required: true
},
{
component_id: 'legacy-messages-chapter',
position: 12,
is_required: true
}
],
special_sections: [
{
section_id: 'dedication-page',
position: 'front_matter',
is_required: false
},
{
section_id: 'family-tree-section',
position: 'back_matter',
is_required: false
},
{
section_id: 'photo-galleries',
position: 'throughout',
is_required: false
},
{
section_id: 'recipe-collection',
position: 'back_matter',
is_required: false
}
],
book_structure: {
front_matter: [
{ type: 'title_page', required: true },
{ type: 'dedication', required: false },
{ type: 'table_of_contents', required: true },
{ type: 'foreword', required: false }
],
main_content: [
{ type: 'chapter_content', required: true },
{ type: 'photo_inserts', required: false }
],
back_matter: [
{ type: 'acknowledgments', required: false },
{ type: 'family_tree', required: false },
{ type: 'recipe_collection', required: false },
{ type: 'about_author', required: true }
]
},
publishing_config: {
target_length: {
min_pages: 150,
max_pages: 300,
optimal_pages: 200
},
pricing_tier: 'premium',
export_formats: ['pdf', 'epub', 'print']
},
completion_flow: {
estimated_duration_months: 12,
prompt_schedule: 'weekly',
milestone_celebrations: [
{ at_chapter: 3, type: 'progress_celebration' },
{ at_chapter: 6, type: 'halfway_milestone' },
{ at_chapter: 9, type: 'final_stretch' },
{ at_completion: true, type: 'book_completion' }
]
}
}Database Schema
Core Tables
-- Page component definitions
CREATE TABLE page_components (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
description TEXT,
category TEXT CHECK (category IN ('text', 'media', 'interactive', 'special', 'design')),
version TEXT NOT NULL DEFAULT '1.0.0',
-- Component definition
schema JSONB NOT NULL,
prompts JSONB NOT NULL DEFAULT '[]',
default_content JSONB NOT NULL DEFAULT '{}',
-- Publishing metadata
format_options JSONB NOT NULL DEFAULT '{}',
validation_rules JSONB NOT NULL DEFAULT '{}',
dependencies JSONB DEFAULT '[]',
-- Metadata
usage_count INTEGER DEFAULT 0,
is_public BOOLEAN DEFAULT false,
creator_id UUID REFERENCES auth.users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Chapter component definitions
CREATE TABLE chapter_components (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
description TEXT,
category TEXT CHECK (category IN ('life-events', 'relationships', 'historical', 'creative', 'memorial')),
version TEXT NOT NULL DEFAULT '1.0.0',
-- Component composition
page_components JSONB NOT NULL DEFAULT '[]',
flow_config JSONB NOT NULL DEFAULT '{}',
-- Narrative structure
narrative_arc TEXT CHECK (narrative_arc IN ('chronological', 'thematic', 'problem-solution', 'journey')),
estimated_length JSONB NOT NULL DEFAULT '{}',
chapter_settings JSONB NOT NULL DEFAULT '{}',
-- Metadata
usage_count INTEGER DEFAULT 0,
is_public BOOLEAN DEFAULT false,
creator_id UUID REFERENCES auth.users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Template component definitions (enhanced book_templates)
CREATE TABLE template_components (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
description TEXT,
category TEXT CHECK (category IN ('memoir', 'family_history', 'cookbook', 'photo_book', 'custom')),
version TEXT NOT NULL DEFAULT '1.0.0',
-- Template composition
chapter_components JSONB NOT NULL DEFAULT '[]',
special_sections JSONB NOT NULL DEFAULT '[]',
book_structure JSONB NOT NULL DEFAULT '{}',
-- Publishing configuration
publishing_config JSONB NOT NULL DEFAULT '{}',
completion_flow JSONB NOT NULL DEFAULT '{}',
-- Metadata
usage_count INTEGER DEFAULT 0,
is_featured BOOLEAN DEFAULT false,
is_public BOOLEAN DEFAULT false,
creator_id UUID REFERENCES auth.users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- User customizations
CREATE TABLE user_customizations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES auth.users(id) NOT NULL,
component_type TEXT CHECK (component_type IN ('page', 'chapter', 'template')),
component_id UUID NOT NULL,
customizations JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(user_id, component_type, component_id)
);Relationship Tables
-- Campaign to template mapping
CREATE TABLE campaign_templates (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
campaign_template_id TEXT NOT NULL, -- from existing templates.ts
template_component_id UUID REFERENCES template_components(id),
mapping_config JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Book to template component usage
CREATE TABLE book_template_usage (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
book_id UUID REFERENCES books(id) ON DELETE CASCADE,
template_component_id UUID REFERENCES template_components(id),
customizations JSONB NOT NULL DEFAULT '{}',
completion_status JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);Component Registry System
Centralized Component Registry
class ComponentRegistry {
private static instance: ComponentRegistry
private pageComponents: Map<string, PageComponent> = new Map()
private chapterComponents: Map<string, ChapterComponent> = new Map()
private templateComponents: Map<string, TemplateComponent> = new Map()
static getInstance(): ComponentRegistry {
if (!ComponentRegistry.instance) {
ComponentRegistry.instance = new ComponentRegistry()
}
return ComponentRegistry.instance
}
// Page component methods
registerPageComponent(component: PageComponent): void {
this.pageComponents.set(component.id, component)
}
getPageComponent(id: string): PageComponent | undefined {
return this.pageComponents.get(id)
}
getPageComponentsByCategory(category: string): PageComponent[] {
return Array.from(this.pageComponents.values())
.filter(comp => comp.category === category)
}
// Chapter component methods
registerChapterComponent(component: ChapterComponent): void {
this.chapterComponents.set(component.id, component)
}
getChapterComponent(id: string): ChapterComponent | undefined {
return this.chapterComponents.get(id)
}
// Template component methods
registerTemplateComponent(component: TemplateComponent): void {
this.templateComponents.set(component.id, component)
}
getTemplateComponent(id: string): TemplateComponent | undefined {
return this.templateComponents.get(id)
}
// Component validation
validateComponent(component: any, type: 'page' | 'chapter' | 'template'): ValidationResult {
const schema = this.getValidationSchema(type)
return validateAgainstSchema(component, schema)
}
// Component dependency resolution
resolveDependencies(componentId: string, type: 'page' | 'chapter' | 'template'): string[] {
const component = this.getComponent(componentId, type)
if (!component) return []
return this.getDependencyTree(component)
}
}Component Builder Interface
interface ComponentBuilder {
// Page component builder
createPageComponent(config: PageComponentConfig): PageComponent
clonePageComponent(sourceId: string, modifications: Partial<PageComponent>): PageComponent
// Chapter component builder
createChapterComponent(config: ChapterComponentConfig): ChapterComponent
addPageToChapter(chapterId: string, pageId: string, position: number): void
reorderChapterPages(chapterId: string, newOrder: string[]): void
// Template component builder
createTemplateComponent(config: TemplateComponentConfig): TemplateComponent
addChapterToTemplate(templateId: string, chapterId: string, position: number): void
customizeTemplateForUser(templateId: string, userId: string, customizations: any): TemplateComponent
}Template Inheritance System
Component Versioning
interface ComponentVersion {
component_id: string
version: string
parent_version?: string
changes: ComponentChange[]
backward_compatible: boolean
migration_script?: string
created_at: string
created_by: string
}
interface ComponentChange {
type: 'field_added' | 'field_removed' | 'field_modified' | 'prompt_changed' | 'schema_updated'
field_path: string
old_value?: any
new_value?: any
breaking_change: boolean
}Template Customization
interface TemplateCustomization {
user_id: string
base_template_id: string
customization_name: string
modifications: {
chapters_added: ChapterModification[]
chapters_removed: string[]
chapters_reordered: string[]
chapter_customizations: Record<string, any>
page_customizations: Record<string, any>
global_settings: Record<string, any>
}
is_public: boolean
created_at: string
updated_at: string
}Component Marketplace
Public Component Sharing
interface ComponentMarketplace {
// Browse components
browsePageComponents(filter: ComponentFilter): PageComponent[]
browseChapterComponents(filter: ComponentFilter): ChapterComponent[]
browseTemplateComponents(filter: ComponentFilter): TemplateComponent[]
// Component ratings and reviews
rateComponent(componentId: string, rating: number, review?: string): void
getComponentRating(componentId: string): ComponentRating
// Usage analytics
trackComponentUsage(componentId: string, userId: string, context: string): void
getPopularComponents(category?: string, timeframe?: string): Component[]
// Component sharing
publishComponent(component: Component, visibility: 'public' | 'community' | 'private'): void
forkComponent(componentId: string, modifications: any): Component
}Integration with Existing Systems
Bridge to Current Templates
// Migration utility to convert existing templates
const migrateExistingTemplates = async () => {
const existingTemplates = await loadExistingTemplates()
for (const template of existingTemplates) {
const templateComponent = await convertToTemplateComponent(template)
await ComponentRegistry.getInstance().registerTemplateComponent(templateComponent)
}
}
// Convert campaign template to template component
const convertCampaignTemplate = (campaignTemplate: any): TemplateComponent => {
return {
id: `campaign-${campaignTemplate.id}`,
name: campaignTemplate.displayName,
description: campaignTemplate.description,
category: 'memoir', // default mapping
chapter_components: convertPromptsToChapters(campaignTemplate.samplePrompts),
// ... rest of conversion logic
}
}Content Migration Strategy
// Migrate existing content to component system
const migrateExistingContent = async (contentId: string, contentType: 'story' | 'chapter' | 'book') => {
const existingContent = await loadContent(contentId, contentType)
const componentStructure = await analyzeContentStructure(existingContent)
// Create component mapping
const componentMapping = await mapContentToComponents(componentStructure)
// Preserve original content
await preserveOriginalContent(contentId, existingContent)
// Apply component structure
await applyComponentStructure(contentId, componentMapping)
return componentMapping
}This modular component architecture provides the foundation for the “Lego Pieces” template system, enabling users to build custom books from reusable, standardized components while maintaining consistency and professional quality across all content types.