# raffaelaldrichs/i-save architecture

> Architecture diagram of the GitHub repository raffaelaldrichs/i-save, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-30). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/raffaelaldrichs/i-save
- Repository: https://github.com/raffaelaldrichs/i-save

## Overview

iSAVE accepts a media URL, extracts platform metadata and available formats, then queues a selected download, reports progress, and serves the resulting file. Its documented product also includes inline preview, carousel ZIPs, audio bitrate choices, QR handoff, and bookmarklet access. The graph includes the main UI/API path and substantial runtime modules; some subsystem links rely on README statements or SOURCE INDEX references because their implementation excerpts were not provided.

Main entry points: [`src/app/api/download/route.ts`](https://github.com/raffaelaldrichs/i-save/blob/main/src/app/api/download/route.ts) (Download endpoint), [`src/lib/jobQueue.ts`](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/jobQueue.ts) (Job queue), [`src/app/page.tsx`](https://github.com/raffaelaldrichs/i-save/blob/main/src/app/page.tsx) (Home page), [`src/components/DownloaderWorkspace.tsx`](https://github.com/raffaelaldrichs/i-save/blob/main/src/components/DownloaderWorkspace.tsx) (Downloader workspace)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_experience["User experience"]
  node_home["Home page<br/>[page.tsx]"]
  node_workspace["Downloader workspace"]
  node_preview["Media preview<br/>[MediaPreview.tsx]"]
  node_qr["QR handoff<br/>[QrCodeModal.tsx]"]
  node_bookmarklet["Bookmarklet help"]
end

subgraph group_api["API workflows"]
  node_extract_api["Extract endpoint<br/>[route.ts]"]
  node_batch_api["Batch extract<br/>[route.ts]"]
  node_download_api["Download endpoint<br/>[route.ts]"]
  node_progress_api["Progress endpoint<br/>[route.ts]"]
  node_worker["Download worker<br/>[route.ts]"]
end

subgraph group_media["Media processing"]
  node_audio["Audio formats<br/>[audioOptions.ts]"]
  node_carousel["Carousel ZIP<br/>[carouselZip.ts]"]
  node_downloader["Media downloader<br/>[mediaDownloader.ts]"]
end

subgraph group_runtime["Jobs and storage"]
  node_jobs["Job queue<br/>[jobQueue.ts]"]
  node_jobstore[("Job state<br/>[jobStore.ts]")]
  node_progress["Progress tracking<br/>[progressTracker.ts]"]
  node_storage[("Media storage<br/>[storage.ts]")]
  node_temp["Temporary storage<br/>[tempStorage.ts]"]
  node_security["URL security<br/>[security.ts]"]
  node_rate["Rate limiting<br/>[rateLimit.ts]"]
  node_redis[("Redis job store<br/>[redisStore.ts]")]
  node_qstash["QStash broker<br/>[qstash.ts]"]
end

subgraph group_platforms["Platform extraction"]
  node_extractors["Extractor manager<br/>[index.ts]"]
  node_platform_extractors["Platform extractors"]
end

node_user(("Visitor"))

node_user -->|"opens"| node_home
node_home -->|"renders"| node_workspace
node_workspace -.->|"previews media"| node_preview
node_workspace -->|"offers handoff"| node_qr
node_workspace -->|"offers guidance"| node_bookmarklet
node_home -->|"requests metadata"| node_extract_api
node_home -->|"requests download"| node_download_api
node_home -->|"polls progress"| node_progress_api
node_extract_api -->|"validates URL"| node_security
node_extract_api -->|"limits requests"| node_rate
node_extract_api -->|"extracts metadata"| node_extractors
node_batch_api -->|"extracts batch"| node_extractors
node_extractors -->|"dispatches providers"| node_platform_extractors
node_platform_extractors -->|"generates audio choices"| node_audio
node_platform_extractors -->|"packages slide media"| node_carousel
node_download_api -->|"validates URL"| node_security
node_download_api -->|"enqueues job"| node_jobs
node_download_api -->|"publishes job"| node_qstash
node_download_api -->|"updates failure state"| node_jobstore
node_worker -->|"processes job"| node_jobs
node_progress_api -->|"reads progress"| node_progress
node_progress -->|"reads and updates"| node_jobstore
node_jobs -->|"stores job state"| node_jobstore
node_jobs -->|"runs download"| node_downloader
node_jobs -->|"registers output"| node_temp
node_jobs -->|"persists jobs"| node_redis
node_downloader -->|"bundles slides"| node_carousel
node_temp -->|"delegates storage"| node_storage
node_download_api -.->|"serves stored file"| node_storage
node_user -.->|"submits batch"| node_batch_api

click node_home "https://github.com/raffaelaldrichs/i-save/blob/main/src/app/page.tsx"
click node_workspace "https://github.com/raffaelaldrichs/i-save/blob/main/src/components/DownloaderWorkspace.tsx"
click node_preview "https://github.com/raffaelaldrichs/i-save/blob/main/src/components/MediaPreview.tsx"
click node_qr "https://github.com/raffaelaldrichs/i-save/blob/main/src/components/QrCodeModal.tsx"
click node_bookmarklet "https://github.com/raffaelaldrichs/i-save/blob/main/src/components/BookmarkletModal.tsx"
click node_extract_api "https://github.com/raffaelaldrichs/i-save/blob/main/src/app/api/extract/route.ts"
click node_batch_api "https://github.com/raffaelaldrichs/i-save/blob/main/src/app/api/extract-batch/route.ts"
click node_download_api "https://github.com/raffaelaldrichs/i-save/blob/main/src/app/api/download/route.ts"
click node_progress_api "https://github.com/raffaelaldrichs/i-save/blob/main/src/app/api/download/progress/route.ts"
click node_worker "https://github.com/raffaelaldrichs/i-save/blob/main/src/app/api/worker/download/route.ts"
click node_extractors "https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/extractors/index.ts"
click node_platform_extractors "https://github.com/raffaelaldrichs/i-save/tree/main/src/lib/extractors"
click node_audio "https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/audioOptions.ts"
click node_carousel "https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/carouselZip.ts"
click node_downloader "https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/mediaDownloader.ts"
click node_jobs "https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/jobQueue.ts"
click node_jobstore "https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/jobStore.ts"
click node_progress "https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/progressTracker.ts"
click node_storage "https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/storage.ts"
click node_temp "https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/tempStorage.ts"
click node_security "https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/security.ts"
click node_rate "https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/rateLimit.ts"
click node_redis "https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/redisStore.ts"
click node_qstash "https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/qstash.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_home,node_workspace,node_preview,node_qr,node_bookmarklet toneBlue
class node_extract_api,node_batch_api,node_download_api,node_progress_api,node_worker toneAmber
class node_audio,node_carousel,node_downloader toneMint
class node_jobs,node_jobstore,node_progress,node_storage,node_temp,node_security,node_rate,node_redis,node_qstash toneRose
class node_extractors,node_platform_extractors,node_user toneIndigo
```

## Components

### User experience

- [Home page](https://github.com/raffaelaldrichs/i-save/blob/main/src/app/page.tsx): `src/app/page.tsx`
- [Downloader workspace](https://github.com/raffaelaldrichs/i-save/blob/main/src/components/DownloaderWorkspace.tsx): `src/components/DownloaderWorkspace.tsx`
- [Media preview](https://github.com/raffaelaldrichs/i-save/blob/main/src/components/MediaPreview.tsx): `src/components/MediaPreview.tsx`
- [QR handoff](https://github.com/raffaelaldrichs/i-save/blob/main/src/components/QrCodeModal.tsx): `src/components/QrCodeModal.tsx`
- [Bookmarklet help](https://github.com/raffaelaldrichs/i-save/blob/main/src/components/BookmarkletModal.tsx): `src/components/BookmarkletModal.tsx`

### API workflows

- [Extract endpoint](https://github.com/raffaelaldrichs/i-save/blob/main/src/app/api/extract/route.ts): `src/app/api/extract/route.ts`
- [Batch extract](https://github.com/raffaelaldrichs/i-save/blob/main/src/app/api/extract-batch/route.ts): `src/app/api/extract-batch/route.ts`
- [Download endpoint](https://github.com/raffaelaldrichs/i-save/blob/main/src/app/api/download/route.ts): `src/app/api/download/route.ts`
- [Progress endpoint](https://github.com/raffaelaldrichs/i-save/blob/main/src/app/api/download/progress/route.ts): `src/app/api/download/progress/route.ts`
- [Download worker](https://github.com/raffaelaldrichs/i-save/blob/main/src/app/api/worker/download/route.ts): `src/app/api/worker/download/route.ts`

### Media processing

- [Audio formats](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/audioOptions.ts): `src/lib/audioOptions.ts`
- [Carousel ZIP](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/carouselZip.ts): `src/lib/carouselZip.ts`
- [Media downloader](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/mediaDownloader.ts): `src/lib/mediaDownloader.ts`

### Jobs and storage

- [Job queue](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/jobQueue.ts): `src/lib/jobQueue.ts`
- [Job state](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/jobStore.ts): `src/lib/jobStore.ts`
- [Progress tracking](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/progressTracker.ts): `src/lib/progressTracker.ts`
- [Media storage](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/storage.ts): `src/lib/storage.ts`
- [Temporary storage](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/tempStorage.ts): `src/lib/tempStorage.ts`
- [URL security](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/security.ts): `src/lib/security.ts`
- [Rate limiting](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/rateLimit.ts): `src/lib/rateLimit.ts`
- [Redis job store](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/redisStore.ts): `src/lib/redisStore.ts`
- [QStash broker](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/qstash.ts): `src/lib/qstash.ts`

### Platform extraction

- [Extractor manager](https://github.com/raffaelaldrichs/i-save/blob/main/src/lib/extractors/index.ts): `src/lib/extractors/index.ts`
- [Platform extractors](https://github.com/raffaelaldrichs/i-save/tree/main/src/lib/extractors): `src/lib/extractors`

### Other components

- **Visitor**

## Connections

- Visitor → Home page: opens (evidence: `src/app/page.tsx`)
- Home page → Downloader workspace: renders (evidence: `src/app/page.tsx`)
- Downloader workspace → Media preview: previews media (evidence: `README.md`)
- Downloader workspace → QR handoff: offers handoff (evidence: `src/components/DownloaderWorkspace.tsx`)
- Downloader workspace → Bookmarklet help: offers guidance (evidence: `src/components/DownloaderWorkspace.tsx`)
- Home page → Extract endpoint: requests metadata (evidence: `src/app/page.tsx`)
- Home page → Download endpoint: requests download (evidence: `src/app/page.tsx`)
- Home page → Progress endpoint: polls progress (evidence: `src/app/page.tsx`)
- Extract endpoint → URL security: validates URL (evidence: `src/app/api/extract/route.ts`)
- Extract endpoint → Rate limiting: limits requests (evidence: `src/app/api/extract/route.ts`)
- Extract endpoint → Extractor manager: extracts metadata (evidence: `src/app/api/extract/route.ts`)
- Batch extract → Extractor manager: extracts batch (evidence: `src/app/api/extract-batch/route.ts`)
- Extractor manager → Platform extractors: dispatches providers (evidence: `src/lib/extractors/index.ts`)
- Platform extractors → Audio formats: generates audio choices (evidence: `src/lib/extractors/instagram.ts`)
- Platform extractors → Carousel ZIP: packages slide media (evidence: `src/lib/extractors/reddit.ts`)
- Download endpoint → URL security: validates URL (evidence: `src/app/api/download/route.ts`)
- Download endpoint → Job queue: enqueues job (evidence: `src/app/api/download/route.ts`)
- Download endpoint → QStash broker: publishes job (evidence: `src/app/api/download/route.ts`)
- Download endpoint → Job state: updates failure state (evidence: `src/app/api/download/route.ts`)
- Download worker → Job queue: processes job (evidence: `src/app/api/worker/download/route.ts`)
- Progress endpoint → Progress tracking: reads progress (evidence: `src/app/api/download/progress/route.ts`)
- Progress tracking → Job state: reads and updates (evidence: `src/lib/progressTracker.ts`)
- Job queue → Job state: stores job state (evidence: `src/lib/jobQueue.ts`)
- Job queue → Media downloader: runs download (evidence: `src/lib/jobQueue.ts`)
- Job queue → Temporary storage: registers output (evidence: `src/lib/jobQueue.ts`)
- Job queue → Redis job store: persists jobs (evidence: `src/lib/jobQueue.ts`)
- Media downloader → Carousel ZIP: bundles slides (evidence: `src/lib/mediaDownloader.ts`)
- Temporary storage → Media storage: delegates storage (evidence: `src/lib/tempStorage.ts`)
- Download endpoint → Media storage: serves stored file (evidence: `src/app/api/download/route.ts`)
- Visitor → Batch extract: submits batch
