# gutslike/image-manager architecture

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

- Interactive diagram: https://gitdiagram.com/gutslike/image-manager
- Repository: https://github.com/gutslike/image-manager

## Overview

#### Purpose and Entry Points
Image Service is a self-hosted Go binary for converting uploads to WebP, storing objects in cloud storage, and tracking image/folder metadata locally. Its primary entry point is `cmd/image-service/main.go`; Cobra commands under `cmd/image-service/cmd/root.go` expose setup, server/UI, provider, and image-management workflows.

#### CLI Orchestration
The CLI is the operational control plane: setup creates configuration and provider profiles; `start` launches headless HTTP serving; `ui` additionally opens the dashboard; upload/list/delete operate against the same service layers. Key paths: `cmd/image-service/cmd/setup.go`, `cmd/image-service/cmd/start.go`, `cmd/image-service/cmd/upload.go`.

#### HTTP API and Dashboard Surface
The server exposes JSON APIs for uploads, images, folders, health, and stats, plus HTML partial endpoints for HTMX-driven dashboard updates. Routing and request/response handling are separated in `internal/api/router.go` and `internal/api/handlers.go`. Embedded templates ensure the binary carries its UI: `web/embed.go`, `web/templates/layout.html`, and `web/templates/partials/`.

#### Upload Processing Pipeline
Uploads from CLI or multipart HTTP flow through service logic: MIME/size validation, decode/orientation handling, WebP conversion at configured quality, UUID/date-path generation, remote object upload, then local metadata persistence. The main boundaries are orchestration in `internal/services/upload.go`, image transformation in `internal/compression/processor.go`, and shared image/folder types in `internal/models/image.go`. If metadata persistence fails after storage succeeds, the object is deleted to avoid drift.

#### Metadata and Folder Model
SQLite is the local system of record for image metadata and folder membership, including schema migration. Folder operations only change database relationships; they never alter provider object paths or public URLs. Metadata is isolated in `internal/metadata/db.go`; higher-level image/folder operations are in `internal/services/image.go`. Loss of the local database affects organization and history, not cloud-hosted objects.

#### Storage Provider Boundary
`internal/storage/adapter.go` defines the provider abstraction used by service code for upload, deletion, and connectivity operations. Cloudflare R2 is implemented in `internal/storage/cloudflare.go`; configuration also supports Supabase Storage and Cloudinary profiles. Objects live remotely under date-based `YYYY/MM/DD/UUID.webp` keys and are served directly by provider/CDN URLs, so the application need not remain online for existing images.

#### Runtime, Configuration, and Infrastructure
The application requires Go with CGO/libwebp and a C compiler when built from source; SQLite uses the pure-Go `modernc.org/sqlite` runtime. YAML configuration selects active provider, server bind/port, local database path, upload limits, and WebP quality via `internal/config/config.go`. Core external infrastructure is Cloudflare R2/S3-compatible object storage, Supabase Storage, or Cloudinary; GitHub Actions builds releases through `.github/workflows/build.yml`.

Main entry points: [`internal/services/upload.go`](https://github.com/gutslike/image-manager/blob/main/internal/services/upload.go) (Upload orchestration), [`cmd/image-service/cmd/root.go`](https://github.com/gutslike/image-manager/blob/main/cmd/image-service/cmd/root.go) (Cobra commands), [`cmd/image-service/cmd/start.go`](https://github.com/gutslike/image-manager/blob/main/cmd/image-service/cmd/start.go) (Start command), [`internal/api/router.go`](https://github.com/gutslike/image-manager/blob/main/internal/api/router.go) (HTTP router)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_control["CLI Control Plane"]
  node_main{{"Go binary entry<br/>entrypoint<br/>[main.go]"}}
  node_commands["Cobra commands<br/>cli<br/>[root.go]"]
  node_setup["Setup command<br/>cli workflow<br/>[setup.go]"]
  node_start["Start command<br/>cli workflow<br/>[start.go]"]
  node_upload_cli["Upload command<br/>cli workflow<br/>[upload.go]"]
end

subgraph group_app["Application Runtime"]
  node_config["YAML configuration<br/>[config.go]"]
  node_api_router["HTTP router<br/>api routing<br/>[router.go]"]
  node_api_handlers["API handlers<br/>http handlers<br/>[handlers.go]"]
  node_dashboard["Embedded dashboard<br/>HTMX UI<br/>[embed.go]"]
  node_upload_service["Upload orchestration<br/>[upload.go]"]
  node_processor["WebP processor<br/>image processing<br/>[processor.go]"]
  node_image_service["Image and folder service<br/>[image.go]"]
  node_models["Image/folder models<br/>domain model<br/>[image.go]"]
end

subgraph group_data["Data and Storage"]
  node_metadata_db[("SQLite metadata<br/>local database<br/>[db.go]")]
  node_storage_adapter["Storage adapter<br/>provider abstraction<br/>[adapter.go]"]
  node_cloudflare["Cloudflare R2 provider<br/>storage implementation<br/>[cloudflare.go]"]
  node_cloud_storage[("Configured cloud provider<br/>external object storage")]
end

subgraph group_delivery["Build and Delivery"]
  node_build["Release build<br/>GitHub Actions<br/>[build.yml]"]
end

node_main -->|"initializes"| node_commands
node_commands -->|"runs"| node_setup
node_commands -->|"runs"| node_start
node_commands -->|"runs"| node_upload_cli
node_setup -->|"writes"| node_config
node_start -->|"loads"| node_config
node_start -->|"serves"| node_api_router
node_api_router -->|"dispatches"| node_api_handlers
node_api_router -->|"renders"| node_dashboard
node_upload_cli -->|"uploads via"| node_upload_service
node_api_handlers -->|"multipart uploads"| node_upload_service
node_api_handlers -->|"image/folder operations"| node_image_service
node_upload_service -->|"converts to WebP"| node_processor
node_upload_service -->|"uploads and compensates"| node_storage_adapter
node_upload_service -->|"persists metadata"| node_metadata_db
node_image_service -->|"manages relationships"| node_metadata_db
node_upload_service -->|"uses"| node_models
node_image_service -->|"uses"| node_models
node_storage_adapter -->|"implemented by"| node_cloudflare
node_cloudflare -->|"stores date/UUID WebP keys"| node_cloud_storage
node_config -.->|"selects provider"| node_storage_adapter
node_build -->|"builds release"| node_main

click node_main "https://github.com/gutslike/image-manager/blob/main/cmd/image-service/main.go"
click node_commands "https://github.com/gutslike/image-manager/blob/main/cmd/image-service/cmd/root.go"
click node_setup "https://github.com/gutslike/image-manager/blob/main/cmd/image-service/cmd/setup.go"
click node_start "https://github.com/gutslike/image-manager/blob/main/cmd/image-service/cmd/start.go"
click node_upload_cli "https://github.com/gutslike/image-manager/blob/main/cmd/image-service/cmd/upload.go"
click node_config "https://github.com/gutslike/image-manager/blob/main/internal/config/config.go"
click node_api_router "https://github.com/gutslike/image-manager/blob/main/internal/api/router.go"
click node_api_handlers "https://github.com/gutslike/image-manager/blob/main/internal/api/handlers.go"
click node_dashboard "https://github.com/gutslike/image-manager/blob/main/web/embed.go"
click node_upload_service "https://github.com/gutslike/image-manager/blob/main/internal/services/upload.go"
click node_processor "https://github.com/gutslike/image-manager/blob/main/internal/compression/processor.go"
click node_image_service "https://github.com/gutslike/image-manager/blob/main/internal/services/image.go"
click node_models "https://github.com/gutslike/image-manager/blob/main/internal/models/image.go"
click node_metadata_db "https://github.com/gutslike/image-manager/blob/main/internal/metadata/db.go"
click node_storage_adapter "https://github.com/gutslike/image-manager/blob/main/internal/storage/adapter.go"
click node_cloudflare "https://github.com/gutslike/image-manager/blob/main/internal/storage/cloudflare.go"
click node_build "https://github.com/gutslike/image-manager/blob/main/.github/workflows/build.yml"

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_main,node_commands,node_setup,node_start,node_upload_cli toneBlue
class node_config,node_api_router,node_api_handlers,node_dashboard,node_upload_service,node_processor,node_image_service,node_models toneAmber
class node_metadata_db,node_storage_adapter,node_cloudflare,node_cloud_storage toneMint
class node_build toneRose
```

## Components

### CLI Control Plane

- [Go binary entry](https://github.com/gutslike/image-manager/blob/main/cmd/image-service/main.go): entrypoint · Builds the CLI application. · `cmd/image-service/main.go`
- [Cobra commands](https://github.com/gutslike/image-manager/blob/main/cmd/image-service/cmd/root.go): cli · Setup, server/UI, provider, and image workflows. · `cmd/image-service/cmd/root.go`
- [Setup command](https://github.com/gutslike/image-manager/blob/main/cmd/image-service/cmd/setup.go): cli workflow · Creates configuration and provider profiles. · `cmd/image-service/cmd/setup.go`
- [Start command](https://github.com/gutslike/image-manager/blob/main/cmd/image-service/cmd/start.go): cli workflow · Launches headless HTTP serving. · `cmd/image-service/cmd/start.go`
- [Upload command](https://github.com/gutslike/image-manager/blob/main/cmd/image-service/cmd/upload.go): cli workflow · Sends uploads through shared service logic. · `cmd/image-service/cmd/upload.go`

### Application Runtime

- [YAML configuration](https://github.com/gutslike/image-manager/blob/main/internal/config/config.go): configuration · Selects provider, server, database, limits, and WebP quality. · `internal/config/config.go`
- [HTTP router](https://github.com/gutslike/image-manager/blob/main/internal/api/router.go): api routing · Maps JSON and HTMX dashboard endpoints. · `internal/api/router.go`
- [API handlers](https://github.com/gutslike/image-manager/blob/main/internal/api/handlers.go): http handlers · Handles uploads, images, folders, health, and stats. · `internal/api/handlers.go`
- [Embedded dashboard](https://github.com/gutslike/image-manager/blob/main/web/embed.go): HTMX UI · Templates are compiled into the binary. · `web/embed.go`
- [Upload orchestration](https://github.com/gutslike/image-manager/blob/main/internal/services/upload.go): service · Validates, transforms, stores, persists metadata, and compensates on failure. · `internal/services/upload.go`
- [WebP processor](https://github.com/gutslike/image-manager/blob/main/internal/compression/processor.go): image processing · Decodes, applies orientation, and converts images. · `internal/compression/processor.go`
- [Image and folder service](https://github.com/gutslike/image-manager/blob/main/internal/services/image.go): service · Manages metadata and folder relationships without moving objects. · `internal/services/image.go`
- [Image/folder models](https://github.com/gutslike/image-manager/blob/main/internal/models/image.go): domain model · `internal/models/image.go`

### Data and Storage

- [SQLite metadata](https://github.com/gutslike/image-manager/blob/main/internal/metadata/db.go): local database · System of record for metadata, folders, and migrations. · `internal/metadata/db.go`
- [Storage adapter](https://github.com/gutslike/image-manager/blob/main/internal/storage/adapter.go): provider abstraction · Defines upload, deletion, and connectivity operations. · `internal/storage/adapter.go`
- [Cloudflare R2 provider](https://github.com/gutslike/image-manager/blob/main/internal/storage/cloudflare.go): storage implementation · S3-compatible remote object storage implementation. · `internal/storage/cloudflare.go`
- **Configured cloud provider**: external object storage · R2, Supabase Storage, or Cloudinary serves stored images directly.

### Build and Delivery

- [Release build](https://github.com/gutslike/image-manager/blob/main/.github/workflows/build.yml): GitHub Actions · Builds release binaries with Go, CGO/libwebp, and a C compiler. · `.github/workflows/build.yml`

## Connections

- Go binary entry → Cobra commands: initializes
- Cobra commands → Setup command: runs
- Cobra commands → Start command: runs
- Cobra commands → Upload command: runs
- Setup command → YAML configuration: writes
- Start command → YAML configuration: loads
- Start command → HTTP router: serves
- HTTP router → API handlers: dispatches
- HTTP router → Embedded dashboard: renders
- Upload command → Upload orchestration: uploads via
- API handlers → Upload orchestration: multipart uploads
- API handlers → Image and folder service: image/folder operations
- Upload orchestration → WebP processor: converts to WebP
- Upload orchestration → Storage adapter: uploads and compensates
- Upload orchestration → SQLite metadata: persists metadata
- Image and folder service → SQLite metadata: manages relationships
- Upload orchestration → Image/folder models: uses
- Image and folder service → Image/folder models: uses
- Storage adapter → Cloudflare R2 provider: implemented by
- Cloudflare R2 provider → Configured cloud provider: stores date/UUID WebP keys
- YAML configuration → Storage adapter: selects provider
- Release build → Go binary entry: builds release
