End-to-end Phase 1 of shared-memory: a logged-in Authentik user can sign into the Web UI (/me debug page), and an MCP client with an Authentik- issued bearer token can call memory.write / memory.list / memory.get / memory.delete plus project.identify against /api/mcp. Stack: - Next.js 15 (App Router) + React 19 + TypeScript, pnpm workspaces - Drizzle ORM + Postgres 16 + pgvector + pg_trgm - Auth.js v5 with Authentik provider (Web UI) - jose + Authentik JWKS for MCP bearer-token validation - JSON-RPC 2.0 dispatcher implementing the MCP wire protocol over plain HTTP POST (hand-rolled to fit Next.js App Router; switches to SSE in a later phase if server-initiated events are needed) - bge-small embeddings sidecar deferred to Phase 2; the schema already reserves the vector(384) column + IVFFlat index, FTS via a STORED tsvector column, and the visibility enum (private/shared/team) so cross-user memory sharing can be added without a future migration Deployment supports two modes (set in .env, never committed): - Behind an external reverse proxy (HAProxy / nginx / Cloudflare Tunnel / Traefik) — DEFAULT; the app exposes APP_PORT on the host with X-Forwarded-* trusted, no in-container TLS - Built-in TLS via Caddy — opt-in with `docker compose --profile tls up` Discovery endpoint at /.well-known/oauth-protected-resource (RFC 9728) points MCP clients at the Authentik authorization server after a 401. README walks through both Authentik providers (Web UI + MCP resource server), the audience scope mapping, redirect URIs, and includes a worked HAProxy config snippet. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
69 lines
2.6 KiB
Docker
69 lines
2.6 KiB
Docker
# syntax=docker/dockerfile:1.7
|
|
# -----------------------------------------------------------------------------
|
|
# Multi-stage build for @shared-memory/web.
|
|
#
|
|
# deps — pnpm install with workspace context
|
|
# builder — next build (standalone) + bundled migrator
|
|
# runner — minimal Node runtime, non-root, runs server.js
|
|
#
|
|
# Build from the repo root:
|
|
# docker build -t shared-memory-web -f apps/web/Dockerfile .
|
|
# -----------------------------------------------------------------------------
|
|
|
|
FROM node:20-alpine AS base
|
|
RUN corepack enable
|
|
WORKDIR /app
|
|
|
|
# ---------- deps ----------
|
|
FROM base AS deps
|
|
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml .npmrc ./
|
|
COPY apps/web/package.json ./apps/web/
|
|
COPY packages/schemas/package.json ./packages/schemas/
|
|
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
|
|
pnpm install --frozen-lockfile
|
|
|
|
# ---------- builder ----------
|
|
FROM base AS builder
|
|
COPY --from=deps /app/node_modules ./node_modules
|
|
COPY --from=deps /app/apps/web/node_modules ./apps/web/node_modules
|
|
COPY . .
|
|
|
|
# Build the Next.js standalone bundle. Env validation is bypassed here so
|
|
# the image can be built without real OIDC/DB secrets baked in; runtime
|
|
# validation in `env.ts` re-checks all vars on first request.
|
|
ENV SKIP_ENV_VALIDATION=true \
|
|
NEXT_TELEMETRY_DISABLED=1
|
|
RUN pnpm --filter @shared-memory/web build
|
|
|
|
# Bundle the migrator into a single ESM file so the runtime image doesn't
|
|
# need tsx or the rest of devDependencies.
|
|
RUN pnpm --filter @shared-memory/web exec esbuild apps/web/scripts/migrate.ts \
|
|
--bundle --platform=node --target=node20 --format=esm \
|
|
--outfile=apps/web/migrate.mjs
|
|
|
|
# ---------- runner ----------
|
|
FROM node:20-alpine AS runner
|
|
WORKDIR /app
|
|
ENV NODE_ENV=production \
|
|
PORT=3000 \
|
|
HOSTNAME=0.0.0.0 \
|
|
NEXT_TELEMETRY_DISABLED=1
|
|
|
|
# `wget` is alpine's tiny default; used by the docker healthcheck.
|
|
RUN addgroup --system --gid 1001 nodejs \
|
|
&& adduser --system --uid 1001 --ingroup nodejs nextjs
|
|
|
|
# Standalone bundle includes traced node_modules + server.js.
|
|
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/standalone ./
|
|
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static
|
|
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public
|
|
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/drizzle ./apps/web/drizzle
|
|
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/migrate.mjs ./apps/web/migrate.mjs
|
|
|
|
USER nextjs
|
|
EXPOSE 3000
|
|
|
|
# Default command runs the server. The compose `migrator` service overrides
|
|
# this to run migrations once before the app comes up.
|
|
CMD ["node", "apps/web/server.js"]
|