# ============================================================
# Ruflo RVFA Appliance Builder
# ADR-058: Self-Contained Ruflo RVF Appliance
#
# Builds the rootfs layers for an RVFA appliance.
# Usage:
#   docker build -f Dockerfile.appliance -t ruflo-appliance:build .
#   docker run --rm ruflo-appliance:build ruflo --version
#   docker run --rm ruflo-appliance:build ruflo doctor
#   docker run --rm -i ruflo-appliance:build ruflo mcp start
# ============================================================

# ------------------------------------------------------------------
# Stage 1: Build — install Ruflo with dependencies
# ------------------------------------------------------------------
FROM node:22-alpine AS build

# Install dumb-init for proper PID 1 signal handling
# and git for any npm packages that need it during install
RUN apk add --no-cache dumb-init git

WORKDIR /build

# Install Ruflo globally.
# --omit=optional: skip heavy native deps (onnxruntime, better-sqlite3, etc.)
# --ignore-scripts: skip postinstall scripts that may compile native addons
# These keep the image under the 100MB target.
RUN npm install -g ruflo@latest \
      --omit=optional \
      --ignore-scripts \
      --no-audit \
      --no-fund \
    && npm cache clean --force

# Strip files that are never needed at runtime.
# This typically saves 5-15MB depending on dependency tree.
RUN GLOBAL_NM="$(npm config get prefix)/lib/node_modules" \
    && find "$GLOBAL_NM" -type f \( \
         -name "*.md" -o \
         -name "*.map" -o \
         -name "*.d.ts" -o \
         -name "*.ts" ! -name "*.d.ts" -o \
         -name "CHANGELOG*" -o \
         -name "LICENSE*" -o \
         -name ".npmignore" -o \
         -name ".eslintrc*" -o \
         -name ".prettierrc*" -o \
         -name "tsconfig.json" -o \
         -name "jest.config*" -o \
         -name "vitest.config*" \
       \) -delete 2>/dev/null || true \
    && find "$GLOBAL_NM" -type d \( \
         -name ".github" -o \
         -name "test" -o \
         -name "tests" -o \
         -name "__tests__" -o \
         -name "docs" -o \
         -name "examples" -o \
         -name "benchmark" \
       \) -exec rm -rf {} + 2>/dev/null || true

# Prune known-heavy optional transitive dependencies.
# The CLI has graceful fallbacks for all of these.
RUN GLOBAL_NM="$(npm config get prefix)/lib/node_modules" \
    && rm -rf \
       "$GLOBAL_NM/ruflo/node_modules/agentic-flow" \
       "$GLOBAL_NM/ruflo/node_modules/@opentelemetry" \
       "$GLOBAL_NM/ruflo/node_modules/onnxruntime-node" \
       "$GLOBAL_NM/ruflo/node_modules/onnxruntime-web" \
       "$GLOBAL_NM/ruflo/node_modules/onnx-proto" \
       "$GLOBAL_NM/ruflo/node_modules/@anthropic-ai" \
       "$GLOBAL_NM/ruflo/node_modules/@xenova" \
       "$GLOBAL_NM/ruflo/node_modules/agentdb" \
       "$GLOBAL_NM/ruflo/node_modules/@ruvector" \
       "$GLOBAL_NM/ruflo/node_modules/ruvector" \
       "$GLOBAL_NM/ruflo/node_modules/tiktoken" \
       "$GLOBAL_NM/ruflo/node_modules/@img" \
       "$GLOBAL_NM/ruflo/node_modules/better-sqlite3" \
       "$GLOBAL_NM/ruflo/node_modules/sharp" \
       "$GLOBAL_NM/ruflo/node_modules/@google" \
       "$GLOBAL_NM/ruflo/node_modules/@claude-flow/embeddings" \
       "$GLOBAL_NM/ruflo/node_modules/@claude-flow/codex" \
       "$GLOBAL_NM/ruflo/node_modules/@claude-flow/guidance" \
       "$GLOBAL_NM/ruflo/node_modules/@claude-flow/neural" \
       "$GLOBAL_NM/ruflo/node_modules/@grpc" \
       "$GLOBAL_NM/ruflo/node_modules/gun" \
    2>/dev/null || true

# Stage the pruned install into /staged for a clean COPY
RUN GLOBAL_PREFIX="$(npm config get prefix)" \
    && mkdir -p /staged/lib /staged/bin \
    && cp -a "$GLOBAL_PREFIX/lib/node_modules" /staged/lib/ \
    && cp -a "$GLOBAL_PREFIX/bin/ruflo" /staged/bin/ 2>/dev/null || true \
    && cp -a "$GLOBAL_PREFIX/bin/claude-flow" /staged/bin/ 2>/dev/null || true

# ------------------------------------------------------------------
# Stage 2: Production — minimal Alpine runtime
# ------------------------------------------------------------------
FROM node:22-alpine AS production

# Runtime dependencies only:
#   dumb-init  — proper signal forwarding for PID 1
#   ca-certs   — TLS for cloud API calls
#   bash       — shell scripts in hooks
RUN apk add --no-cache \
      dumb-init \
      ca-certificates \
      bash

# Create non-root user for the appliance
RUN addgroup -g 1001 -S ruflo \
    && adduser -S -D -H -u 1001 -h /home/ruflo -s /bin/bash -G ruflo ruflo \
    && mkdir -p /home/ruflo/.ruflo /home/ruflo/data \
    && chown -R ruflo:ruflo /home/ruflo

# Copy only the global node_modules and bin links from the build stage
COPY --from=build /staged/lib/node_modules /usr/local/lib/node_modules
COPY --from=build /staged/bin/ /usr/local/bin/
COPY --from=build /usr/bin/dumb-init /usr/bin/dumb-init

# Ensure bin symlinks resolve correctly
RUN ln -sf /usr/local/lib/node_modules/ruflo/bin/ruflo.js /usr/local/bin/ruflo 2>/dev/null || true \
    && chmod +x /usr/local/bin/ruflo 2>/dev/null || true

# Production environment
ENV NODE_ENV=production \
    RUFLO_HOME=/home/ruflo/.ruflo \
    CLAUDE_FLOW_MEMORY_PATH=/home/ruflo/data/memory \
    CLAUDE_FLOW_LOG_LEVEL=info

# Switch to non-root user
USER ruflo
WORKDIR /home/ruflo

# Volumes for persistent data across container restarts
VOLUME ["/home/ruflo/data"]

# Health check via the doctor command
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
    CMD ruflo doctor -c version || exit 1

# Use dumb-init as PID 1 for proper signal handling
ENTRYPOINT ["dumb-init", "--"]

# Default: print help. Override with:
#   docker run --rm ruflo-appliance:build ruflo mcp start
#   docker run --rm ruflo-appliance:build ruflo doctor
CMD ["ruflo", "--help"]
