Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dist
coverage

# Logs
*.log
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
Expand All @@ -24,12 +25,12 @@ lerna-debug.log*

# Documentation
*.md
!README.md

# Test files
test
*.spec.ts
*.test.ts
__tests__

# IDE
.vscode
Expand All @@ -51,9 +52,26 @@ docker-compose*.yml
.github
.gitlab-ci.yml

# Misc
# Plugin packages (not needed for server build)
packages/oer-finder-plugin
packages/oer-finder-plugin-react
packages/oer-finder-plugin-example
packages/oer-finder-plugin-react-example
packages/oer-finder-api-client

# Tool data
nak-data

# Config files not needed in build
.editorconfig
.prettierrc
.eslintrc.js
.prettierignore
.claude

# Preserve files needed for build
!tsconfig.json
!tsconfig.build.json
!nest-cli.json
!package.json
!pnpm-workspace.yaml
!pnpm-lock.yaml
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
inject-workspace-packages=true
63 changes: 48 additions & 15 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,45 +1,78 @@
FROM node:24 AS base

# Enable pnpm via corepack (recommended method)
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN corepack enable && corepack prepare pnpm@10 --activate

ENV APP_PATH=/home/node/app
WORKDIR $APP_PATH

# Ensure the directory is owned by node user before switching
RUN chown -R node:node $APP_PATH

USER node

FROM base AS development

# Switch back to root to install system packages
USER root

RUN apt update && apt install -y \
RUN apt-get update && apt-get install -y --no-install-recommends \
jq \
make \
g++ \
python3 \
vim \
curl \
python3-pip
python3-pip \
&& rm -rf /var/lib/apt/lists/*

USER node

FROM base AS production
FROM base AS build

ARG PROD_PATH=/home/node/prod

COPY --chown=node:node package.json pnpm-workspace.yaml pnpm-lock.yaml .npmrc ./
COPY --chown=node:node packages/oer-adapter-core/package.json ./packages/oer-adapter-core/
COPY --chown=node:node packages/oer-adapter-nostr-amb-relay/package.json ./packages/oer-adapter-nostr-amb-relay/
COPY --chown=node:node packages/oer-adapter-arasaac/package.json ./packages/oer-adapter-arasaac/
COPY --chown=node:node packages/oer-adapter-openverse/package.json ./packages/oer-adapter-openverse/
COPY --chown=node:node packages/oer-adapter-rpi-virtuell/package.json ./packages/oer-adapter-rpi-virtuell/
COPY --chown=node:node packages/oer-adapter-wikimedia/package.json ./packages/oer-adapter-wikimedia/

COPY --chown=node:node package.json pnpm-workspace.yaml pnpm-lock.yaml $APP_PATH/
COPY --chown=node:node packages/oer-adapter-core $APP_PATH/packages/oer-adapter-core/
COPY --chown=node:node packages/oer-adapter-nostr-amb-relay $APP_PATH/packages/oer-adapter-nostr-amb-relay/
COPY --chown=node:node packages/oer-adapter-arasaac $APP_PATH/packages/oer-adapter-arasaac/
COPY --chown=node:node packages/oer-adapter-openverse $APP_PATH/packages/oer-adapter-openverse/
COPY --chown=node:node packages/oer-adapter-rpi-virtuell $APP_PATH/packages/oer-adapter-rpi-virtuell/
COPY --chown=node:node packages/oer-adapter-wikimedia $APP_PATH/packages/oer-adapter-wikimedia/
RUN pnpm install

COPY --chown=node:node src tsconfig.build.json tsconfig.json $APP_PATH/
# Copy source code for building
COPY --chown=node:node packages/ ./packages/
COPY --chown=node:node src/ ./src/
COPY --chown=node:node tsconfig.json tsconfig.build.json nest-cli.json ./

# Build all adapter packages (Vite) and main NestJS app
RUN pnpm run build

# Create a standalone production bundle with only prod dependencies.
# Workspace adapters are resolved using their "files" field (dist/ only).
RUN pnpm --filter @edufeed-org/oer-proxy deploy --prod $PROD_PATH

# Remove non-runtime files (root package has no "files" field, so everything gets copied)
RUN rm -rf $PROD_PATH/src $PROD_PATH/test $PROD_PATH/scripts \
$PROD_PATH/tsconfig* $PROD_PATH/nest-cli.json \
$PROD_PATH/.eslint* $PROD_PATH/.prettier* $PROD_PATH/.editorconfig \
$PROD_PATH/*.config.* $PROD_PATH/CLAUDE.md $PROD_PATH/.claude

FROM node:24-slim AS production

ARG PROD_PATH=/home/node/prod
ENV NODE_ENV=production
WORKDIR /app

# Copy production bundle as root (read-only for the running process).
# If the app is compromised, an attacker cannot modify application code.
COPY --from=build $PROD_PATH .

# Only grant the node user ownership of directories that need write access at runtime.
# Application code stays root-owned and read-only.
RUN mkdir -p /app/tmp && chown node:node /app/tmp

USER node

EXPOSE 3000

CMD ["node", "dist/main.js"]
Loading
Loading