Modernize and optimize the GROWI official Docker image's Dockerfile (apps/app/docker/Dockerfile) and docker-entrypoint.sh based on 2025-2026 best practices. Target Node.js 24 and incorporate findings from the memory report (apps/app/tmp/memory-results/REPORT.md) to improve memory management.
Current Dockerfile structure:
base → builder → release (based on node:20-slim)pnpm deployCOPY . . copies the entire context into the buildernpm run migrate in CMDGROWI-specific design intentions (items to maintain):
/data/uploads and /tmp/page-bulk-export with root privileges, then drop to the node user for executionpnpm deploy --prod: The official method for extracting only production dependencies from a pnpm monorepoapps/app/tmp directory: Required in the production image as files are placed there during operation--expose_gc flag: Required for explicitly calling gc() in batch processing (ES rebuild, import, etc.)npm run migrate in CMD: Automatically runs migrations at startup for the convenience of Docker image usersReferences:
apps/app/tmp/memory-results/REPORT.md)Objective: As an infrastructure administrator, I want the Dockerfile's base image and syntax to comply with the latest best practices, so that security patch application, performance improvements, and maintainability enhancements are achieved
Summary: DHI base images adopted (dhi.io/node:24-debian13-dev for build, dhi.io/node:24-debian13 for release) with up to 95% CVE reduction. Syntax directive updated to auto-follow latest stable. pnpm installed via wget standalone script (corepack not adopted due to planned removal in Node.js 25+). Fixed ---frozen-lockfile typo and eliminated hardcoded pnpm version.
Objective: As a GROWI operator, I want the Node.js heap size to be appropriately controlled according to container memory constraints, so that the risk of OOMKilled is reduced and memory efficiency in multi-tenant environments is improved
Summary: 3-tier heap size fallback implemented in docker-entrypoint.ts: (1) GROWI_HEAP_SIZE env var, (2) cgroup v2/v1 auto-calculation at 60%, (3) V8 default. Uses --max-heap-size (not --max_old_space_size) passed as direct spawn arguments (not NODE_OPTIONS). Additional flags: --optimize-for-size via GROWI_OPTIMIZE_MEMORY=true, --lite-mode via GROWI_LITE_MODE=true.
Objective: As a developer, I want Docker builds to be fast and efficient, so that CI/CD pipeline build times are reduced and image size is minimized
Summary: turbo prune --docker pattern adopted to eliminate COPY . . and maximize layer cache (dependency install cached separately from source changes). pnpm store and apt-get cache mounts maintained. .next/cache excluded from release stage. Artifact transfer uses COPY --from=builder (adapted from design's --mount=type=bind,from=builder due to shell-less DHI runtime).
Objective: As a security officer, I want the Docker image to comply with security best practices, so that the attack surface is minimized and the safety of the production environment is improved
Summary: Non-root execution via Node.js native process.setuid/setgid (no gosu/setpriv). Release stage contains no unnecessary packages — no shell, no apt, no build tools. Enhanced .dockerignore excludes .git, secrets, test files, IDE configs. --no-install-recommends used for apt-get in build stage.
Objective: As an operations engineer, I want the Docker image to have appropriate metadata configured, so that management by container orchestrators is facilitated
Summary: OCI standard LABEL annotations added (org.opencontainers.image.source, .title, .description, .vendor). EXPOSE 3000 and VOLUME /data maintained.
Objective: As a developer, I want the entrypoint script and CMD to have a clear and maintainable structure, so that dynamic assembly of memory flags and future extensions are facilitated
Summary: Entrypoint rewritten in TypeScript (docker-entrypoint.ts) executed via Node.js 24 native type stripping. Handles: directory setup (/data/uploads, /tmp/page-bulk-export), heap size calculation (3-tier fallback), privilege drop (process.setgid + process.setuid), migration execution (execFileSync), app process spawn with signal forwarding. Always includes --expose_gc. Logs applied flags to stdout.
Objective: As an existing Docker image user, I want existing operations to not break when migrating to the new Dockerfile, so that the risk during upgrades is minimized
Summary: Full backward compatibility maintained. Environment variables (MONGO_URI, FILE_UPLOAD, etc.), VOLUME /data, port 3000, and docker-compose usage patterns all work as before. Without memory management env vars, behavior is equivalent to V8 defaults.
Objective: As an infrastructure administrator, I want the artifacts in the docker-new directory to officially replace the existing docker directory and the CI/CD pipeline to operate with the new Dockerfile, so that DHI-based images are used in production builds
Summary: All files moved from apps/app/docker-new/ to apps/app/docker/, old files deleted. Dockerfile self-referencing path updated. docker login dhi.io added to buildspec.yml pre_build phase, reusing existing DOCKER_REGISTRY_PASSWORD secret. codebuild/ directory and README.md maintained.