chore: deploy to Cloudflare Pages and update branding

- Add Cloudflare Pages deployment for landing page (snapotter.com) and
  docs (docs.snapotter.com)
- Create deploy-landing.yml and update deploy-docs.yml workflows
- Update CI to ignore apps/landing/** paths
- Fix logo transparency (remove white background) across all apps
- Recreate social-preview.png with SnapOtter branding
- Update all docs URLs from GitHub Pages to docs.snapotter.com
- Update VitePress config: light theme default, fix llms.txt paths
- Add .vitepress/cache/ and .env.* to gitignore
This commit is contained in:
SnapOtter
2026-04-24 18:06:29 +08:00
parent fbaa603d03
commit 0309e0f680
174 changed files with 970 additions and 926 deletions
+6 -6
View File
@@ -1,11 +1,11 @@
# Architecture
ashim is a monorepo managed with pnpm workspaces and Turborepo. Everything ships as a single Docker container.
SnapOtter is a monorepo managed with pnpm workspaces and Turborepo. Everything ships as a single Docker container.
## Project structure
```
ashim/
snapotter/
├── apps/
│ ├── api/ # Fastify backend
│ ├── web/ # React + Vite frontend
@@ -19,13 +19,13 @@ ashim/
## Packages
### `@ashim/image-engine`
### `@snapotter/image-engine`
The core image processing library built on [Sharp](https://sharp.pixelplumbing.com/). It handles all non-AI operations: resize, crop, rotate, flip, convert, compress, strip metadata, and color adjustments (brightness, contrast, saturation, grayscale, sepia, invert, color channels).
This package has no network dependencies and runs entirely in-process.
### `@ashim/ai`
### `@snapotter/ai`
A bridge layer that calls Python scripts for ML operations. On first use, the bridge starts a persistent Python dispatcher process that pre-imports heavy libraries (PIL, NumPy, MediaPipe, rembg) so subsequent AI calls skip the import overhead. If the dispatcher is not yet ready, the bridge falls back to spawning a fresh Python subprocess per request.
@@ -35,7 +35,7 @@ Supported operations: background removal (rembg/BiRefNet), upscaling (RealESRGAN
Python scripts live in `packages/ai/python/`. The Docker image pre-downloads all model weights during the build so the container works fully offline.
### `@ashim/shared`
### `@snapotter/shared`
Shared TypeScript types, constants (like `APP_VERSION` and tool definitions), and i18n translation strings used by both the frontend and backend.
@@ -88,7 +88,7 @@ For batch processing, the API uses p-queue with a configurable concurrency limit
## Resource footprint
ashim is designed for low idle memory use. Nothing is preloaded or kept warm at startup.
SnapOtter is designed for low idle memory use. Nothing is preloaded or kept warm at startup.
### At idle
+7 -7
View File
@@ -1,6 +1,6 @@
# Configuration
All configuration is done through environment variables. Every variable has a sensible default, so ashim works out of the box without setting any of them.
All configuration is done through environment variables. Every variable has a sensible default, so SnapOtter works out of the box without setting any of them.
## Environment variables
@@ -30,7 +30,7 @@ All configuration is done through environment variables. Every variable has a se
| Variable | Default | Description |
|---|---|---|
| `STORAGE_MODE` | `local` | `local` or `s3`. Only local storage is currently implemented. |
| `DB_PATH` | `./data/ashim.db` | Path to the SQLite database file. |
| `DB_PATH` | `./data/snapotter.db` | Path to the SQLite database file. |
| `WORKSPACE_PATH` | `./tmp/workspace` | Directory for temporary files during processing. Cleaned up automatically. |
| `FILES_STORAGE_PATH` | `./data/files` | Directory for persistent user files (uploaded images, saved results). |
@@ -62,7 +62,7 @@ All configuration is done through environment variables. Every variable has a se
| Variable | Default | Description |
|---|---|---|
| `APP_NAME` | `ashim` | Display name shown in the UI. |
| `APP_NAME` | `SnapOtter` | Display name shown in the UI. |
| `DEFAULT_THEME` | `light` | Default theme for new sessions. `light` or `dark`. |
| `DEFAULT_LOCALE` | `en` | Default interface language. |
@@ -77,13 +77,13 @@ All configuration is done through environment variables. Every variable has a se
```yaml
services:
ashim:
image: ashimhq/ashim:latest
SnapOtter:
image: snapotterhq/snapotter:latest
ports:
- "1349:1349"
volumes:
- ashim-data:/data
- ashim-workspace:/tmp/workspace
- SnapOtter-data:/data
- SnapOtter-workspace:/tmp/workspace
environment:
- AUTH_ENABLED=true
- DEFAULT_USERNAME=admin
+4 -4
View File
@@ -1,10 +1,10 @@
# Contributing
Thanks for your interest in ashim. Community feedback helps shape the project, and there are several ways to get involved.
Thanks for your interest in SnapOtter. Community feedback helps shape the project, and there are several ways to get involved.
## How to contribute
The best way to contribute is through [GitHub Issues](https://github.com/ashim-hq/ashim/issues):
The best way to contribute is through [GitHub Issues](https://github.com/snapotter-hq/snapotter/issues):
- **Bug reports** - Found something broken? Open a bug report with steps to reproduce, your Docker setup, and what you expected to happen.
- **Feature requests** - Have an idea for a new tool or improvement? Describe the problem you want solved and why it matters to you.
@@ -18,8 +18,8 @@ If you have found a bug, open an issue describing it rather than submitting a fi
## Forking
You are welcome to fork the project for your own use under the terms of the [AGPLv3 license](https://github.com/ashim-hq/ashim/blob/main/LICENSE). The [Developer Guide](/guide/developer) covers setup, architecture, and how to add new tools.
You are welcome to fork the project for your own use under the terms of the [AGPLv3 license](https://github.com/snapotter-hq/snapotter/blob/main/LICENSE). The [Developer Guide](/guide/developer) covers setup, architecture, and how to add new tools.
## Security
If you discover a security vulnerability, please report it privately through [GitHub Security Advisories](https://github.com/ashim-hq/ashim/security/advisories/new) rather than opening a public issue.
If you discover a security vulnerability, please report it privately through [GitHub Security Advisories](https://github.com/snapotter-hq/snapotter/security/advisories/new) rather than opening a public issue.
+3 -3
View File
@@ -1,8 +1,8 @@
# Database
ashim uses SQLite with [Drizzle ORM](https://orm.drizzle.team/) for data persistence. The schema is defined in `apps/api/src/db/schema.ts`.
SnapOtter uses SQLite with [Drizzle ORM](https://orm.drizzle.team/) for data persistence. The schema is defined in `apps/api/src/db/schema.ts`.
The database file lives at the path set by `DB_PATH` (defaults to `./data/ashim.db`). In Docker, mount the `/data` volume to persist it across container restarts.
The database file lives at the path set by `DB_PATH` (defaults to `./data/snapotter.db`). In Docker, mount the `/data` volume to persist it across container restarts.
## Tables
@@ -119,7 +119,7 @@ Key-value store for server-wide settings that admins can change from the UI.
Drizzle handles schema migrations. The config is in `apps/api/drizzle.config.ts`. During development, run:
```bash
pnpm --filter @ashim/api drizzle-kit push
pnpm --filter @snapotter/api drizzle-kit push
```
In production, the schema is applied automatically on startup.
+30 -30
View File
@@ -1,6 +1,6 @@
# Deployment
ashim ships as a single Docker container. The image supports **linux/amd64** (with NVIDIA CUDA) and **linux/arm64** (CPU), so it runs natively on Intel/AMD servers, Apple Silicon Macs, and ARM devices like the Raspberry Pi 4/5.
SnapOtter ships as a single Docker container. The image supports **linux/amd64** (with NVIDIA CUDA) and **linux/arm64** (CPU), so it runs natively on Intel/AMD servers, Apple Silicon Macs, and ARM devices like the Raspberry Pi 4/5.
See [Docker Image](./docker-tags) for GPU setup, Docker Compose examples, and version pinning.
@@ -9,14 +9,14 @@ See [Docker Image](./docker-tags) for GPU setup, Docker Compose examples, and ve
```yaml
# docker-compose.yml — Copy this file and run: docker compose up -d
services:
ashim:
image: ashimhq/ashim:latest # or ghcr.io/ashim-hq/ashim:latest
container_name: ashim
SnapOtter:
image: snapotterhq/snapotter:latest # or ghcr.io/snapotter-hq/snapotter:latest
container_name: SnapOtter
ports:
- "1349:1349" # Web UI + API
volumes:
- ashim-data:/data # Database, AI models, user files (PERSISTENT)
- ashim-workspace:/tmp/workspace # Temp processing files (can be tmpfs)
- SnapOtter-data:/data # Database, AI models, user files (PERSISTENT)
- SnapOtter-workspace:/tmp/workspace # Temp processing files (can be tmpfs)
environment:
# --- Authentication ---
- AUTH_ENABLED=true # Set to false to disable login entirely
@@ -50,8 +50,8 @@ services:
max-file: "3"
volumes:
ashim-data: # Named volume — Docker manages permissions automatically
ashim-workspace:
SnapOtter-data: # Named volume — Docker manages permissions automatically
SnapOtter-workspace:
```
```bash
@@ -60,7 +60,7 @@ docker compose up -d
The app is then available at `http://localhost:1349`.
> **Docker Hub rate limits?** Replace `ashimhq/ashim:latest` with `ghcr.io/ashim-hq/ashim:latest` to pull from GitHub Container Registry instead. Both registries receive the same image on every release.
> **Docker Hub rate limits?** Replace `snapotterhq/snapotter:latest` with `ghcr.io/snapotter-hq/snapotter:latest` to pull from GitHub Container Registry instead. Both registries receive the same image on every release.
## Quick Start (GPU)
@@ -70,14 +70,14 @@ For NVIDIA GPU acceleration on AI tools (background removal, upscaling, face enh
# docker-compose-gpu.yml — Requires: NVIDIA GPU + nvidia-container-toolkit
# Install toolkit: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html
services:
ashim:
image: ashimhq/ashim:latest
container_name: ashim
SnapOtter:
image: snapotterhq/snapotter:latest
container_name: SnapOtter
ports:
- "1349:1349"
volumes:
- ashim-data:/data
- ashim-workspace:/tmp/workspace
- SnapOtter-data:/data
- SnapOtter-workspace:/tmp/workspace
environment:
- AUTH_ENABLED=true
- DEFAULT_USERNAME=admin
@@ -104,8 +104,8 @@ services:
max-file: "3"
volumes:
ashim-data:
ashim-workspace:
SnapOtter-data:
SnapOtter-workspace:
```
```bash
@@ -115,7 +115,7 @@ docker compose -f docker-compose-gpu.yml up -d
Check GPU detection in the logs:
```bash
docker logs ashim 2>&1 | head -20
docker logs SnapOtter 2>&1 | head -20
# Look for: [INFO] GPU detected — AI tools will use CUDA acceleration
```
@@ -281,13 +281,13 @@ Not supported: BMP (V4/V5 headers), JPEG XL (JXL), EXR (missing decode delegate
**Named volumes** (recommended) — Docker manages permissions automatically:
```yaml
volumes:
- ashim-data:/data
- SnapOtter-data:/data
```
**Bind mounts** — You manage permissions. Set `PUID`/`PGID` to match your host user:
```yaml
volumes:
- ./ashim-data:/data
- ./SnapOtter-data:/data
environment:
- PUID=1000 # Your host UID (run: id -u)
- PGID=1000 # Your host GID (run: id -g)
@@ -318,7 +318,7 @@ The container includes a built-in health check:
```bash
# Check container health status
docker inspect --format='{{.State.Health.Status}}' ashim
docker inspect --format='{{.State.Health.Status}}' SnapOtter
# Manual health check
curl http://localhost:1349/api/v1/health
@@ -327,7 +327,7 @@ curl http://localhost:1349/api/v1/health
## Reverse Proxy
ashim sets `TRUST_PROXY=true` by default so rate limiting and logging use the real client IP from `X-Forwarded-For` headers.
SnapOtter sets `TRUST_PROXY=true` by default so rate limiting and logging use the real client IP from `X-Forwarded-For` headers.
### Nginx
@@ -360,23 +360,23 @@ server {
1. Add a new Proxy Host
2. Set Domain Name to your domain
3. Set Scheme to `http`, Forward Hostname to `ashim` (or your container IP), Forward Port to `1349`
3. Set Scheme to `http`, Forward Hostname to `SnapOtter` (or your container IP), Forward Port to `1349`
4. Enable WebSocket support
5. Under Advanced, add: `client_max_body_size 500M;` and `proxy_buffering off;`
### Traefik
```yaml
# Add these labels to the ashim service in docker-compose.yml
# Add these labels to the SnapOtter service in docker-compose.yml
labels:
- "traefik.enable=true"
- "traefik.http.routers.ashim.rule=Host(`images.example.com`)"
- "traefik.http.routers.ashim.entrypoints=websecure"
- "traefik.http.routers.ashim.tls.certresolver=letsencrypt"
- "traefik.http.services.ashim.loadbalancer.server.port=1349"
- "traefik.http.routers.snapotter.rule=Host(`images.example.com`)"
- "traefik.http.routers.snapotter.entrypoints=websecure"
- "traefik.http.routers.snapotter.tls.certresolver=letsencrypt"
- "traefik.http.services.snapotter.loadbalancer.server.port=1349"
# Increase upload limit (default 2MB is too low)
- "traefik.http.middlewares.ashim-body.buffering.maxRequestBodyBytes=524288000"
- "traefik.http.routers.ashim.middlewares=ashim-body"
- "traefik.http.middlewares.snapotter-body.buffering.maxRequestBodyBytes=524288000"
- "traefik.http.routers.snapotter.middlewares=snapotter-body"
```
### Cloudflare Tunnels
@@ -392,7 +392,7 @@ Note: Cloudflare has a 100 MB upload limit on free plans. Set `MAX_UPLOAD_SIZE_M
The GitHub repository has three workflows:
- **ci.yml** -- Runs automatically on every push and PR. Lints, typechecks, tests, builds, and validates the Docker image (without pushing).
- **release.yml** -- Triggered manually via `workflow_dispatch`. Runs semantic-release to create a version tag and GitHub release, then builds a multi-arch Docker image (amd64 + arm64) and pushes to Docker Hub (`ashimhq/ashim`) and GitHub Container Registry (`ghcr.io/ashim-hq/ashim`).
- **release.yml** -- Triggered manually via `workflow_dispatch`. Runs semantic-release to create a version tag and GitHub release, then builds a multi-arch Docker image (amd64 + arm64) and pushes to Docker Hub (`snapotterhq/snapotter`) and GitHub Container Registry (`ghcr.io/snapotter-hq/snapotter`).
- **deploy-docs.yml** -- Builds this documentation site and deploys it to GitHub Pages on push to `main`.
To create a release, go to **Actions > Release > Run workflow** in the GitHub UI, or run:
+6 -6
View File
@@ -1,6 +1,6 @@
# Developer guide
How to set up a local development environment and contribute code to ashim.
How to set up a local development environment and contribute code to SnapOtter.
## Prerequisites
@@ -14,8 +14,8 @@ Python 3.10+ is only needed if you are working on the AI/ML sidecar (background
## Setup
```bash
git clone https://github.com/ashim-hq/ashim.git
cd ashim
git clone https://github.com/snapotter-hq/snapotter.git
cd snapotter
pnpm install
pnpm dev
```
@@ -72,7 +72,7 @@ pnpm test:coverage # tests with coverage report
## Database
SQLite via Drizzle ORM. The database file lives at `./data/ashim.db` by default.
SQLite via Drizzle ORM. The database file lives at `./data/snapotter.db` by default.
```bash
cd apps/api
@@ -195,13 +195,13 @@ Add a `data-testid` attribute to your action button (as shown above) so e2e test
Build the full production image locally:
```bash
docker build -f docker/Dockerfile -t ashim:latest .
docker build -f docker/Dockerfile -t snapotter:latest .
```
Use BuildKit cache mounts for faster rebuilds:
```bash
DOCKER_BUILDKIT=1 docker build -f docker/Dockerfile -t ashim:latest .
DOCKER_BUILDKIT=1 docker build -f docker/Dockerfile -t snapotter:latest .
```
## Environment variables
+15 -15
View File
@@ -1,11 +1,11 @@
# Docker Image
ashim ships as a single Docker image that works on all platforms.
SnapOtter ships as a single Docker image that works on all platforms.
## Quick start
```bash
docker run -d --name ashim -p 1349:1349 -v ashim-data:/data ashimhq/ashim:latest
docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data snapotterhq/snapotter:latest
```
The app is available at `http://localhost:1349`.
@@ -15,7 +15,7 @@ The app is available at `http://localhost:1349`.
The image includes CUDA support on amd64. If you have an NVIDIA GPU with the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) installed, add `--gpus all`:
```bash
docker run -d --name ashim --gpus all -p 1349:1349 -v ashim-data:/data ashimhq/ashim:latest
docker run -d --name SnapOtter --gpus all -p 1349:1349 -v SnapOtter-data:/data snapotterhq/snapotter:latest
```
The image auto-detects your GPU at runtime. Without `--gpus all`, it runs on CPU. Same image either way.
@@ -56,13 +56,13 @@ GET /api/v1/admin/health
```yaml
services:
ashim:
image: ashimhq/ashim:latest
SnapOtter:
image: snapotterhq/snapotter:latest
ports:
- "1349:1349"
volumes:
- ashim-data:/data
- ashim-workspace:/tmp/workspace
- SnapOtter-data:/data
- SnapOtter-workspace:/tmp/workspace
restart: unless-stopped
logging:
driver: json-file
@@ -71,21 +71,21 @@ services:
max-file: "3"
volumes:
ashim-data:
ashim-workspace:
SnapOtter-data:
SnapOtter-workspace:
```
For GPU acceleration via Docker Compose, add the deploy section:
```yaml
services:
ashim:
image: ashimhq/ashim:latest
SnapOtter:
image: snapotterhq/snapotter:latest
ports:
- "1349:1349"
volumes:
- ashim-data:/data
- ashim-workspace:/tmp/workspace
- SnapOtter-data:/data
- SnapOtter-workspace:/tmp/workspace
deploy:
resources:
reservations:
@@ -96,8 +96,8 @@ services:
restart: unless-stopped
volumes:
ashim-data:
ashim-workspace:
SnapOtter-data:
SnapOtter-workspace:
```
## Version pinning
+10 -10
View File
@@ -3,14 +3,14 @@
## Quick Start
```bash
docker run -d --name ashim -p 1349:1349 -v ashim-data:/data ghcr.io/ashim-hq/ashim:latest
docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data ghcr.io/snapotter-hq/snapotter:latest
```
Open [http://localhost:1349](http://localhost:1349) in your browser.
::: tip Also on Docker Hub
```bash
docker run -d --name ashim -p 1349:1349 -v ashim-data:/data ashimhq/ashim:latest
docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data snapotterhq/snapotter:latest
```
Both registries publish the same image on every release.
@@ -29,7 +29,7 @@ You will be asked to change your password on first login.
Add `--gpus all` for GPU-accelerated background removal, upscaling, OCR, face enhancement, and restoration:
```bash
docker run -d --name ashim -p 1349:1349 --gpus all -v ashim-data:/data ashimhq/ashim:latest
docker run -d --name SnapOtter -p 1349:1349 --gpus all -v SnapOtter-data:/data snapotterhq/snapotter:latest
```
Requires the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Falls back to CPU automatically. See [Docker Tags](/guide/docker-tags) for benchmarks.
@@ -39,12 +39,12 @@ Requires the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud
```yaml
services:
ashim:
image: ghcr.io/ashim-hq/ashim:latest # or ashimhq/ashim:latest
SnapOtter:
image: ghcr.io/snapotter-hq/snapotter:latest # or snapotterhq/snapotter:latest
ports:
- "1349:1349"
volumes:
- ashim-data:/data
- SnapOtter-data:/data
environment:
- AUTH_ENABLED=true
- DEFAULT_USERNAME=admin
@@ -52,7 +52,7 @@ services:
restart: unless-stopped
volumes:
ashim-data:
SnapOtter-data:
```
See [Configuration](/guide/configuration) for all environment variables.
@@ -62,8 +62,8 @@ See [Configuration](/guide/configuration) for all environment variables.
**Prerequisites:** Node.js 22+, pnpm 9+, Python 3.10+ (for AI features), Git.
```bash
git clone https://github.com/ashim-hq/ashim.git
cd ashim
git clone https://github.com/snapotter-hq/snapotter.git
cd snapotter
pnpm install
pnpm dev
```
@@ -99,7 +99,7 @@ Pipelines have unlimited steps by default.
### File Library
Every file you process can be saved to your **Files** library. ashim tracks the full version history so you can trace every processing step from the original upload to the final output.
Every file you process can be saved to your **Files** library. SnapOtter tracks the full version history so you can trace every processing step from the original upload to the final output.
### REST API & API Keys
+2 -2
View File
@@ -1,6 +1,6 @@
# Translation guide
ashim ships with English by default. The i18n system is designed so adding a new language is straightforward.
SnapOtter ships with English by default. The i18n system is designed so adding a new language is straightforward.
## How translations work
@@ -10,7 +10,7 @@ The `TranslationKeys` type is derived from the English file, so TypeScript will
## Requesting a translation
To request a new language or report a mistranslation, open a [GitHub Issue](https://github.com/ashim-hq/ashim/issues) with:
To request a new language or report a mistranslation, open a [GitHub Issue](https://github.com/snapotter-hq/snapotter/issues) with:
- The language name and locale code (e.g., German / `de`)
- Any specific strings or sections you want translated