# Execution Plan: Refactor Share Page and Enhance Thumbnails
**Outcome Name:** RefactorSharePageAndEnhanceThumbnails
**Created:** 2025-12-21
**Status:** Ready for Implementation
---
## Overview
This plan addresses three key improvements to the InstaChef PWA:
1. **Component Modularization**: Split the monolithic 306-line share page into focused, reusable components
2. **LLM Health Monitoring**: Add visual health status indicator for the LLM service
3. **Stealthy Thumbnail Extraction**: Enhance thumbnail extraction with Instagram-friendly stealth techniques
---
## Problem Statement
### Current Issues
1. **Share Page Complexity**: The `+page.svelte` file contains 306 lines with mixed concerns (state management, UI rendering, business logic), making it difficult to maintain and test
2. **No LLM Visibility**: Users have no way to know if the LLM service is healthy before attempting extraction
3. **Basic Thumbnail Extraction**: Current screenshot-based approach is detectable and may trigger Instagram's anti-bot measures
### User Impact
- Difficult to maintain and extend the share page functionality
- Poor user experience when LLM service is down (only discover during extraction)
- Risk of Instagram blocking due to detectable automation patterns
---
## Technical Context
### Current Architecture
**Frontend:**
- Svelte 5.43.8 with modern runes (`$state`, `$derived`, `$effect`)
- TailwindCSS 4.1.17 for styling
- Share page uses snippets for UI modularity
**Backend:**
- Playwright 1.56.1 for browser automation
- Existing `/api/llm-health` endpoint for service monitoring
- `extractThumbnail()` function uses screenshot-based approach
### Hexagonal Architecture Alignment
- **Domain**: extraction.ts contains business logic for thumbnail extraction
- **Adapters**:
- Primary (Driving): Svelte components, API routes
- Secondary (Driven): Playwright Page interface
- **Ports**: Clear interfaces between components and domain logic
---
## Stories
### Story 1: Refactor Share Page into Modular Components
**Priority:** High
**Complexity:** Medium
**Estimated Effort:** 4 hours
#### Description
Extract the current snippets from `+page.svelte` into standalone, reusable Svelte components. This improves maintainability, testability, and follows single responsibility principle.
#### Acceptance Criteria
- [ ] Create `src/routes/share/components/` directory
- [ ] Extract 6 components from current snippets:
1. `UrlInputSection.svelte` - URL input and extraction trigger
2. `ProgressIndicator.svelte` - Loading state display
3. `ExtractedTextViewer.svelte` - Collapsible text preview
4. `RecipeCard.svelte` - Recipe display with Tandoor integration
5. `ErrorState.svelte` - Error handling UI
6. `LogViewer.svelte` - System logs display
- [ ] Parent `+page.svelte` orchestrates state and passes props to components
- [ ] Reduced `+page.svelte` from 306 to ~100 lines
- [ ] All components use Svelte 5 runes (`$state`, `$props`)
- [ ] Maintain existing functionality with no regressions
- [ ] TailwindCSS styling preserved
#### Technical Specifications
**Component Interfaces:**
```typescript
// UrlInputSection.svelte
interface Props {
targetUrl: string | null;
sharedText: string;
sharedUrl: string;
status: string;
onProcess: () => void;
}
// ProgressIndicator.svelte
interface Props {
status: string;
}
// ExtractedTextViewer.svelte
interface Props {
bodyText: string;
}
// RecipeCard.svelte
interface Props {
recipe: Recipe | null;
tandoorEnabled: boolean;
tandoorImporting: boolean;
tandoorError: string | null;
onRetry: () => void;
onImportToTandoor: () => void;
}
// ErrorState.svelte
interface Props {
status: string;
bodyText: string;
onRetry: () => void;
}
// LogViewer.svelte
interface Props {
logs: string[];
currentMethod: string;
status: string;
}
```
#### Implementation Steps
1. Create `src/routes/share/components/` directory
2. For each component:
- Create new `.svelte` file
- Extract relevant snippet code
- Define props interface using `let { prop1, prop2 } = $props()`
- Convert callbacks to prop functions
- Preserve TailwindCSS classes
3. Update `+page.svelte`:
- Import all components
- Remove snippet definitions
- Replace `{@render snippet()}` with `