# mudelkun/louvo architecture

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

- Interactive diagram: https://gitdiagram.com/mudelkun/louvo
- Repository: https://github.com/mudelkun/louvo

## Overview

Louvo lets people browse a hairstyle catalogue, choose a cut and hair type, and preview the cut on their own photo. Its web and mobile clients use one API; previews run as background jobs, with results returned for comparison, saving, and sharing. The README documents catalogue imagery, credit balances and purchases, referrals, notifications, and short-lived photo storage. The graph preserves those product branches; sampled excerpts provide direct wiring evidence for mobile preview uploads and worker processing, while some web and auxiliary feature connections follow README documentation.

Main entry points: [`server/src/routes.ts`](https://github.com/mudelkun/louvo/blob/main/server/src/routes.ts) (HTTP routes), [`server/src/worker.ts`](https://github.com/mudelkun/louvo/blob/main/server/src/worker.ts) (Generation worker), [`server/src/catalog.ts`](https://github.com/mudelkun/louvo/blob/main/server/src/catalog.ts) (Catalogue API), [`src/api/client.ts`](https://github.com/mudelkun/louvo/blob/main/src/api/client.ts) (Mobile API client)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_clients["Web and mobile"]
  node_mobile["Mobile screens<br/>[index.tsx]"]
  node_mobile_client["Mobile API client<br/>[client.ts]"]
  node_mobile_preview["Preview uploads<br/>[previews.ts]"]
  node_web["Web app<br/>[page.tsx]"]
  node_web_api["Web API client<br/>[api.ts]"]
  node_catalogue["Catalogue browser<br/>[CatalogBrowser.tsx]"]
end

subgraph group_backend["API and generation"]
  node_api["HTTP routes<br/>[routes.ts]"]
  node_tryon["Preview jobs<br/>[tryOn.ts]"]
  node_jobs["Job state<br/>[jobs.ts]"]
  node_worker["Generation worker<br/>[worker.ts]"]
  node_database[("Postgres<br/>[db.ts]")]
  node_storage["Transient storage<br/>[storage.ts]"]
  node_fal["Image model adapter<br/>[fal.ts]"]
  node_push["Push notifications<br/>[push.ts]"]
end

subgraph group_catalog["Catalogue and looks"]
  node_catalog_api["Catalogue API<br/>[catalog.ts]"]
  node_catalog_routes["Catalogue routes<br/>[routes.ts]"]
end

subgraph group_commerce["Credits and sharing"]
  node_looks["Saved looks and shares<br/>[shares.ts]"]
  node_credits["Credits and purchases<br/>[credits.ts]"]
  node_checkout["Checkout<br/>[checkout.ts]"]
end

node_visitor(("Visitor"))
node_fal_service{{"fal.ai"}}
node_private_bucket[("Private R2 bucket")]
node_cdn[("Catalogue CDN")]
node_stripe{{"Stripe"}}
node_revenuecat{{"RevenueCat"}}
node_device_push(("Mobile device"))

node_visitor -->|"browses and submits"| node_web
node_visitor -->|"chooses photo and style"| node_mobile
node_web -->|"requests data"| node_web_api
node_web_api -->|"calls API"| node_api
node_mobile -->|"requests data"| node_mobile_client
node_mobile_client -->|"calls API"| node_api
node_mobile_client -->|"submits preview"| node_mobile_preview
node_mobile_preview -->|"creates job"| node_api
node_mobile_preview -->|"uploads photo"| node_private_bucket
node_api -->|"dispatches job"| node_tryon
node_tryon -->|"creates and reserves"| node_jobs
node_tryon -->|"signs upload"| node_storage
node_storage -->|"presigns and deletes"| node_private_bucket
node_worker -->|"claims and updates"| node_jobs
node_worker -->|"loads reference"| node_catalog_api
node_worker -->|"reads and writes images"| node_storage
node_worker -->|"requests generation"| node_fal
node_fal -->|"calls model"| node_fal_service
node_worker -->|"requests ready notice"| node_push
node_push -->|"sends notification"| node_device_push
node_catalogue -->|"loads styles"| node_web_api
node_api -->|"serves reads"| node_catalog_routes
node_catalog_routes -->|"loads catalogue"| node_catalog_api
node_catalog_api -->|"reads metadata"| node_database
node_catalog_api -->|"resolves imagery"| node_cdn
node_api -->|"serves balances"| node_credits
node_api -->|"starts purchase"| node_checkout
node_checkout -->|"creates checkout"| node_stripe
node_stripe -.->|"webhook"| node_api
node_revenuecat -.->|"webhook"| node_api
node_api -->|"serves saved looks and shares"| node_looks
node_looks -->|"stores look data"| node_database

click node_mobile "https://github.com/mudelkun/louvo/blob/main/app/(tabs)/index.tsx"
click node_mobile_client "https://github.com/mudelkun/louvo/blob/main/src/api/client.ts"
click node_mobile_preview "https://github.com/mudelkun/louvo/blob/main/src/api/previews.ts"
click node_web "https://github.com/mudelkun/louvo/blob/main/web/app/studio/page.tsx"
click node_web_api "https://github.com/mudelkun/louvo/blob/main/web/lib/api.ts"
click node_api "https://github.com/mudelkun/louvo/blob/main/server/src/routes.ts"
click node_tryon "https://github.com/mudelkun/louvo/blob/main/server/src/tryOn.ts"
click node_jobs "https://github.com/mudelkun/louvo/blob/main/server/src/jobs.ts"
click node_worker "https://github.com/mudelkun/louvo/blob/main/server/src/worker.ts"
click node_database "https://github.com/mudelkun/louvo/blob/main/server/src/db.ts"
click node_storage "https://github.com/mudelkun/louvo/blob/main/server/src/storage.ts"
click node_fal "https://github.com/mudelkun/louvo/blob/main/server/src/fal.ts"
click node_catalog_api "https://github.com/mudelkun/louvo/blob/main/server/src/catalog.ts"
click node_catalog_routes "https://github.com/mudelkun/louvo/blob/main/server/src/routes.ts"
click node_catalogue "https://github.com/mudelkun/louvo/blob/main/web/components/CatalogBrowser.tsx"
click node_looks "https://github.com/mudelkun/louvo/blob/main/server/src/shares.ts"
click node_credits "https://github.com/mudelkun/louvo/blob/main/server/src/credits.ts"
click node_checkout "https://github.com/mudelkun/louvo/blob/main/server/src/checkout.ts"
click node_push "https://github.com/mudelkun/louvo/blob/main/server/src/push.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_mobile,node_mobile_client,node_mobile_preview,node_web,node_web_api,node_catalogue toneBlue
class node_api,node_tryon,node_jobs,node_worker,node_database,node_storage,node_fal,node_push,node_private_bucket,node_cdn toneAmber
class node_catalog_api,node_catalog_routes toneMint
class node_looks,node_credits,node_checkout toneRose
class node_visitor,node_fal_service,node_stripe,node_revenuecat,node_device_push toneIndigo
```

## Components

### Web and mobile

- [Mobile screens](https://github.com/mudelkun/louvo/blob/main/app/(tabs)/index.tsx): `app/(tabs)/index.tsx`
- [Mobile API client](https://github.com/mudelkun/louvo/blob/main/src/api/client.ts): `src/api/client.ts`
- [Preview uploads](https://github.com/mudelkun/louvo/blob/main/src/api/previews.ts): `src/api/previews.ts`
- [Web app](https://github.com/mudelkun/louvo/blob/main/web/app/studio/page.tsx): `web/app/studio/page.tsx`
- [Web API client](https://github.com/mudelkun/louvo/blob/main/web/lib/api.ts): `web/lib/api.ts`
- [Catalogue browser](https://github.com/mudelkun/louvo/blob/main/web/components/CatalogBrowser.tsx): `web/components/CatalogBrowser.tsx`

### API and generation

- [HTTP routes](https://github.com/mudelkun/louvo/blob/main/server/src/routes.ts): `server/src/routes.ts`
- [Preview jobs](https://github.com/mudelkun/louvo/blob/main/server/src/tryOn.ts): `server/src/tryOn.ts`
- [Job state](https://github.com/mudelkun/louvo/blob/main/server/src/jobs.ts): `server/src/jobs.ts`
- [Generation worker](https://github.com/mudelkun/louvo/blob/main/server/src/worker.ts): `server/src/worker.ts`
- [Postgres](https://github.com/mudelkun/louvo/blob/main/server/src/db.ts): `server/src/db.ts`
- [Transient storage](https://github.com/mudelkun/louvo/blob/main/server/src/storage.ts): `server/src/storage.ts`
- [Image model adapter](https://github.com/mudelkun/louvo/blob/main/server/src/fal.ts): `server/src/fal.ts`
- [Push notifications](https://github.com/mudelkun/louvo/blob/main/server/src/push.ts): `server/src/push.ts`

### Catalogue and looks

- [Catalogue API](https://github.com/mudelkun/louvo/blob/main/server/src/catalog.ts): `server/src/catalog.ts`
- [Catalogue routes](https://github.com/mudelkun/louvo/blob/main/server/src/routes.ts): `server/src/routes.ts`

### Credits and sharing

- [Saved looks and shares](https://github.com/mudelkun/louvo/blob/main/server/src/shares.ts): `server/src/shares.ts`
- [Credits and purchases](https://github.com/mudelkun/louvo/blob/main/server/src/credits.ts): `server/src/credits.ts`
- [Checkout](https://github.com/mudelkun/louvo/blob/main/server/src/checkout.ts): `server/src/checkout.ts`

### Other components

- **Visitor**
- **fal.ai**
- **Private R2 bucket**
- **Catalogue CDN**
- **Stripe**
- **RevenueCat**
- **Mobile device**

## Connections

- Visitor → Web app: browses and submits
- Visitor → Mobile screens: chooses photo and style
- Web app → Web API client: requests data
- Web API client → HTTP routes: calls API
- Mobile screens → Mobile API client: requests data
- Mobile API client → HTTP routes: calls API
- Mobile API client → Preview uploads: submits preview
- Preview uploads → HTTP routes: creates job
- Preview uploads → Private R2 bucket: uploads photo
- HTTP routes → Preview jobs: dispatches job
- Preview jobs → Job state: creates and reserves
- Preview jobs → Transient storage: signs upload
- Transient storage → Private R2 bucket: presigns and deletes
- Generation worker → Job state: claims and updates
- Generation worker → Catalogue API: loads reference
- Generation worker → Transient storage: reads and writes images
- Generation worker → Image model adapter: requests generation
- Image model adapter → fal.ai: calls model
- Generation worker → Push notifications: requests ready notice
- Push notifications → Mobile device: sends notification
- Catalogue browser → Web API client: loads styles
- HTTP routes → Catalogue routes: serves reads
- Catalogue routes → Catalogue API: loads catalogue
- Catalogue API → Postgres: reads metadata
- Catalogue API → Catalogue CDN: resolves imagery
- HTTP routes → Credits and purchases: serves balances
- HTTP routes → Checkout: starts purchase
- Checkout → Stripe: creates checkout
- Stripe → HTTP routes: webhook
- RevenueCat → HTTP routes: webhook
- HTTP routes → Saved looks and shares: serves saved looks and shares
- Saved looks and shares → Postgres: stores look data
