FROM node:22-bookworm-slim AS frontend-builder WORKDIR /app COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ RUN corepack enable && pnpm install --frozen-lockfile COPY index.html postcss.config.js tailwind.config.ts tsconfig.json tsconfig.app.json tsconfig.node.json vite.config.ts components.json ./ COPY public ./public COPY src ./src ARG VITE_APPOPS_API_MODE=live ARG VITE_APPOPS_API_BASE_URL= ENV VITE_APPOPS_API_MODE=${VITE_APPOPS_API_MODE} \ VITE_APPOPS_API_BASE_URL=${VITE_APPOPS_API_BASE_URL} RUN pnpm run build FROM python:3.13-slim AS runtime ARG APPOPS_BUILD_ID=development ARG APPOPS_SOURCE_REVISION=development ARG APPOPS_SOURCE_REPOSITORY=local/unraid-appops-gateway ARG APPOPS_SOURCE_TREE=development ARG APPOPS_BUILD_DATE=1970-01-01T00:00:00Z LABEL org.opencontainers.image.title="Unraid AppOps Gateway" \ org.opencontainers.image.description="Local-first, policy-gated operations gateway for Unraid and connected services" \ org.opencontainers.image.version="${APPOPS_BUILD_ID}" \ org.opencontainers.image.revision="${APPOPS_SOURCE_REVISION}" \ org.opencontainers.image.source="${APPOPS_SOURCE_REPOSITORY}" \ org.opencontainers.image.source-tree="${APPOPS_SOURCE_TREE}" \ org.opencontainers.image.created="${APPOPS_BUILD_DATE}" \ io.itworx.app.version="1.8.0" \ io.itworx.app.user-auth="oidc-rbac" \ org.opencontainers.image.vendor="AppOps" \ net.unraid.docker.managed="dockerman" \ net.unraid.docker.webui="http://[IP]:[PORT:1216]/" \ net.unraid.docker.icon="/boot/config/plugins/dockerMan/images/unraid-appops-gateway.png" ENV APPOPS_ENV=production \ APPOPS_DEPLOYMENT_MODE=private \ APP_OPS_VOICE_TOKEN_FILE=/data/voice-token \ APPOPS_BIND_HOST=0.0.0.0 \ APPOPS_PORT=1216 \ APPOPS_DATA_DIR=/data \ APPOPS_DB_PATH=/data/appops.db \ APPOPS_STATIC_DIR=/app/dist \ APPOPS_LOG_LEVEL=info \ APPOPS_DISCOVERY_HISTORY_RUNS=48 \ APPOPS_ENABLE_MCP=false \ APPOPS_MCP_TOKEN_FILE=/data/mcp-token \ APPOPS_MCP_ALLOWED_HOSTS=localhost:*,127.0.0.1:* \ APPOPS_ENABLE_N8N=false \ APPOPS_N8N_TOKEN_FILE=/data/n8n-token \ PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 WORKDIR /app RUN mkdir -p /etc/appops && printf '%s\n' "$APPOPS_SOURCE_REPOSITORY" "$APPOPS_SOURCE_REVISION" "$APPOPS_SOURCE_TREE" > /etc/appops/source-metadata && chmod 0444 /etc/appops/source-metadata RUN apt-get update \ && apt-get install -y --no-install-recommends gosu \ && rm -rf /var/lib/apt/lists/* \ && addgroup --system appops && adduser --system --ingroup appops appops \ && adduser appops users \ && mkdir -p /data \ && chown -R appops:appops /data /app COPY backend/requirements.txt /tmp/requirements.txt RUN pip install --no-cache-dir -r /tmp/requirements.txt COPY backend/app ./backend/app COPY README.md CHANGELOG.md ./ COPY --from=frontend-builder /app/dist ./dist COPY docker/entrypoint.sh /entrypoint.sh RUN sed -i 's/\r$//' /entrypoint.sh && chmod +x /entrypoint.sh EXPOSE 1216 VOLUME ["/data"] HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:1216/api/health', timeout=3).read()" ENTRYPOINT ["/entrypoint.sh"] CMD ["uvicorn", "backend.app.main:app", "--host", "0.0.0.0", "--port", "1216"]