diff --git a/AGENTS.md b/AGENTS.md index 6fca356..4b612da 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -16,6 +16,7 @@ Compose Anything is a collection of production-ready, portable Docker Compose st 3. Update these files together when a service changes: `docker-compose.yaml`, `.env.example`, `README.md`, and `README.zh.md`. 4. Update the root `README.md` and `README.zh.md` whenever a service is added, renamed, removed, or needs a new quick-start entry. 5. Keep the default startup path within `docker compose up -d`. If extra setup is unavoidable, document it clearly and prefer a `Makefile` over ad-hoc instructions. +6. If a user requests to test locally, ensure that each service is healthy (if the service has health checks) and that there are no unnamed volumes. ## Compose Standards diff --git a/README.md b/README.md index a77c0f6..0246dbf 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ These services require building custom Docker images from source. | [OpenTelemetry Collector](./src/otel-collector) | 0.115.1 | | [OpenViking](./src/openviking) | 0.1.0 | | [Overleaf](./src/overleaf) | 5.2.1 | +| [Paca](./apps/paca) | 0.5.2 | | [PocketBase](./src/pocketbase) | 0.30.0 | | [Podman](./src/podman) | v5.7.1 | | [Pogocache](./src/pogocache) | 1.3.1 | diff --git a/README.zh.md b/README.zh.md index 98690e0..5c6a680 100644 --- a/README.zh.md +++ b/README.zh.md @@ -160,6 +160,7 @@ docker compose exec redis redis-cli ping | [OpenTelemetry Collector](./src/otel-collector) | 0.115.1 | | [OpenViking](./src/openviking) | 0.1.0 | | [Overleaf](./src/overleaf) | 5.2.1 | +| [Paca](./apps/paca) | 0.5.2 | | [PocketBase](./src/pocketbase) | 0.30.0 | | [Podman](./src/podman) | v5.7.1 | | [Pogocache](./src/pogocache) | 1.3.1 | diff --git a/apps/paca/.env.example b/apps/paca/.env.example new file mode 100644 index 0000000..b824a96 --- /dev/null +++ b/apps/paca/.env.example @@ -0,0 +1,113 @@ +# Paca Configuration + +# Paca application version (applies to API, Web, and Realtime images) +# Individual image overrides: PACA_API_IMAGE, PACA_WEB_IMAGE, PACA_REALTIME_IMAGE +PACA_VERSION=0.5.2 + +# Infrastructure versions +PACA_POSTGRES_VERSION=16-alpine +PACA_VALKEY_VERSION=8-alpine +PACA_MINIO_VERSION=latest +PACA_NGINX_VERSION=1.27-alpine + +# Port Configuration +PACA_PORT_OVERRIDE=80 + +# Environment +PACA_ENVIRONMENT=production + +# Timezone +TZ=UTC + +# ── Database ─────────────────────────────────────────────────────────────── +PACA_POSTGRES_DB=paca +PACA_POSTGRES_USER=paca +# IMPORTANT: Change this to a strong password in production! +PACA_POSTGRES_PASSWORD=changeme +# Set PACA_DATABASE_URL to use an external Postgres instead of the bundled one. +# PACA_DATABASE_URL=postgres://user:password@host:5432/paca?sslmode=disable + +# ── Cache ────────────────────────────────────────────────────────────────── +# Set PACA_REDIS_URL to use an external Valkey/Redis instead of the bundled one. +# PACA_REDIS_URL=redis://host:6379/0 + +# ── Security ─────────────────────────────────────────────────────────────── +# IMPORTANT: Change all of these in production! +# Generate with: openssl rand -hex 32 +PACA_JWT_SECRET=changeme_jwt_secret_minimum_32_chars +PACA_ENCRYPTION_KEY= +PACA_ADMIN_USERNAME=admin +PACA_ADMIN_PASSWORD=changeme +PACA_AGENT_API_KEY= + +# Cookie security: set to true when serving over HTTPS +PACA_COOKIE_SECURE=false + +# JWT TTL settings +PACA_JWT_ACCESS_TTL=15m +PACA_JWT_REFRESH_TTL=168h +PACA_JWT_REFRESH_SESSION_TTL=24h + +# ── Object Storage ───────────────────────────────────────────────────────── +# Default: bundled MinIO. Set STORAGE_PROVIDER=s3 for AWS S3. +PACA_STORAGE_PROVIDER=minio +PACA_STORAGE_ENDPOINT=paca-minio:9000 +PACA_STORAGE_PUBLIC_URL=http://localhost/storage +PACA_STORAGE_REGION=us-east-1 +PACA_STORAGE_BUCKET=paca +PACA_STORAGE_ACCESS_KEY_ID=minioadmin +PACA_STORAGE_SECRET_ACCESS_KEY=minioadmin +PACA_STORAGE_USE_SSL=false + +# ── Public URL ───────────────────────────────────────────────────────────── +# The base URL where Paca will be accessed (used for plugin callbacks, etc.) +PACA_PUBLIC_URL=http://localhost + +# ── CORS Origins ─────────────────────────────────────────────────────────── +# Defaults to PACA_PUBLIC_URL if not set +# PACA_CORS_ORIGINS=http://localhost + +# ── Logging ──────────────────────────────────────────────────────────────── +LOG_LEVEL=info + +# ── Resource Limits - PostgreSQL ─────────────────────────────────────────── +PACA_POSTGRES_CPU_LIMIT=1.0 +PACA_POSTGRES_CPU_RESERVATION=0.1 +PACA_POSTGRES_MEMORY_LIMIT=1G +PACA_POSTGRES_MEMORY_RESERVATION=256M + +# ── Resource Limits - Valkey ─────────────────────────────────────────────── +PACA_VALKEY_CPU_LIMIT=0.5 +PACA_VALKEY_CPU_RESERVATION=0.1 +PACA_VALKEY_MEMORY_LIMIT=512M +PACA_VALKEY_MEMORY_RESERVATION=128M + +# ── Resource Limits - MinIO ──────────────────────────────────────────────── +PACA_MINIO_CPU_LIMIT=0.5 +PACA_MINIO_CPU_RESERVATION=0.1 +PACA_MINIO_MEMORY_LIMIT=512M +PACA_MINIO_MEMORY_RESERVATION=256M + +# ── Resource Limits - API ────────────────────────────────────────────────── +PACA_API_CPU_LIMIT=1.0 +PACA_API_CPU_RESERVATION=0.1 +PACA_API_MEMORY_LIMIT=1G +PACA_API_MEMORY_RESERVATION=256M + +# ── Resource Limits - Web ────────────────────────────────────────────────── +PACA_WEB_CPU_LIMIT=0.5 +PACA_WEB_CPU_RESERVATION=0.1 +PACA_WEB_MEMORY_LIMIT=512M +PACA_WEB_MEMORY_RESERVATION=128M + +# ── Resource Limits - Realtime ───────────────────────────────────────────── +PACA_REALTIME_CPU_LIMIT=0.5 +PACA_REALTIME_CPU_RESERVATION=0.1 +PACA_REALTIME_MEMORY_LIMIT=512M +PACA_REALTIME_MEMORY_RESERVATION=128M + +# ── Resource Limits - Gateway ────────────────────────────────────────────── +PACA_GATEWAY_CPU_LIMIT=0.5 +PACA_GATEWAY_CPU_RESERVATION=0.1 +PACA_GATEWAY_MEMORY_LIMIT=256M +PACA_GATEWAY_MEMORY_RESERVATION=128M diff --git a/apps/paca/README.md b/apps/paca/README.md new file mode 100644 index 0000000..646aa31 --- /dev/null +++ b/apps/paca/README.md @@ -0,0 +1,83 @@ +# Paca + +Self-hosted project management platform designed for human + AI collaboration as Scrum team members. + +## Services + +- `paca-postgres`: PostgreSQL 16 database for persistent storage. +- `paca-valkey`: Valkey 8 cache and pub-sub event bus. +- `paca-minio`: MinIO S3-compatible object store for file uploads. +- `paca-api`: Go REST API backend (port 8080 internal). +- `paca-web`: React SPA frontend served via internal nginx (port 3000 internal). +- `paca-realtime`: Node.js Socket.IO real-time event hub (port 3001 internal). +- `paca-gateway`: Nginx reverse proxy that routes all traffic to the correct service. + +## Quick Start + +1. Create a `.env` file from the example and set your secrets: + +```bash +cp .env.example .env +# Edit .env to set PACA_JWT_SECRET, PACA_ENCRYPTION_KEY, PACA_ADMIN_PASSWORD, etc. +``` + +1. Start the stack: + +```bash +docker compose up -d +``` + +1. Open `http://localhost` in your browser and log in with the configured admin credentials. + +## Key Environment Variables + +| Variable | Description | Default | +| -------------------------------- | --------------------------------- | ------------------ | +| `PACA_PORT_OVERRIDE` | Host port for the gateway | `80` | +| `PACA_VERSION` | Application image tag | `latest` | +| `PACA_POSTGRES_PASSWORD` | PostgreSQL password | `changeme` | +| `PACA_ADMIN_USERNAME` | Initial admin username | `admin` | +| `PACA_ADMIN_PASSWORD` | Initial admin password | `changeme` | +| `PACA_JWT_SECRET` | JWT signing secret (min 32 chars) | (placeholder) | +| `PACA_ENCRYPTION_KEY` | AES-256 key for plugin secrets | (empty) | +| `PACA_PUBLIC_URL` | Public base URL | `http://localhost` | +| `PACA_STORAGE_PROVIDER` | Object storage provider | `minio` | +| `PACA_STORAGE_ACCESS_KEY_ID` | Storage access key | `minioadmin` | +| `PACA_STORAGE_SECRET_ACCESS_KEY` | Storage secret key | `minioadmin` | + +## Storage + +| Volume | Purpose | +| ----------------------- | ----------------------------- | +| `paca_postgres_data` | PostgreSQL database files | +| `paca_valkey_data` | Valkey append-only file | +| `paca_minio_data` | MinIO object store data | +| `paca_backend_plugins` | WASM backend plugin binaries | +| `paca_frontend_plugins` | Frontend plugin static assets | +| `paca_mcp_plugins` | MCP plugin bundles | + +## Using External Services + +- **External PostgreSQL**: Set `PACA_DATABASE_URL` and run with `--scale paca-postgres=0`. +- **AWS S3 instead of MinIO**: Set `PACA_STORAGE_PROVIDER=s3` and run with `--scale paca-minio=0`. +- **External Valkey/Redis**: Set `PACA_REDIS_URL` and run with `--scale paca-valkey=0`. + +## Security Notes + +- Generate strong secrets with `openssl rand -hex 32`. +- Change all default passwords before using in production. +- Set `PACA_COOKIE_SECURE=true` when serving over HTTPS. +- The gateway binds to port 80 by default; use a reverse proxy with TLS for production. +- This stack runs multiple services as root (nginx, postgres); consider hardening for production. + +## Scaling + +You can selectively disable optional services: + +```bash +# Without MinIO (use S3 instead) +docker compose up -d --scale paca-minio=0 + +# Without the web frontend (serve SPA from CDN) +docker compose up -d --scale paca-web=0 +``` diff --git a/apps/paca/README.zh.md b/apps/paca/README.zh.md new file mode 100644 index 0000000..13812e8 --- /dev/null +++ b/apps/paca/README.zh.md @@ -0,0 +1,83 @@ +# Paca + +自托管的项目管理平台,专为人类与 AI 作为 Scrum 团队成员协作而设计。 + +## 服务 + +- `paca-postgres`:PostgreSQL 16 数据库,用于持久化存储。 +- `paca-valkey`:Valkey 8 缓存与发布/订阅事件总线。 +- `paca-minio`:兼容 S3 的 MinIO 对象存储,用于文件上传。 +- `paca-api`:Go 语言 REST API 后端(内部端口 8080)。 +- `paca-web`:React SPA 前端,通过内部 nginx 提供服务(内部端口 3000)。 +- `paca-realtime`:Node.js Socket.IO 实时事件中心(内部端口 3001)。 +- `paca-gateway`:Nginx 反向代理,将所有流量路由到正确的服务。 + +## 快速开始 + +1. 从示例文件创建 `.env` 并设置密钥: + +```bash +cp .env.example .env +# 编辑 .env 文件,设置 PACA_JWT_SECRET、PACA_ENCRYPTION_KEY、PACA_ADMIN_PASSWORD 等 +``` + +1. 启动服务栈: + +```bash +docker compose up -d +``` + +1. 在浏览器中打开 `http://localhost`,使用配置的管理员凭据登录。 + +## 主要环境变量 + +| 变量 | 说明 | 默认值 | +| -------------------------------- | ---------------------------- | ------------------ | +| `PACA_PORT_OVERRIDE` | 网关主机端口 | `80` | +| `PACA_VERSION` | 应用镜像标签 | `latest` | +| `PACA_POSTGRES_PASSWORD` | PostgreSQL 密码 | `changeme` | +| `PACA_ADMIN_USERNAME` | 初始管理员用户名 | `admin` | +| `PACA_ADMIN_PASSWORD` | 初始管理员密码 | `changeme` | +| `PACA_JWT_SECRET` | JWT 签名密钥(至少 32 字符) | (占位符) | +| `PACA_ENCRYPTION_KEY` | 插件密钥 AES-256 加密密钥 | (空) | +| `PACA_PUBLIC_URL` | 公开访问的基础 URL | `http://localhost` | +| `PACA_STORAGE_PROVIDER` | 对象存储提供商 | `minio` | +| `PACA_STORAGE_ACCESS_KEY_ID` | 存储访问密钥 ID | `minioadmin` | +| `PACA_STORAGE_SECRET_ACCESS_KEY` | 存储访问密钥 | `minioadmin` | + +## 存储 + +| 卷 | 用途 | +| ----------------------- | ----------------------- | +| `paca_postgres_data` | PostgreSQL 数据库文件 | +| `paca_valkey_data` | Valkey 追加日志文件 | +| `paca_minio_data` | MinIO 对象存储数据 | +| `paca_backend_plugins` | WASM 后端插件二进制文件 | +| `paca_frontend_plugins` | 前端插件静态资源 | +| `paca_mcp_plugins` | MCP 插件包 | + +## 使用外部服务 + +- **外部 PostgreSQL**:设置 `PACA_DATABASE_URL`,启动时添加 `--scale paca-postgres=0`。 +- **AWS S3 替代 MinIO**:设置 `PACA_STORAGE_PROVIDER=s3`,启动时添加 `--scale paca-minio=0`。 +- **外部 Valkey / Redis**:设置 `PACA_REDIS_URL`,启动时添加 `--scale paca-valkey=0`。 + +## 安全说明 + +- 使用 `openssl rand -hex 32` 生成强密钥。 +- 在生产环境使用前务必修改所有默认密码。 +- 通过 HTTPS 提供服务时,设置 `PACA_COOKIE_SECURE=true`。 +- 网关默认绑定 80 端口;生产环境建议在前方使用带 TLS 的反向代理。 +- 本服务栈中多个服务以 root 运行(nginx、postgres);生产环境建议进一步加固。 + +## 扩缩容 + +可以按需禁用可选服务: + +```bash +# 不使用 MinIO(改用 S3) +docker compose up -d --scale paca-minio=0 + +# 不使用 Web 前端(从 CDN 提供 SPA) +docker compose up -d --scale paca-web=0 +``` diff --git a/apps/paca/docker-compose.yaml b/apps/paca/docker-compose.yaml new file mode 100644 index 0000000..ceb8a54 --- /dev/null +++ b/apps/paca/docker-compose.yaml @@ -0,0 +1,272 @@ +# Paca - Self-hosted project management platform for humans + AI +# https://github.com/Paca-AI/paca +# +# Paca is a project management platform designed for human + AI collaboration +# as Scrum team members. It features a real-time Scrumban board, BDD +# collaborative editing, system design docs, a plugin system (WASM backend + +# frontend modules), and a built-in MCP server. +# +# Key Features: +# - Real-time Scrumban board for task management +# - AI agents as Scrum team members +# - BDD (Behavior-Driven Development) collaborative editor +# - System design documentation +# - Plugin system with WASM backend and frontend modules +# - Built-in MCP (Model Context Protocol) server +# - Connects with Claude and other MCP-compatible clients +# +# Default Access: +# - Access UI at http://localhost (after setting PUBLIC_URL) +# - Default admin: configured via ADMIN_USERNAME / ADMIN_PASSWORD +# +# Security Notes: +# - Change ADMIN_USERNAME and ADMIN_PASSWORD immediately +# - Use strong JWT_SECRET and ENCRYPTION_KEY in production +# - Generate keys with: openssl rand -hex 32 +# - Use STORAGE_PROVIDER=s3 for production instead of bundled MinIO +# - Set COOKIE_SECURE=true when serving over HTTPS +# +# License: AGPL-3.0 (https://github.com/Paca-AI/paca/blob/main/LICENSE) + +x-defaults: &defaults + restart: unless-stopped + logging: + driver: json-file + options: + max-size: 100m + max-file: '3' + +services: + # ── PostgreSQL ────────────────────────────────────────────────────────── + paca-postgres: + <<: *defaults + image: ${GLOBAL_REGISTRY:-}postgres:${PACA_POSTGRES_VERSION:-16-alpine} + environment: + - TZ=${TZ:-UTC} + - POSTGRES_DB=${PACA_POSTGRES_DB:-paca} + - POSTGRES_USER=${PACA_POSTGRES_USER:-paca} + - POSTGRES_PASSWORD=${PACA_POSTGRES_PASSWORD:-changeme} + - PGDATA=/var/lib/postgresql/data/pgdata + volumes: + - paca_postgres_data:/var/lib/postgresql/data + healthcheck: + test: + - CMD-SHELL + - pg_isready -U ${PACA_POSTGRES_USER:-paca} -d ${PACA_POSTGRES_DB:-paca} + interval: 10s + timeout: 5s + retries: 10 + start_period: 10s + deploy: + resources: + limits: + cpus: '${PACA_POSTGRES_CPU_LIMIT:-1.0}' + memory: '${PACA_POSTGRES_MEMORY_LIMIT:-1G}' + reservations: + cpus: '${PACA_POSTGRES_CPU_RESERVATION:-0.1}' + memory: '${PACA_POSTGRES_MEMORY_RESERVATION:-256M}' + + # ── Valkey (Redis-compatible cache / pub-sub) ─────────────────────────── + paca-valkey: + <<: *defaults + image: ${GLOBAL_REGISTRY:-}valkey/valkey:${PACA_VALKEY_VERSION:-8-alpine} + command: valkey-server --appendonly yes + environment: + - TZ=${TZ:-UTC} + volumes: + - paca_valkey_data:/data + healthcheck: + test: + - CMD + - valkey-cli + - ping + interval: 10s + timeout: 5s + retries: 10 + start_period: 5s + deploy: + resources: + limits: + cpus: '${PACA_VALKEY_CPU_LIMIT:-0.5}' + memory: '${PACA_VALKEY_MEMORY_LIMIT:-512M}' + reservations: + cpus: '${PACA_VALKEY_CPU_RESERVATION:-0.1}' + memory: '${PACA_VALKEY_MEMORY_RESERVATION:-128M}' + + # ── MinIO (S3-compatible object store) ────────────────────────────────── + paca-minio: + <<: *defaults + user: root + image: ${CGR_DEV_REGISTRY:-cgr.dev/}chainguard/minio:${PACA_MINIO_VERSION:-latest} + command: server /data --console-address ":9001" + environment: + - TZ=${TZ:-UTC} + - MINIO_ROOT_USER=${PACA_STORAGE_ACCESS_KEY_ID:-minioadmin} + - MINIO_ROOT_PASSWORD=${PACA_STORAGE_SECRET_ACCESS_KEY:-minioadmin} + volumes: + - paca_minio_data:/data + healthcheck: + test: + - CMD + - mc + - ready + - local + interval: 10s + timeout: 5s + retries: 10 + start_period: 10s + deploy: + resources: + limits: + cpus: '${PACA_MINIO_CPU_LIMIT:-0.5}' + memory: '${PACA_MINIO_MEMORY_LIMIT:-512M}' + reservations: + cpus: '${PACA_MINIO_CPU_RESERVATION:-0.1}' + memory: '${PACA_MINIO_MEMORY_RESERVATION:-256M}' + + # ── API (Go backend) ──────────────────────────────────────────────────── + paca-api: + <<: *defaults + image: ${PACA_API_IMAGE:-${GLOBAL_REGISTRY:-}pacaai/paca-api:${PACA_VERSION:-0.5.2}} + environment: + - TZ=${TZ:-UTC} + - ENV=${PACA_ENVIRONMENT:-production} + - PORT=8080 + # Database. Set DATABASE_URL for an external Postgres and scale paca-postgres to 0. + - DATABASE_URL=${PACA_DATABASE_URL:-postgres://${PACA_POSTGRES_USER:-paca}:${PACA_POSTGRES_PASSWORD:-changeme}@paca-postgres:5432/${PACA_POSTGRES_DB:-paca}?sslmode=disable} + - REDIS_URL=${PACA_REDIS_URL:-redis://paca-valkey:6379/0} + - JWT_SECRET=${PACA_JWT_SECRET:-changeme_jwt_secret_minimum_32_chars} + - JWT_ACCESS_TTL=${PACA_JWT_ACCESS_TTL:-15m} + - JWT_REFRESH_TTL=${PACA_JWT_REFRESH_TTL:-168h} + - JWT_REFRESH_SESSION_TTL=${PACA_JWT_REFRESH_SESSION_TTL:-24h} + - COOKIE_SECURE=${PACA_COOKIE_SECURE:-false} + - ADMIN_USERNAME=${PACA_ADMIN_USERNAME:-admin} + - ADMIN_PASSWORD=${PACA_ADMIN_PASSWORD:-changeme} + # Object storage. Set STORAGE_PROVIDER=s3 for AWS S3 and scale paca-minio to 0. + - STORAGE_PROVIDER=${PACA_STORAGE_PROVIDER:-minio} + - STORAGE_ENDPOINT=${PACA_STORAGE_ENDPOINT:-paca-minio:9000} + - STORAGE_PUBLIC_URL=${PACA_STORAGE_PUBLIC_URL:-http://localhost/storage} + - STORAGE_REGION=${PACA_STORAGE_REGION:-us-east-1} + - STORAGE_BUCKET=${PACA_STORAGE_BUCKET:-paca} + - STORAGE_ACCESS_KEY_ID=${PACA_STORAGE_ACCESS_KEY_ID:-minioadmin} + - STORAGE_SECRET_ACCESS_KEY=${PACA_STORAGE_SECRET_ACCESS_KEY:-minioadmin} + - STORAGE_USE_SSL=${PACA_STORAGE_USE_SSL:-false} + - ENCRYPTION_KEY=${PACA_ENCRYPTION_KEY:-} + - PUBLIC_URL=${PACA_PUBLIC_URL:-http://localhost} + # Plugin directories + - PLUGINS_WASM_DIR=/plugins + - PLUGINS_FRONTEND_DIR=/plugins-frontend + - PLUGINS_MCP_DIR=/plugins-mcp + # Pre-shared key for AI agent integration + - AGENT_API_KEY=${PACA_AGENT_API_KEY:-} + depends_on: + paca-postgres: + condition: service_healthy + paca-valkey: + condition: service_healthy + paca-minio: + condition: service_healthy + volumes: + - paca_backend_plugins:/plugins + - paca_frontend_plugins:/plugins-frontend + - paca_mcp_plugins:/plugins-mcp + healthcheck: + test: + - CMD + - wget + - --no-verbose + - --tries=1 + - --spider + - http://localhost:8080/api/healthz + interval: 10s + timeout: 5s + retries: 10 + start_period: 40s + deploy: + resources: + limits: + cpus: '${PACA_API_CPU_LIMIT:-1.0}' + memory: '${PACA_API_MEMORY_LIMIT:-1G}' + reservations: + cpus: '${PACA_API_CPU_RESERVATION:-0.1}' + memory: '${PACA_API_MEMORY_RESERVATION:-256M}' + + # ── Web (React SPA served via nginx) ──────────────────────────────────── + paca-web: + <<: *defaults + image: ${PACA_WEB_IMAGE:-${GLOBAL_REGISTRY:-}pacaai/paca-web:${PACA_VERSION:-0.5.2}} + environment: + - TZ=${TZ:-UTC} + depends_on: + paca-api: + condition: service_healthy + deploy: + resources: + limits: + cpus: '${PACA_WEB_CPU_LIMIT:-0.5}' + memory: '${PACA_WEB_MEMORY_LIMIT:-512M}' + reservations: + cpus: '${PACA_WEB_CPU_RESERVATION:-0.1}' + memory: '${PACA_WEB_MEMORY_RESERVATION:-128M}' + + # ── Realtime (Socket.IO event hub) ────────────────────────────────────── + paca-realtime: + <<: *defaults + image: ${PACA_REALTIME_IMAGE:-${GLOBAL_REGISTRY:-}pacaai/paca-realtime:${PACA_VERSION:-0.5.2}} + environment: + - TZ=${TZ:-UTC} + - PORT=3001 + - NODE_ENV=${PACA_ENVIRONMENT:-production} + - API_URL=http://paca-api:8080 + - REDIS_URL=${PACA_REDIS_URL:-redis://paca-valkey:6379/0} + - CORS_ORIGINS=${PACA_CORS_ORIGINS:-${PACA_PUBLIC_URL:-http://localhost}} + - LOG_LEVEL=${LOG_LEVEL:-info} + depends_on: + paca-valkey: + condition: service_healthy + paca-api: + condition: service_healthy + deploy: + resources: + limits: + cpus: '${PACA_REALTIME_CPU_LIMIT:-0.5}' + memory: '${PACA_REALTIME_MEMORY_LIMIT:-512M}' + reservations: + cpus: '${PACA_REALTIME_CPU_RESERVATION:-0.1}' + memory: '${PACA_REALTIME_MEMORY_RESERVATION:-128M}' + + # ── Gateway (nginx reverse proxy) ─────────────────────────────────────── + paca-gateway: + <<: *defaults + image: ${GLOBAL_REGISTRY:-}nginx:${PACA_NGINX_VERSION:-1.27-alpine} + ports: + - '${PACA_PORT_OVERRIDE:-80}:80' + environment: + - TZ=${TZ:-UTC} + volumes: + - ./gateway.conf:/etc/nginx/conf.d/default.conf:ro + - paca_frontend_plugins:/var/www/plugins:ro + - paca_mcp_plugins:/var/www/plugins-mcp:ro + depends_on: + paca-api: + condition: service_started + paca-web: + condition: service_started + paca-realtime: + condition: service_started + deploy: + resources: + limits: + cpus: '${PACA_GATEWAY_CPU_LIMIT:-0.5}' + memory: '${PACA_GATEWAY_MEMORY_LIMIT:-256M}' + reservations: + cpus: '${PACA_GATEWAY_CPU_RESERVATION:-0.1}' + memory: '${PACA_GATEWAY_MEMORY_RESERVATION:-128M}' + +volumes: + paca_postgres_data: + paca_valkey_data: + paca_minio_data: + paca_backend_plugins: + paca_frontend_plugins: + paca_mcp_plugins: diff --git a/apps/paca/gateway.conf b/apps/paca/gateway.conf new file mode 100644 index 0000000..60d5bd5 --- /dev/null +++ b/apps/paca/gateway.conf @@ -0,0 +1,161 @@ +# ============================================================================= +# Gateway nginx configuration for Paca +# ============================================================================= +# +# Single public entrypoint for the Paca stack: +# /api/* → REST API service +# /ws/* → Realtime service (Socket.IO) +# /storage/* → MinIO object storage +# /* → Web application (SPA) +# +# Mounted as /etc/nginx/conf.d/default.conf inside the nginx container. + +# -- Rate-limit zones --------------------------------------------------------- +limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s; + +# -- WebSocket connection upgrade map ----------------------------------------- +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +# Resolve Docker service names for variable-based proxy_pass targets. +resolver 127.0.0.11 ipv6=off valid=30s; + +# -- Upstream pools ----------------------------------------------------------- +upstream api_backend { + server paca-api:8080; + keepalive 32; +} + +upstream realtime_backend { + server paca-realtime:3001; + keepalive 16; +} + +# ============================================================================= +server { + listen 80; + server_name _; + + server_tokens off; + client_max_body_size 10m; + + # -- Compression ---------------------------------------------------------- + gzip on; + gzip_proxied any; + gzip_comp_level 5; + gzip_min_length 256; + gzip_types + application/javascript + application/json + application/wasm + font/woff + font/woff2 + image/svg+xml + text/css + text/plain; + + # -- Security headers ----------------------------------------------------- + add_header X-Frame-Options "DENY" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; + add_header X-XSS-Protection "0" always; + + # ========================================================================= + # Routing + # ========================================================================= + + # -- Object storage (MinIO) ----------------------------------------------- + location /storage/ { + set $minio_backend http://paca-minio:9000; + rewrite ^/storage/(.*)$ /$1 break; + proxy_pass $minio_backend; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host minio:9000; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + client_max_body_size 0; + proxy_request_buffering off; + proxy_connect_timeout 10s; + proxy_send_timeout 120s; + proxy_read_timeout 120s; + } + + # -- Realtime service (Socket.IO) ----------------------------------------- + location /ws/ { + proxy_pass http://realtime_backend/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_connect_timeout 10s; + proxy_send_timeout 60s; + proxy_read_timeout 3600s; + } + + # -- API routes ----------------------------------------------------------- + location /api/ { + limit_req zone=api burst=50 nodelay; + limit_req_status 429; + + proxy_pass http://api_backend/api/; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_connect_timeout 10s; + proxy_send_timeout 30s; + proxy_read_timeout 30s; + } + + # -- Local plugin frontend assets ----------------------------------------- + location /plugins/ { + alias /var/www/plugins/; + autoindex off; + types { + application/javascript js; + application/wasm wasm; + text/css css; + text/html html; + image/svg+xml svg; + font/woff woff; + font/woff2 woff2; + } + add_header Cache-Control "public, max-age=900, immutable" always; + } + + # -- MCP plugin bundles --------------------------------------------------- + location /plugins-mcp/ { + alias /var/www/plugins-mcp/; + autoindex off; + types { + application/javascript js; + } + add_header Cache-Control "public, max-age=900, immutable" always; + } + + # -- Web application (SPA) ------------------------------------------------ + location / { + set $web_backend http://paca-web:3000; + proxy_pass $web_backend; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_connect_timeout 10s; + proxy_send_timeout 30s; + proxy_read_timeout 30s; + } +} diff --git a/src/minio/.env.example b/src/minio/.env.example index 5eb1c1d..9ff66eb 100644 --- a/src/minio/.env.example +++ b/src/minio/.env.example @@ -1,5 +1,5 @@ # MinIO Version (Chainguard Image) -MINIO_VERSION=0.20251015 +MINIO_VERSION=latest # MinIO Root User Credentials MINIO_ROOT_USER=minioadmin @@ -16,4 +16,4 @@ TZ=UTC MINIO_CPU_LIMIT=0.5 MINIO_MEMORY_LIMIT=1G MINIO_CPU_RESERVATION=0.1 -MINIO_MEMORY_RESERVATION=512M \ No newline at end of file +MINIO_MEMORY_RESERVATION=512M diff --git a/src/minio/README.md b/src/minio/README.md index 4ba66e3..f8de180 100644 --- a/src/minio/README.md +++ b/src/minio/README.md @@ -12,7 +12,7 @@ Open the Web UI: . ## Configuration -- `MINIO_VERSION`: The version of the MinIO image, default is `0.20251015`. +- `MINIO_VERSION`: The version of the MinIO image, default is `latest`. - `MINIO_PORT_OVERRIDE_API`: The host port for the MinIO API, default is `9000`. - `MINIO_PORT_OVERRIDE_WEBUI`: The host port for the MinIO Web UI, default is `9001`. - `MINIO_ROOT_USER`: The root username for MinIO, default is `minioadmin`. diff --git a/src/minio/README.zh.md b/src/minio/README.zh.md index 3a11edd..5539e29 100644 --- a/src/minio/README.zh.md +++ b/src/minio/README.zh.md @@ -12,7 +12,7 @@ MinIO 是一个高性能的 S3 兼容对象存储系统,可以用于存储和 ## 配置 -- `MINIO_VERSION`: MinIO 镜像的版本,默认为 `0.20251015`。 +- `MINIO_VERSION`: MinIO 镜像的版本,默认为 `latest`。 - `MINIO_PORT_OVERRIDE_API`: MinIO API 的主机端口,默认为 `9000`。 - `MINIO_PORT_OVERRIDE_WEBUI`: MinIO Web UI 的主机端口,默认为 `9001`。 - `MINIO_ROOT_USER`: MinIO 的根用户名,默认为 `minioadmin`。 diff --git a/src/minio/docker-compose.yaml b/src/minio/docker-compose.yaml index 6bee9b6..3c5f023 100644 --- a/src/minio/docker-compose.yaml +++ b/src/minio/docker-compose.yaml @@ -1,3 +1,4 @@ +# https://images.chainguard.dev/directory/image/minio/versions#/ x-defaults: &defaults restart: unless-stopped logging: @@ -9,7 +10,7 @@ x-defaults: &defaults services: minio: <<: *defaults - image: ${CGR_DEV_REGISTRY:cgr.dev-}/chainguard/minio:${MINIO_VERSION:-0.20251015} + image: ${CGR_DEV_REGISTRY:cgr.dev-}/chainguard/minio:${MINIO_VERSION:-latest} ports: - '${MINIO_PORT_OVERRIDE_API:-9000}:9000' - '${MINIO_PORT_OVERRIDE_WEBUI:-9001}:9001'