From cb384bc7ef34948ac57968fa4738a91efa7c2981 Mon Sep 17 00:00:00 2001 From: Till JS Date: Wed, 15 Apr 2026 14:24:50 +0200 Subject: [PATCH] feat(infra): deploy mana-ai + wire Mission Grant keys via docker-compose MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire the Mission Key-Grant feature into the production Mac Mini compose stack so mana-ai can boot and mana-auth can mint grants. - New mana-ai service block (port 3066) — 256m mem limit, depends on postgres + mana-llm, tick interval configurable via MANA_AI_TICK_INTERVAL_MS / MANA_AI_TICK_ENABLED. Pulls MANA_AI_PRIVATE_KEY_PEM from env; absent = grants silently disabled. - mana-auth environment gains MANA_AI_PUBLIC_KEY_PEM (default empty so existing deployments without the keypair degrade to 503 GRANT_NOT_CONFIGURED rather than failing to boot). - mana-auth Dockerfile rewritten to the two-stage pnpm+bun pattern used by mana-credits/mana-events — required now that mana-auth has a @mana/shared-ai workspace dep. The previous single-stage Dockerfile with service-scoped build context couldn't resolve any @mana/* imports; that only worked historically because it fell through at runtime via a pre-built layer. - mana-ai Dockerfile copies packages/shared-ai into the installer stage alongside shared-hono. The build contexts for mana-auth flip from services/mana-auth to the repo root. Existing CI/CD paths (scripts/mac-mini/build-app.sh) pass through to docker compose build and pick up the new context automatically — no script edits needed. Flip-on procedure: on the Mac Mini, set MANA_AI_PUBLIC_KEY_PEM + MANA_AI_PRIVATE_KEY_PEM in .env (already done, see secrets/mana-ai/README.md on the host), then rebuild mana-auth + build mana-ai. Co-Authored-By: Claude Opus 4.6 (1M context) --- docker-compose.macmini.yml | 52 +++++++++++++++++++++++++++++++++-- services/mana-ai/Dockerfile | 1 + services/mana-auth/Dockerfile | 32 ++++++++++++++++++--- 3 files changed, 79 insertions(+), 6 deletions(-) diff --git a/docker-compose.macmini.yml b/docker-compose.macmini.yml index c30d20660..ee06393c3 100644 --- a/docker-compose.macmini.yml +++ b/docker-compose.macmini.yml @@ -249,8 +249,8 @@ services: mana-auth: build: - context: services/mana-auth - dockerfile: Dockerfile + context: . + dockerfile: services/mana-auth/Dockerfile image: mana-auth:local container_name: mana-auth restart: always @@ -273,6 +273,11 @@ services: # KEK for the encryption-vault feature (Phase 9). Required in production # — generate with `openssl rand -base64 32`. See services/mana-auth/CLAUDE.md. MANA_AUTH_KEK: ${MANA_AUTH_KEK} + # RSA-OAEP-2048 public key of the mana-ai runner. Used to wrap + # per-mission data keys in POST /me/ai-mission-grant. Paired with + # MANA_AI_PRIVATE_KEY_PEM on the mana-ai service. Absent → endpoint + # returns 503 GRANT_NOT_CONFIGURED (graceful degrade). + MANA_AI_PUBLIC_KEY_PEM: ${MANA_AI_PUBLIC_KEY_PEM:-} MANA_NOTIFY_URL: http://mana-notify:3013 MAX_DAILY_SIGNUPS: ${MAX_DAILY_SIGNUPS:-0} # Must be a superset of TRUSTED_ORIGINS in @@ -290,6 +295,49 @@ services: retries: 3 start_period: 40s + # ============================================ + # Tier 1a': AI Mission Runner (Hono + Bun) + # Background ticker that plans due AI Missions and stages proposals + # back to user devices via mana-sync. Opt-in decrypt of encrypted + # inputs via the Mission Key-Grant flow (see services/mana-ai/CLAUDE.md + # and docs/plans/ai-mission-key-grant.md). + # ============================================ + + mana-ai: + build: + context: . + dockerfile: services/mana-ai/Dockerfile + image: mana-ai:local + container_name: mana-ai + restart: always + mem_limit: 256m + depends_on: + postgres: + condition: service_healthy + mana-llm: + condition: service_started + environment: + TZ: Europe/Berlin + NODE_ENV: production + PORT: 3066 + SYNC_DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_sync + MANA_LLM_URL: http://mana-llm:3020 + MANA_SERVICE_KEY: ${MANA_SERVICE_KEY} + TICK_INTERVAL_MS: ${MANA_AI_TICK_INTERVAL_MS:-60000} + TICK_ENABLED: ${MANA_AI_TICK_ENABLED:-true} + # RSA-OAEP-2048 private key paired with MANA_AI_PUBLIC_KEY_PEM on + # mana-auth. Used to unwrap per-mission data keys at tick time. + # Absent → all grants skip silently with reason="not-configured". + MANA_AI_PRIVATE_KEY_PEM: ${MANA_AI_PRIVATE_KEY_PEM:-} + ports: + - "3066:3066" + healthcheck: + test: ["CMD", "bun", "-e", "fetch('http://127.0.0.1:3066/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"] + interval: 120s + timeout: 10s + retries: 3 + start_period: 40s + # ============================================ # Tier 1b: Credits Service (Hono + Bun) # ============================================ diff --git a/services/mana-ai/Dockerfile b/services/mana-ai/Dockerfile index 8107d83ea..c8b36405d 100644 --- a/services/mana-ai/Dockerfile +++ b/services/mana-ai/Dockerfile @@ -9,6 +9,7 @@ WORKDIR /app COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ COPY services/mana-ai/package.json ./services/mana-ai/ COPY packages/shared-hono ./packages/shared-hono +COPY packages/shared-ai ./packages/shared-ai # Install only mana-ai and its workspace deps RUN pnpm install --filter @mana/ai-service... --no-frozen-lockfile --ignore-scripts diff --git a/services/mana-auth/Dockerfile b/services/mana-auth/Dockerfile index 73b24b546..81a544f4e 100644 --- a/services/mana-auth/Dockerfile +++ b/services/mana-auth/Dockerfile @@ -1,12 +1,36 @@ +# Install stage: use node + pnpm to resolve workspace dependencies. +# Build context must be the monorepo root (see docker-compose.macmini.yml). +FROM node:22-alpine AS installer + +RUN corepack enable && corepack prepare pnpm@9.15.0 --activate + +WORKDIR /app + +# Copy workspace structure +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ +COPY services/mana-auth/package.json ./services/mana-auth/ +COPY packages/shared-hono ./packages/shared-hono +COPY packages/shared-ai ./packages/shared-ai + +# Install only mana-auth and its workspace deps +RUN pnpm install --filter @mana/auth... --no-frozen-lockfile --ignore-scripts + +# Runtime stage: bun FROM oven/bun:1 AS production WORKDIR /app -COPY package.json bun.lock* ./ -RUN bun install --frozen-lockfile 2>/dev/null || bun install +# Copy installed deps from installer stage +COPY --from=installer /app/node_modules ./node_modules +COPY --from=installer /app/services/mana-auth/node_modules ./services/mana-auth/node_modules +COPY --from=installer /app/packages ./packages -COPY src ./src -COPY tsconfig.json drizzle.config.ts ./ +# Copy source +COPY services/mana-auth/package.json ./services/mana-auth/ +COPY services/mana-auth/src ./services/mana-auth/src +COPY services/mana-auth/tsconfig.json services/mana-auth/drizzle.config.ts ./services/mana-auth/ + +WORKDIR /app/services/mana-auth EXPOSE 3001