diff --git a/CLAUDE.md b/CLAUDE.md index ca64866..25b14d2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,6 +23,7 @@ Root `compose.yaml` uses Docker Compose's `include` directive to orchestrate mul - **vault**: Vaultwarden password manager (SQLite) - **joplin**: Joplin Server note-taking and sync platform (PostgreSQL) - **vert**: VERT file format converter (WebAssembly-based, stateless) +- **paint**: miniPaint web-based image editor (built from GitHub) - **restic**: Backrest backup system with restic backend - **sablier**: Dynamic scaling plugin for Traefik - **vpn**: WireGuard VPN (wg-easy) @@ -272,6 +273,27 @@ Simply access https://vert.pivoine.art and drag/drop files to convert between fo **Note**: VERT is stateless and doesn't require backups as no data is persisted. +### Paint (paint/compose.yaml) +miniPaint web-based image editor built from GitHub: +- **paint**: miniPaint app exposed at `paint.pivoine.art:80` + - Online image editor with layer support + - Built directly from https://github.com/viliusle/miniPaint + - Supports PNG, JPG, GIF, WebP formats + - Features: layers, filters, drawing tools, text, shapes + - Client-side processing (no uploads to server) + - No persistent data storage required + - Stateless architecture + +**Build Process**: +- Multi-stage Docker build clones from GitHub +- Builds using Node.js 18 +- Serves static files via nginx + +**Usage**: +Access https://paint.pivoine.art to use the image editor. All editing happens in the browser - images are not uploaded to the server. + +**Note**: miniPaint is stateless and doesn't require backups as no data is persisted. + ### Restic (restic/compose.yaml) Backrest backup system with restic backend: - **backrest**: Backrest web UI exposed at `restic.pivoine.art:9898` diff --git a/arty.yml b/arty.yml index af2a9a1..c7438ad 100644 --- a/arty.yml +++ b/arty.yml @@ -116,6 +116,10 @@ envs: VERT_IMAGE: ghcr.io/vert-sh/vert:latest VERT_TRAEFIK_HOST: vert.pivoine.art VERT_SABLIER_ENABLED: true + # Paint + PAINT_TRAEFIK_ENABLED: true + PAINT_COMPOSE_PROJECT_NAME: paint + PAINT_TRAEFIK_HOST: paint.pivoine.art # Proxy PROXY_COMPOSE_PROJECT_NAME: proxy PROXY_DOCKER_IMAGE: traefik:latest diff --git a/compose.yaml b/compose.yaml index 5c413bf..401578f 100644 --- a/compose.yaml +++ b/compose.yaml @@ -11,6 +11,7 @@ include: - vault/compose.yaml - joplin/compose.yaml - vert/compose.yaml + - paint/compose.yaml - restic/compose.yaml - umami/compose.yaml - sablier/compose.yaml diff --git a/paint/Dockerfile b/paint/Dockerfile new file mode 100644 index 0000000..a35505a --- /dev/null +++ b/paint/Dockerfile @@ -0,0 +1,23 @@ +# Build miniPaint from GitHub repository +FROM node:18-alpine AS builder + +WORKDIR /app + +# Clone the repository +RUN apk add --no-cache git && \ + git clone https://github.com/viliusle/miniPaint.git . && \ + npm install && \ + npm run build + +# Production stage with nginx +FROM nginx:alpine + +# Copy built files from builder +COPY --from=builder /app/dist /usr/share/nginx/html + +# Copy nginx configuration if needed +COPY --from=builder /app /usr/share/nginx/html + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/paint/compose.yaml b/paint/compose.yaml new file mode 100644 index 0000000..2faa8d6 --- /dev/null +++ b/paint/compose.yaml @@ -0,0 +1,32 @@ +services: + paint: + build: + context: . + dockerfile: Dockerfile + image: minipaint:latest + container_name: ${PAINT_COMPOSE_PROJECT_NAME}_app + restart: unless-stopped + networks: + - compose_network + labels: + - 'traefik.enable=${PAINT_TRAEFIK_ENABLED}' + # HTTP to HTTPS redirect + - 'traefik.http.middlewares.${PAINT_COMPOSE_PROJECT_NAME}-redirect-web-secure.redirectscheme.scheme=https' + - 'traefik.http.routers.${PAINT_COMPOSE_PROJECT_NAME}-web.middlewares=${PAINT_COMPOSE_PROJECT_NAME}-redirect-web-secure' + - 'traefik.http.routers.${PAINT_COMPOSE_PROJECT_NAME}-web.rule=Host(`${PAINT_TRAEFIK_HOST}`)' + - 'traefik.http.routers.${PAINT_COMPOSE_PROJECT_NAME}-web.entrypoints=web' + # HTTPS router + - 'traefik.http.routers.${PAINT_COMPOSE_PROJECT_NAME}-web-secure.rule=Host(`${PAINT_TRAEFIK_HOST}`)' + - 'traefik.http.routers.${PAINT_COMPOSE_PROJECT_NAME}-web-secure.tls.certresolver=resolver' + - 'traefik.http.routers.${PAINT_COMPOSE_PROJECT_NAME}-web-secure.entrypoints=web-secure' + - 'traefik.http.routers.${PAINT_COMPOSE_PROJECT_NAME}-web-secure.middlewares=security-headers@file' + # Service + - 'traefik.http.services.${PAINT_COMPOSE_PROJECT_NAME}-web-secure.loadbalancer.server.port=80' + - 'traefik.docker.network=${NETWORK_NAME}' + # Watchtower + - 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}' + +networks: + compose_network: + name: ${NETWORK_NAME} + external: true