# InstaRecipe - Async Instagram Recipe Extractor A modern web application that extracts recipes from Instagram posts and saves them to Tandoor Recipe Manager using an async queue-based processing system. ## ๐Ÿš€ Features ### Core Functionality - **Async Queue Processing**: Fire-and-forget recipe extraction with background processing - **Real-time Updates**: Server-Sent Events for live progress tracking - **Push Notifications**: Background notifications when recipes complete - **Instagram Integration**: Extract recipes from Instagram posts and stories - **Tandoor Integration**: Automatic upload to Tandoor Recipe Manager - **PWA Support**: Installable Progressive Web App with offline capabilities ### User Experience - **Queue Dashboard**: Monitor all recipe extractions in real-time - **Share Integration**: Browser share target for easy URL submission - **Responsive Design**: Works on desktop, tablet, and mobile - **Error Recovery**: Retry failed extractions with one click - **Progress Tracking**: Visual progress through extraction phases ### Technical Architecture - **SvelteKit Frontend**: Modern reactive UI with TypeScript - **Hexagonal Architecture**: Clean separation of concerns - **In-Memory Queue**: High-performance processing with configurable concurrency - **Three-Phase Pipeline**: Extraction โ†’ Parsing โ†’ Uploading - **Comprehensive Testing**: 138 tests covering all components ## ๐Ÿ“‹ API Endpoints ### Queue Management - `POST /api/queue` - Enqueue Instagram URL for processing - `GET /api/queue` - List queue items with filtering and pagination - `GET /api/queue/{id}` - Get specific queue item details - `POST /api/queue/{id}/retry` - Retry failed item - `GET /api/queue/stream` - Server-Sent Events for real-time updates ### Push Notifications - `POST /api/notifications/subscribe` - Subscribe to push notifications - `DELETE /api/notifications/subscribe` - Unsubscribe from notifications - `GET /api/notifications/vapid-key` - Get VAPID public key ### Legacy Endpoints (Deprecated) - ~~`POST /api/extract`~~ - Use `/api/queue` instead - ~~`GET /api/extract-stream`~~ - Use `/api/queue/stream` instead ## ๐Ÿ›  Development Setup ### Prerequisites - Node.js 18+ - npm or pnpm - Tandoor Recipe Manager instance (optional) - LLM API access (OpenAI, Anthropic, or local) ### Installation ```bash # Clone the repository git clone cd insta-recipe # Install dependencies npm install # Copy environment template cp .env.example .env # Configure your environment variables (see Configuration section) ``` ### Local Development ```bash # Start development server with HTTPS npm run dev # Open in browser (certificate must be trusted) open https://localhost:5173 ``` The app runs on HTTPS by default for: - Service worker support (required for PWA) - Push notifications - Browser share target API - Instagram cookie handling ### SSL Certificate Setup The application uses HTTPS in development with SSL certificates signed by an external Caddy CA container. The current certificate is valid until **December 20, 2035** (10 years). **Certificate Information:** - Location: `.ssl/` directory - CA Certificate: `.ssl/root.crt` (already trusted on the system) - Server Certificate: `.ssl/localhost.crt` - Server Private Key: `.ssl/localhost.key` Since the Caddy CA is already trusted on the system, the certificate should work without additional trust steps. If you encounter browser warnings: **Linux (Ubuntu/Debian):** ```bash sudo cp .ssl/root.crt /usr/local/share/ca-certificates/caddy-local.crt sudo update-ca-certificates ``` **Chrome/Chromium:** 1. Go to `chrome://settings/certificates` 2. Click "Authorities" โ†’ "Import" 3. Select `.ssl/root.crt` 4. Check "Trust this certificate for identifying websites" **Checking Certificate Expiration:** ```bash openssl x509 -enddate -noout -in .ssl/localhost.crt ``` **Regenerating the Certificate (if needed):** If the certificate expires or needs to be regenerated: ```bash # Identify the Caddy container (usually named caddy-local) CADDY_CONTAINER="caddy-local" # Copy Caddy's CA certificate and private key docker cp $CADDY_CONTAINER:/data/caddy/pki/authorities/local/root.crt .ssl/root.crt docker cp $CADDY_CONTAINER:/data/caddy/pki/authorities/local/root.key .ssl/caddy-ca.key # Generate new server private key openssl genrsa -out .ssl/localhost.key 2048 # Generate Certificate Signing Request (CSR) openssl req -new \ -key .ssl/localhost.key \ -out .ssl/localhost.csr \ -subj "/O=Caddy Local Authority/CN=localhost" # Create OpenSSL config for Subject Alternative Names cat > .ssl/localhost.ext << 'EOF' authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1 = localhost DNS.2 = *.localhost IP.1 = 127.0.0.1 IP.2 = ::1 EOF # Sign certificate with Caddy's CA (10 years = 3650 days) openssl x509 -req \ -in .ssl/localhost.csr \ -CA .ssl/root.crt \ -CAkey .ssl/caddy-ca.key \ -CAcreateserial \ -out .ssl/localhost.crt \ -days 3650 \ -sha256 \ -extfile .ssl/localhost.ext # Cleanup temporary files and set permissions rm .ssl/localhost.csr .ssl/localhost.ext .ssl/caddy-ca.key .ssl/root.srl chmod 600 .ssl/localhost.key chmod 644 .ssl/localhost.crt .ssl/root.crt # Verify the certificate openssl verify -CAfile .ssl/root.crt .ssl/localhost.crt ``` ## โš™๏ธ Configuration ### Environment Variables Create a `.env` file with the following variables: ```env # LLM Configuration LLM_API_BASE_URL=https://api.openai.com/v1 LLM_API_KEY=your-api-key LLM_MODEL=gpt-4o-mini # Tandoor Integration (optional) TANDOOR_BASE_URL=https://your-tandoor.com TANDOOR_API_KEY=your-tandoor-token # Queue Processing QUEUE_CONCURRENCY=2 QUEUE_TIMEOUT_MS=30000 # Push Notifications (optional) VAPID_PUBLIC_KEY=your-vapid-public-key VAPID_PRIVATE_KEY=your-vapid-private-key # Instagram Authentication (optional) AUTH_SCHEDULER_ENABLED=true AUTH_SCHEDULER_INTERVAL_MINUTES=720 ``` ### Tandoor Setup To automatically upload extracted recipes to Tandoor: 1. Create an API token in your Tandoor instance 2. Set `TANDOOR_BASE_URL` and `TANDOOR_API_KEY` in `.env` 3. Recipes will be automatically uploaded after successful extraction ### Push Notifications To enable web push notifications: 1. Generate VAPID keys: ```bash npx web-push generate-vapid-keys ``` 2. Set `VAPID_PUBLIC_KEY` and `VAPID_PRIVATE_KEY` in `.env` 3. Users can enable notifications in the dashboard settings ## ๐Ÿ— Architecture Overview ### Queue System ``` User submits URL โ†’ Queue Manager โ†’ Queue Processor โ†“ Extraction Phase โ† โ†’ Parsing Phase โ† โ†’ Upload Phase โ†“ Push Notifications โ† โ†’ SSE Updates โ† โ†’ Dashboard Updates ``` ### Processing Pipeline 1. **Extraction Phase**: Browser automation extracts text and images 2. **Parsing Phase**: LLM converts text to structured recipe data 3. **Upload Phase**: Automatic upload to Tandoor (if configured) Each phase tracks progress and can fail independently with proper error handling. ### Error Classification - **Recoverable Errors** (`unhealthy`): Temporary issues, can be retried - **Non-recoverable Errors** (`error`): Invalid URLs, parsing failures, etc. ## ๐Ÿงช Testing ```bash # Run all tests npm test # Run specific test suites npm run test:unit # Unit tests only npm run test:client # Browser tests only npm run test:server # Server tests only # Run tests in watch mode npm run test:watch ``` Test Coverage: - **138 total tests** covering all major components - Queue Manager: 28 tests - Queue Processor: 5 integration tests - API Endpoints: 17 tests - SSE Streaming: 6 tests - Frontend Components: Browser tests ## ๐Ÿ“ฆ Building & Deployment ### Production Build ```bash # Build for production npm run build # Preview production build locally npm run preview ``` ### Deployment The app is built as a Node.js application with the following outputs: - `/.svelte-kit/output/server/` - Server bundle - `/.svelte-kit/output/client/` - Static assets - `/build/` - Adapter output Deploy the server bundle with: ```bash node build/index.js ``` ### Docker Deployment ```dockerfile FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY build ./build EXPOSE 3000 CMD ["node", "build"] ``` ## ๐Ÿ”„ Migration from Synchronous System ### What Changed The app was migrated from a synchronous extraction system to an async queue-based system: **Before (Synchronous)**: - User waited for entire extraction process to complete - No progress tracking during processing - No retry capability for failures - Single-threaded processing - Limited error handling **After (Async Queue)**: - Fire-and-forget: submit URL and redirect immediately - Real-time progress tracking via SSE - Comprehensive retry system for failures - Concurrent processing (configurable) - Detailed error classification and reporting - Push notifications for background updates ### API Migration **Old Synchronous Endpoints** (Deprecated): ```bash POST /api/extract # Submit URL and wait for completion GET /api/extract-stream # Long-polling for progress ``` **New Queue Endpoints**: ```bash POST /api/queue # Submit URL, get queue ID immediately GET /api/queue # List all queue items GET /api/queue/{id} # Get specific item status POST /api/queue/{id}/retry # Retry failed items GET /api/queue/stream # Real-time SSE updates ``` ### Migration Steps If migrating from the old system: 1. **Update Client Code**: Replace `/api/extract` calls with `/api/queue` 2. **Handle Async Responses**: Process queue ID instead of waiting for completion 3. **Add Progress Tracking**: Implement SSE listeners for real-time updates 4. **Update Error Handling**: Handle new error classification system 5. **Add Retry Logic**: Implement retry functionality for failed items ### Backward Compatibility The legacy endpoints are still available but deprecated: - They will return `410 Gone` status with migration instructions - Support will be removed in a future version - All new development should use the queue endpoints ## ๐Ÿค Contributing 1. Fork the repository 2. Create a feature branch (`git checkout -b feature/amazing-feature`) 3. Make your changes with tests 4. Run the test suite (`npm test`) 5. Commit your changes (`git commit -m 'Add amazing feature'`) 6. Push to the branch (`git push origin feature/amazing-feature`) 7. Open a Pull Request ### Development Guidelines - Follow TypeScript strict mode - Add tests for all new functionality - Use the existing architecture patterns (Hexagonal Architecture) - Update documentation for API changes - Ensure PWA functionality remains intact ## ๐Ÿ“„ License This project is licensed under the MIT License - see the LICENSE file for details. ## ๐Ÿ™ Acknowledgments - [SvelteKit](https://kit.svelte.dev/) - Application framework - [Tandoor Recipe Manager](https://docs.tandoor.dev/) - Recipe management system - [Workbox](https://developers.google.com/web/tools/workbox) - PWA capabilities - [fastq](https://github.com/mcollina/fastq) - High-performance queue processing