# Explore container for flaredown — rubyforgood chronic-illness symptom tracker. # github.com/rubyforgood/Flaredown (GPL-3), pinned upstream at 5f859e8d. Polyglot, multi-service: # - backend/ Rails 7.1 API, Ruby 3.2.3. Mongoid 8.1 on MongoDB (primary store) + Postgres # (small relational slice) + Redis + Sidekiq. # - frontend/ Ember.js client, Node 14.21.3 (npm 7). # Adapted for live-mount: the source repo is bind-mounted at /workspace/repo; deps + DB set up # by post-create.sh, and the three datastores are started by post-start.sh. # # Deliberate version choice: docker-compose pins MongoDB 4.4.9, which is EOL and ships no # arm64 / Debian-bookworm packages. Mongoid 8.1.3 + the mongo ruby driver 2.20.1 support # servers up to 7.0, so we run MongoDB 7.0 (native amd64 + aarch64, no emulation) instead of # fighting a dead 4.4 build. Same wire protocol; the app is version-agnostic here. FROM ruby:3.2.3 # System deps: Postgres + libpq (the pg gem), Redis (Sidekiq), plus build tooling. python3 # (bookworm ships 3.11 ≥ 3.10, which the reduced-toolset str_replace_editor needs). xz/curl/ # gnupg for the Node + Mongo downloads. libyaml for psych. RUN apt-get update && apt-get install -y --no-install-recommends \ postgresql postgresql-client libpq-dev \ redis-server \ build-essential pkg-config libyaml-dev \ python3 \ git sudo curl ca-certificates gnupg xz-utils procps \ && rm -rf /var/lib/apt/lists/* # MongoDB 7.0 server binary (mongod) from the official tarball, arch-aware. The ubuntu2204 # build (glibc 2.35) runs fine on bookworm (glibc 2.36). Only mongod is needed — Mongoid # connects over the wire; no mongosh required (post-start probes the port directly). RUN set -eux; \ arch="$(dpkg --print-architecture)"; \ case "$arch" in \ amd64) marm=x86_64;; \ arm64) marm=aarch64;; \ *) echo "unsupported arch: $arch" >&2; exit 1;; \ esac; \ ver=7.0.14; \ curl -fsSL "https://fastdl.mongodb.org/linux/mongodb-linux-${marm}-ubuntu2204-${ver}.tgz" -o /tmp/mongo.tgz; \ tar -xzf /tmp/mongo.tgz -C /tmp; \ cp /tmp/mongodb-linux-${marm}-ubuntu2204-${ver}/bin/mongod /usr/local/bin/; \ rm -rf /tmp/mongo.tgz /tmp/mongodb-linux-*; \ mongod --version | head -1 # Node via nvm: 18 (default — toolkit tooling: create-snapshot hooks, `node -e` reads of # toolkit.json) + 14 (the Ember app; frontend/.nvmrc = v14.21.3). Symlink v18 to /usr/local/bin # so the toolkit's own node always resolves; run-app switches PATH to v14 for the client. # The frontend's .npmrc sets engine-strict=true and its package.json requires npm 6.x, so pin # npm 6 in the v14 line (nvm's 14.21.3 otherwise bundles npm 7, which fails engine-strict). The # v18.* glob (not `nvm version`) avoids sourcing nvm.sh under Docker's /bin/sh (dash), bash-only. ENV NVM_DIR=/usr/local/nvm RUN mkdir -p "$NVM_DIR" \ && curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash \ && bash -c '. "$NVM_DIR/nvm.sh" \ && nvm install 18 \ && nvm install 14.21.3 && nvm use 14.21.3 && npm install -g npm@6.14.18 \ && nvm alias default 18' \ && for b in node npm npx; do ln -sf "$NVM_DIR"/versions/node/v18.*/bin/"$b" /usr/local/bin/"$b"; done \ && node --version # phantomjs stub. The Ember client depends on phantomjs-prebuilt@2.1.16, which has NO arm64 # binary and is EOL everywhere — its install script aborts `npm install` on Apple-Silicon # hosts. A stub on PATH that reports the expected version makes the install script treat # PhantomJS as "already installed" and skip the (impossible) download, so `npm install` # completes and `ember build`/`ember serve` (what run-app uses) work. `ember test` runs on # headless Chrome at this pin, wired up after the Playwright block below. RUN printf '#!/bin/bash\n[ "$1" = "--version" ] && { echo "2.1.1"; exit 0; }\nexit 0\n' > /usr/local/bin/phantomjs \ && chmod +x /usr/local/bin/phantomjs # Match backend/Gemfile.lock "BUNDLED WITH 2.5.6". RUN gem install bundler -v 2.5.6 # Postgres trust auth: backend/config/database.yml connects as PG_DATABASE_USERNAME (default # postgres). OVERWRITE pg_hba.conf (Debian's default `local all all peer` is first-match, so # an appended trust rule never applies). RUN PG_VERSION=$(ls /etc/postgresql) \ && printf 'local all all trust\nhost all all 127.0.0.1/32 trust\nhost all all ::1/128 trust\nhost all all 0.0.0.0/0 trust\n' > "/etc/postgresql/${PG_VERSION}/main/pg_hba.conf" \ && echo "listen_addresses='*'" >> "/etc/postgresql/${PG_VERSION}/main/postgresql.conf" USER root # --- Playwright + Chromium, for driving the app in a real browser ------------- # Self-contained under /opt — the member's own runtime is untouched. ENV PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright RUN apt-get update -qq \ && apt-get install -y -qq --no-install-recommends \ xz-utils \ libxcomposite1 \ libxdamage1 \ libxfixes3 \ libxrandr2 \ libasound2 \ libatk1.0-0 \ libatk-bridge2.0-0 \ libatspi2.0-0 \ libcups2 \ libdbus-1-3 \ libgbm1 \ libnspr4 \ libnss3 \ libxkbcommon0 \ libpango-1.0-0 \ libcairo2 \ libxshmfence1 \ libx11-xcb1 \ libxcb-dri3-0 \ libdrm2 \ && rm -rf /var/lib/apt/lists/* RUN set -eux; \ arch="$(dpkg --print-architecture)"; \ case "$arch" in amd64) nodearch=x64;; arm64) nodearch=arm64;; *) echo "unsupported arch: $arch" >&2; exit 1;; esac; \ curl -fsSL "https://nodejs.org/dist/v20.19.5/node-v20.19.5-linux-${nodearch}.tar.xz" -o /tmp/pw-node.tar.xz; \ mkdir -p /opt/pw-node; \ tar -xJf /tmp/pw-node.tar.xz -C /opt/pw-node --strip-components=1; \ rm /tmp/pw-node.tar.xz; \ export npm_config_prefix=/opt/pw-node PATH="/opt/pw-node/bin:$PATH"; \ /opt/pw-node/bin/npm install -g playwright@1.56.0; \ test -d /opt/pw-node/lib/node_modules/playwright; \ /opt/pw-node/bin/node /opt/pw-node/lib/node_modules/playwright/cli.js install chromium # `pw ` runs Node with `require("playwright")` resolvable (CommonJS). RUN printf '#!/bin/sh\nNODE_PATH=/opt/pw-node/lib/node_modules exec /opt/pw-node/bin/node "$@"\n' > /usr/local/bin/pw \ && chmod +x /usr/local/bin/pw # Fail the build if Chromium cannot start. RUN printf 'const{chromium}=require("playwright");(async()=>{const b=await chromium.launch();const p=await b.newPage();await p.setContent("

ok

");if(await p.textContent("#t")!=="ok")throw new Error("bad render");await b.close();console.log("chromium OK");})()\n' > /tmp/pw-check.js \ && pw /tmp/pw-check.js \ && rm -f /tmp/pw-check.js # `ember test` resolves its browser via CHROME_BIN, falling back to `google-chrome` on PATH # (frontend/testem.js). Point both at the Chromium Playwright just installed. The glob is # resolved at build time so a Playwright bump can't strand a hardcoded chromium- path. RUN set -eux; \ chrome="$(echo /opt/ms-playwright/chromium-*/chrome-linux/chrome)"; \ test -x "$chrome"; \ printf '#!/bin/bash\nexec %s --no-sandbox --disable-dev-shm-usage "$@"\n' "$chrome" \ > /usr/local/bin/google-chrome; \ chmod +x /usr/local/bin/google-chrome; \ google-chrome --version ENV CHROME_BIN=/usr/local/bin/google-chrome ENV IS_SANDBOX=1 RUN mkdir -p /root/.claude && \ echo '{"permissions":{"deny":["WebFetch","WebSearch"]}}' > /root/.claude/settings.json # Startup for a direct `docker run` (the devcontainer path uses post-start.sh instead, which # starts the same services). Bring up Postgres + Redis + MongoDB, then hand off. RUN cat > /usr/local/bin/start-services.sh <<'EOF' #!/bin/bash set -e service postgresql start || true service redis-server start >/dev/null 2>&1 || redis-server --daemonize yes >/dev/null 2>&1 || true mkdir -p /data/db mongod --dbpath /data/db --bind_ip 127.0.0.1 --fork --logpath /tmp/mongod.log >/dev/null 2>&1 || true until pg_isready -h localhost -p 5432 -U postgres >/dev/null 2>&1; do sleep 0.5; done exec "$@" EOF RUN chmod +x /usr/local/bin/start-services.sh WORKDIR /workspace/repo # Resolver for the DNS jail (.devcontainer/dns-jail-container.sh, applied by # post-start.sh); if this does not land, Explore just runs unjailed. RUN (command -v apk >/dev/null 2>&1 && apk add --no-cache dnsmasq bind-tools) \ || (apt-get update && apt-get install -y --no-install-recommends dnsmasq-base dnsutils \ && rm -rf /var/lib/apt/lists/*) \ || true ENTRYPOINT ["/usr/local/bin/start-services.sh"] CMD ["sleep", "infinity"]